瀏覽代碼

'commit_by_xulin_20190317'

lyn 6 年之前
當前提交
2f3a3b351a
共有 100 個文件被更改,包括 5653 次插入0 次删除
  1. 65 0
      .gitignore
  2. 29 0
      .idea/codeStyles/Project.xml
  3. 38 0
      .idea/misc.xml
  4. 11 0
      .idea/modules.xml
  5. 12 0
      .idea/runConfigurations.xml
  6. 2 0
      README.md
  7. 0 0
      adb
  8. 1 0
      apk/release/output.json
  9. 1 0
      app/.gitignore
  10. 82 0
      app/build.gradle
  11. 二進制
      app/libs/BaminSDK.jar
  12. 二進制
      app/libs/VDS-2.4.6.jar
  13. 二進制
      app/libs/adsdk.jar
  14. 二進制
      app/libs/armeabi-v7a/libVDS.so
  15. 二進制
      app/libs/armeabi-v7a/libadsdk.so
  16. 二進制
      app/libs/armeabi-v7a/libkystb.so
  17. 二進制
      app/libs/armeabi-v7a/liblogsdk.so
  18. 二進制
      app/libs/armeabi-v7a/libottlogin.so
  19. 二進制
      app/libs/armeabi-v7a/libupgradesdk.so
  20. 二進制
      app/libs/icntvplayersdk.jar
  21. 二進制
      app/libs/logsdk.jar
  22. 二進制
      app/libs/ottlogin.jar
  23. 二進制
      app/libs/universal-image-loader-1.9.5.jar
  24. 二進制
      app/libs/upgradeSDK.jar
  25. 136 0
      app/proguard-rules.pro
  26. 1 0
      app/release/output.json
  27. 26 0
      app/src/androidTest/java/com/hc/webapp/ExampleInstrumentedTest.java
  28. 74 0
      app/src/main/AndroidManifest.xml
  29. 8 0
      app/src/main/assets/DeviceInfo.ini
  30. 133 0
      app/src/main/java/com/hc/webapp/BaseApp.java
  31. 258 0
      app/src/main/java/com/hc/webapp/MainActivity.java
  32. 32 0
      app/src/main/java/com/hc/webapp/model/VideoInfo.java
  33. 200 0
      app/src/main/java/com/hc/webapp/other/ThirdPartPlatform.java
  34. 142 0
      app/src/main/java/com/hc/webapp/store/LastPlayTimeStore.java
  35. 38 0
      app/src/main/java/com/hc/webapp/store/TvDB.java
  36. 109 0
      app/src/main/java/com/hc/webapp/video/SysVideoPlayerActivity.java
  37. 233 0
      app/src/main/java/com/hc/webapp/video/VideoControlDelegate.java
  38. 24 0
      app/src/main/java/com/hc/webapp/video/VideoInfo.java
  39. 631 0
      app/src/main/java/com/hc/webapp/web/AndroidToJS.java
  40. 291 0
      app/src/main/java/com/hc/webapp/web/BaseWebActivity.java
  41. 87 0
      app/src/main/java/com/hc/webapp/web/DownloadInstall.java
  42. 5 0
      app/src/main/java/com/hc/webapp/web/GetRequestListener.java
  43. 39 0
      app/src/main/java/com/hc/webapp/web/GetRuquest.java
  44. 18 0
      app/src/main/java/com/hc/webapp/web/HCWebChromeClient.java
  45. 71 0
      app/src/main/java/com/hc/webapp/web/HCWebViewClient.java
  46. 50 0
      app/src/main/java/com/hc/webapp/web/MD5.java
  47. 243 0
      app/src/main/java/com/hc/webapp/yst/AdData.java
  48. 139 0
      app/src/main/java/com/hc/webapp/yst/LocalStore.java
  49. 617 0
      app/src/main/java/com/hc/webapp/yst/MainActivity.java
  50. 377 0
      app/src/main/java/com/hc/webapp/yst/OttLoginUtil.java
  51. 77 0
      app/src/main/java/com/hc/webapp/yst/PayActivity.java
  52. 116 0
      app/src/main/java/com/hc/webapp/yst/TrackUtil.java
  53. 203 0
      app/src/main/java/com/hc/webapp/yst/VideoData.java
  54. 1006 0
      app/src/main/java/com/hc/webapp/yst/YSTVideoPlayer.java
  55. 二進制
      app/src/main/res/drawable-hdpi/anniu_2.png
  56. 二進制
      app/src/main/res/drawable-hdpi/btn_icon_right.png
  57. 二進制
      app/src/main/res/drawable-hdpi/btn_icon_stop.png
  58. 二進制
      app/src/main/res/drawable-hdpi/cancel_collect_focus.png
  59. 二進制
      app/src/main/res/drawable-hdpi/cancel_collect_normal.png
  60. 二進制
      app/src/main/res/drawable-hdpi/collect_normal.png
  61. 二進制
      app/src/main/res/drawable-hdpi/collect_normal_focus.png
  62. 二進制
      app/src/main/res/drawable-hdpi/continue_play_focus.png
  63. 二進制
      app/src/main/res/drawable-hdpi/continue_play_normal.png
  64. 二進制
      app/src/main/res/drawable-hdpi/exit_play_focus.png
  65. 二進制
      app/src/main/res/drawable-hdpi/exit_play_normal.png
  66. 二進制
      app/src/main/res/drawable-hdpi/img_bear_point.png
  67. 二進制
      app/src/main/res/drawable-hdpi/loading.png
  68. 二進制
      app/src/main/res/drawable-hdpi/more_video.png
  69. 二進制
      app/src/main/res/drawable-hdpi/more_video_back.png
  70. 二進制
      app/src/main/res/drawable-hdpi/pause_dialog_back.png
  71. 二進制
      app/src/main/res/drawable-hdpi/replay_focus.png
  72. 二進制
      app/src/main/res/drawable-hdpi/replay_normal.png
  73. 二進制
      app/src/main/res/drawable-hdpi/seek.png
  74. 二進制
      app/src/main/res/drawable-hdpi/seek_back.png
  75. 二進制
      app/src/main/res/drawable-hdpi/start_pause.png
  76. 二進制
      app/src/main/res/drawable-hdpi/start_pause_back.png
  77. 二進制
      app/src/main/res/drawable-ldpi/anniu_2.png
  78. 二進制
      app/src/main/res/drawable-ldpi/btn_icon_right.png
  79. 二進制
      app/src/main/res/drawable-ldpi/btn_icon_stop.png
  80. 二進制
      app/src/main/res/drawable-ldpi/cancel_collect_focus.png
  81. 二進制
      app/src/main/res/drawable-ldpi/cancel_collect_normal.png
  82. 二進制
      app/src/main/res/drawable-ldpi/collect_normal.png
  83. 二進制
      app/src/main/res/drawable-ldpi/collect_normal_focus.png
  84. 二進制
      app/src/main/res/drawable-ldpi/continue_play_focus.png
  85. 二進制
      app/src/main/res/drawable-ldpi/continue_play_normal.png
  86. 28 0
      app/src/main/res/drawable-ldpi/dudu_video_seek_progress.xml
  87. 二進制
      app/src/main/res/drawable-ldpi/exit_play_focus.png
  88. 二進制
      app/src/main/res/drawable-ldpi/exit_play_normal.png
  89. 二進制
      app/src/main/res/drawable-ldpi/img_bear_point.png
  90. 二進制
      app/src/main/res/drawable-ldpi/loading.png
  91. 二進制
      app/src/main/res/drawable-ldpi/more_video.png
  92. 二進制
      app/src/main/res/drawable-ldpi/more_video_back.png
  93. 二進制
      app/src/main/res/drawable-ldpi/pause_dialog_back.png
  94. 二進制
      app/src/main/res/drawable-ldpi/replay_focus.png
  95. 二進制
      app/src/main/res/drawable-ldpi/replay_normal.png
  96. 二進制
      app/src/main/res/drawable-ldpi/seek.png
  97. 二進制
      app/src/main/res/drawable-ldpi/seek_back.png
  98. 二進制
      app/src/main/res/drawable-ldpi/start_pause.png
  99. 二進制
      app/src/main/res/drawable-ldpi/start_pause_back.png
  100. 0 0
      app/src/main/res/drawable-mdpi-1280x720/anniu_2.png

+ 65 - 0
.gitignore

@@ -0,0 +1,65 @@
+# Built application files
+*.apk
+*.ap_
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+.idea/caches
+
+# Keystore files
+# Uncomment the following line if you do not want to check your keystore files in.
+#*.jks
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Google Services (e.g. APIs or Firebase)
+google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md

+ 29 - 0
.idea/codeStyles/Project.xml

@@ -0,0 +1,29 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <Objective-C-extensions>
+      <file>
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
+      </file>
+      <class>
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
+        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
+      </class>
+      <extensions>
+        <pair source="cpp" header="h" fileNamingConvention="NONE" />
+        <pair source="c" header="h" fileNamingConvention="NONE" />
+      </extensions>
+    </Objective-C-extensions>
+  </code_scheme>
+</component>

+ 38 - 0
.idea/misc.xml

@@ -0,0 +1,38 @@
+<?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="7">
+          <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="javax.annotation.CheckForNull" />
+          <item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+          <item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+          <item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
+          <item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
+        </list>
+      </value>
+    </option>
+    <option name="myNotNulls">
+      <value>
+        <list size="6">
+          <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" />
+          <item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
+          <item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
+        </list>
+      </value>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" 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>
+</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$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
+      <module fileurl="file://$PROJECT_DIR$/lib/lib.iml" filepath="$PROJECT_DIR$/lib/lib.iml" />
+      <module fileurl="file://$PROJECT_DIR$/model/model.iml" filepath="$PROJECT_DIR$/model/model.iml" />
+      <module fileurl="file://$PROJECT_DIR$/sxyd_dudu_weilai.iml" filepath="$PROJECT_DIR$/sxyd_dudu_weilai.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>

+ 2 - 0
README.md

@@ -0,0 +1,2 @@
+# guangdian_dj
+福建广电电竞

+ 0 - 0
adb


+ 1 - 0
apk/release/output.json

@@ -0,0 +1 @@
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":12,"versionName":"V2.0.2","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]

+ 1 - 0
app/.gitignore

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

+ 82 - 0
app/build.gradle

@@ -0,0 +1,82 @@
+apply plugin: 'com.android.application'
+
+android {
+    signingConfigs {
+        config {
+            keyAlias 'hc'
+            keyPassword 'hc123456'
+            storeFile file('D:\\android project\\sxyd\\sxyd_dudu_weilai\\key\\hcKeyStore.jks')
+            storePassword 'hc123456'
+        }
+    }
+    compileSdkVersion versions.compileSdk
+    defaultConfig {
+        applicationId "com.sxyd.duduUp"
+        minSdkVersion versions.minSdk
+        targetSdkVersion versions.targetSdk
+        versionCode 4
+        versionName "V1.0.4"
+        ndk {
+            //APP的build.gradle设置支持的SO库架构
+            abiFilters 'armeabi-v7a'
+        }
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        buildConfigField 'int','platformType','3'   ////1:百事通,2:银河,3:未来
+    }
+    buildTypes {
+        debug {
+            buildConfigField "Boolean", "isDebug", "true"
+//            zipAlignEnabled true
+//            shrinkResources true
+//            debuggable true
+            signingConfig signingConfigs.config
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+        release {
+            buildConfigField "Boolean", "isDebug", "false"
+//            zipAlignEnabled true
+//            shrinkResources true
+//            debuggable true
+            signingConfig signingConfigs.config
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    sourceSets {
+        main {
+            jniLibs.srcDirs = ['libs']
+        }
+    }
+    productFlavors {
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    implementation fileTree(include: ['*.jar'], dir: 'libs')
+    testImplementation lib.test.junit
+    androidTestImplementation lib.test.runner
+    androidTestImplementation lib.test.espresso
+    implementation project(':model')
+    //    implementation project(':sysvideo')
+    implementation files('libs/adsdk.jar')
+    implementation files('libs/icntvplayersdk.jar')
+    implementation files('libs/logsdk.jar')
+    implementation files('libs/ottlogin.jar')
+    implementation files('libs/universal-image-loader-1.9.5.jar')
+    implementation files('libs/VDS-2.4.6.jar')
+    implementation files('libs/BaminSDK.jar')
+    implementation 'com.liulishuo.filedownloader:library:1.7.5'
+    implementation('com.jewel.lib:JLib:1.0.12') {
+        exclude group: "com.android.support"
+    }
+    implementation('com.jewel.util:ViewInject:1.0.1') {
+        exclude group: "com.android.support"
+    }
+    implementation 'com.squareup.okhttp3:okhttp:3.12.1'
+//    implementation 'com.loopj.android:android-async-http:1.4.9'
+}

二進制
app/libs/BaminSDK.jar


二進制
app/libs/VDS-2.4.6.jar


二進制
app/libs/adsdk.jar


二進制
app/libs/armeabi-v7a/libVDS.so


二進制
app/libs/armeabi-v7a/libadsdk.so


二進制
app/libs/armeabi-v7a/libkystb.so


二進制
app/libs/armeabi-v7a/liblogsdk.so


二進制
app/libs/armeabi-v7a/libottlogin.so


二進制
app/libs/armeabi-v7a/libupgradesdk.so


二進制
app/libs/icntvplayersdk.jar


二進制
app/libs/logsdk.jar


二進制
app/libs/ottlogin.jar


二進制
app/libs/universal-image-loader-1.9.5.jar


二進制
app/libs/upgradeSDK.jar


+ 136 - 0
app/proguard-rules.pro

@@ -0,0 +1,136 @@
+# 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
+# 指定代码的压缩级别
+-optimizationpasses 5
+# 是否使用大小写混合
+-dontusemixedcaseclassnames
+# 是否混淆第三方jar
+-dontskipnonpubliclibraryclasses
+# 混淆时是否做预校验
+-dontpreverify
+# 混淆时是否记录日志
+-verbose
+# 混淆时所采用的算法
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+-ignorewarnings
+#-ignorewarnings
+-keepattributes *Annotation*
+-keepattributes Signature
+-keepattributes SourceFile,LineNumberTable
+-keepattributes Exceptions,InnerClasses,Deprecated,LocalVariable*Table,Synthetic,EnclosingMethod
+-keepattributes EnclosingMethod
+
+
+
+# Keep native methods
+-keepclassmembers class * {
+    native <methods>;
+}
+
+-keepclassmembers class * implements java.io.Serializable {
+    static final long serialVersionUID;
+    private static final java.io.ObjectStreamField[] serialPersistentFields;
+    private void writeObject(java.io.ObjectOutputStream);
+    private void readObject(java.io.ObjectInputStream);
+    java.lang.Object writeReplace();
+    java.lang.Object readResolve();
+}
+
+-keep public class * implements java.io.Serializable {
+    public *;
+}
+
+-keep class **.R$*{
+    *;
+}
+
+-keepclassmembers class * {
+   public <init>(org.json.JSONObject);
+}
+
+-keepclasseswithmembernames class * {
+native <methods>;
+}
+
+-keepclassmembers enum * {
+public static **[] values();
+public static ** valueOf(java.lang.String);
+}
+
+
+# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
+-keepclassmembers class * {
+    void *(**On*Event);
+    void *(**On*Listener);
+}
+
+-keepattributes *JavascriptInterface*
+-keep class android.webkit.JavascriptInterface {*;}
+
+-keepclassmembers class * extends android.webkit.webViewClient {
+    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
+    public boolean *(android.webkit.WebView, java.lang.String);
+}
+-keepclassmembers class * extends android.webkit.webViewClient {
+    public void *(android.webkit.webView, jav.lang.String);
+}
+
+-keep class com.hc.webapp.web.AndroidToJS {*;}
+-keep class com.hc.webapp.web.HCWebChromeClient {*;}
+-keep class com.hc.webapp.web.HCWebViewClient {*;}
+
+
+# ButterKnife
+-keep class butterknife.** { *; }
+-dontwarn butterknife.internal.**
+-keep class **$$ViewBinder { *; }
+-keepclasseswithmembernames class * {
+    @butterknife.* <fields>;
+}
+-keepclasseswithmembernames class * {
+    @butterknife.* <methods>;
+}
+
+# Glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
+  **[] $VALUES;
+  public *;
+}
+
+
+# 保留我们自定义控件(继承自View)不被混淆
+-keep public class * extends android.view.View{
+    *** get*();
+    void set*(***);
+    public <init>(android.content.Context);
+    public <init>(android.content.Context, android.util.AttributeSet);
+    public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+-keep class com.shuyu.gsyvideoplayer.video.** { *; }
+-dontwarn com.shuyu.gsyvideoplayer.video.**
+-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
+-dontwarn com.shuyu.gsyvideoplayer.video.base.**
+-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
+-dontwarn com.shuyu.gsyvideoplayer.utils.**
+-keep class tv.danmaku.ijk.** { *; }
+-dontwarn tv.danmaku.ijk.**

+ 1 - 0
app/release/output.json

@@ -0,0 +1 @@
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":4,"versionName":"V1.0.4","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]

+ 26 - 0
app/src/androidTest/java/com/hc/webapp/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.hc.webapp;
+
+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() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getTargetContext();
+
+        assertEquals("com.hc.webapp", 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="com.hc.webapp">
+
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />>
+
+    <!-- 未来电视所需权限 -->
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+
+
+    <application
+        android:name=".BaseApp"
+        android:allowBackup="true"
+        android:hardwareAccelerated="true"
+        android:largeHeap="true"
+        android:icon="@drawable/dudu"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <!--<activity-->
+            <!--android:name=".MainActivity"-->
+            <!--android:enabled="true"-->
+            <!--android:exported="true"-->
+            <!--android:screenOrientation="landscape">-->
+            <!--<intent-filter>-->
+                <!--<action android:name="android.intent.action.MAIN" /> -->
+                <!--<category android:name="android.intent.category.LAUNCHER" />-->
+                <!---->
+                <!--&lt;!&ndash; 供第三方调用 &ndash;&gt;-->
+                <!--<action android:name="com.hc.fj.dj" />-->
+                <!--<category android:name=" android.intent.category.DEFAULT" />-->
+            <!--</intent-filter>-->
+        <!--</activity>-->
+
+        <activity
+            android:name=".yst.MainActivity"
+            android:enabled="true"
+            android:exported="true"
+            android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+
+                <!-- 供第三方调用 -->
+                <action android:name="com.hc.fj.dj" />
+                <category android:name=" android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".yst.PayActivity"
+            android:screenOrientation="landscape"
+            android:launchMode="singleInstance"
+            android:theme="@style/PayTheme"/>
+    </application>
+
+</manifest>

+ 8 - 0
app/src/main/assets/DeviceInfo.ini

@@ -0,0 +1,8 @@
+[DEVICE]
+BootGuideServer=http://newtv.boot.ottcn.com:8080
+LoginType=1
+MacFile=/sys/class/efuse/mac_bt
+
+[LOG]
+; 1 日志开启  0 日志关闭
+LogOpen=1

+ 133 - 0
app/src/main/java/com/hc/webapp/BaseApp.java

@@ -0,0 +1,133 @@
+package com.hc.webapp;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.Application;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import com.hc.lib.TAG;
+import com.hc.webapp.yst.MainActivity;
+import com.jewel.lib.android.SharedPre;
+import com.orhanobut.logger.AndroidLogAdapter;
+import com.orhanobut.logger.FormatStrategy;
+import com.orhanobut.logger.PrettyFormatStrategy;
+import com.yanzhenjie.nohttp.InitializationConfig;
+import com.yanzhenjie.nohttp.Logger;
+import com.yanzhenjie.nohttp.NoHttp;
+import com.yanzhenjie.nohttp.URLConnectionNetworkExecutor;
+import com.yanzhenjie.nohttp.cache.DBCacheStore;
+import com.yanzhenjie.nohttp.cookie.DBCookieStore;
+
+import java.util.List;
+
+public class BaseApp extends Application {
+
+    private static BaseApp instance;
+
+    public static BaseApp getInstance() {
+        return instance;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        instance = this;
+        SharedPre.init(this, getPackageName());
+        initHttp();
+        initLogger();
+        initVideo();
+        caughtException();
+    }
+
+    private void initHttp() {
+        InitializationConfig config = InitializationConfig.newBuilder(this)
+                // 全局连接服务器超时时间,单位毫秒,默认10s。
+                .connectionTimeout(60 * 1000)
+                // 全局等待服务器响应超时时间,单位毫秒,默认10s。
+                .readTimeout(60 * 1000)
+                // 配置缓存,默认保存数据库DBCacheStore,保存到SD卡使用DiskCacheStore。
+                .cacheStore(
+                        // 如果不使用缓存,setEnable(false)禁用。
+                        new DBCacheStore(this).setEnable(true)
+                )
+                // 配置Cookie,默认保存数据库DBCookieStore,开发者可以自己实现CookieStore接口。
+                .cookieStore(
+                        // 如果不维护cookie,setEnable(false)禁用。
+                        new DBCookieStore(this).setEnable(true)
+                )
+                // 配置网络层,默认URLConnectionNetworkExecutor,如果想用OkHttp:OkHttpNetworkExecutor。
+                .networkExecutor(new URLConnectionNetworkExecutor())
+                // 全局重试次数,配置后每个请求失败都会重试x次。
+                .retry(2)
+                .build();
+        NoHttp.initialize(config);
+        // 开启NoHttp的调试模式, 配置后可看到请求过程、日志和错误信息。
+        Logger.setDebug(BuildConfig.DEBUG);
+        // 打印Log的tag。
+        Logger.setTag(TAG.HTTP);
+    }
+
+    private void initLogger() {
+        FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder().tag(getApplicationContext().getPackageName()).build();
+        com.orhanobut.logger.Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy));
+    }
+
+    private void initVideo() {
+//        PlayerFactory.setPlayManager(new SystemPlayerManager());
+//        GSYVideoType.setRenderType(GSYVideoType.SUFRACE);
+//        GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL);
+//        GSYVideoType.enableMediaCodec();
+//        GSYVideoType.enableMediaCodecTexture();
+    }
+
+    /**
+     * 判断应用是否处于前台
+     *
+     * @return <code>true</code>为前台,反之为后台
+     */
+    public static boolean isRunningForeground(Context context) {
+        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        if (activityManager == null) return false;
+        List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
+        // 枚举进程
+        for (ActivityManager.RunningAppProcessInfo appProcessInfo : appProcessInfos) {
+            if (appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                if (appProcessInfo.processName.equals(context.getApplicationInfo().processName)) {
+                    com.orhanobut.logger.Logger.d("应用处于前台状态");
+                    return true;
+                }
+            }
+        }
+        com.orhanobut.logger.Logger.d("应用退到后台");
+        return false;
+    }
+
+    private void caughtException() {
+        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                com.orhanobut.logger.Logger.e(e, "程序奔溃【%s】", e != null ? e.getMessage() : "无");
+                Intent intent = new Intent(getApplicationContext(), MainActivity.class);
+                PendingIntent restartIntent = PendingIntent.getActivity(
+                        getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
+
+//                //退出程序
+                AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+                mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 500,
+                        restartIntent); // 1秒钟后重启应用
+
+                //结束进程之前可以把你程序的注销或者退出代码放在这段代码之前
+                android.os.Process.killProcess(android.os.Process.myPid());
+            }
+        });
+    }
+
+    public static void exit() {
+        android.os.Process.killProcess(android.os.Process.myPid());   //获取PID
+        System.exit(0);
+    }
+
+}

+ 258 - 0
app/src/main/java/com/hc/webapp/MainActivity.java

@@ -0,0 +1,258 @@
+//package com.hc.webapp;
+//
+//import android.animation.PropertyValuesHolder;
+//import android.animation.ValueAnimator;
+//import android.os.Bundle;
+//import android.support.annotation.Nullable;
+//import android.view.KeyEvent;
+//import android.view.View;
+//import android.view.ViewGroup;
+//import android.view.animation.LinearInterpolator;
+//import android.widget.FrameLayout;
+//
+//import com.hc.lib.video.HCVideoPlayer;
+//import com.hc.webapp.video.VideoControlDelegate;
+//import com.hc.webapp.web.AndroidToJS;
+//import com.hc.webapp.web.BaseWebActivity;
+//import com.orhanobut.logger.Logger;
+//import com.shuyu.gsyvideoplayer.GSYVideoManager;
+//
+//public class MainActivity extends BaseWebActivity implements AndroidToJS.PlayVideoListener {
+//
+//    final String url = com.hc.model.BuildConfig.Domain + com.hc.model.BuildConfig.port + "/tv/h5v2/index.html";
+//
+////    public static final String[] urls = {"http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4",
+////            "https://hnh5pic.oss-cn-shenzhen.aliyuncs.com/20180910_test.ts"};
+//
+//    private HCVideoPlayer videoPlayer;
+//    private VideoControlDelegate controlDelegate;
+//
+//    private int floatVideoX = -1, floatVideoY = -1;
+//    private int floatVideoWidth = -1, floatVideoHeight = -1;
+//    private boolean isFullScreenVideo = false;
+//    private boolean hadFloatVideo = false;
+//
+//    @Override
+//    protected void onCreate(@Nullable Bundle savedInstanceState) {
+//        super.onCreate(savedInstanceState);
+//
+//        videoPlayer = new HCVideoPlayer(MainActivity.this);
+//        // 是否需要显示流量提示
+//        videoPlayer.setNeedShowWifiTip(false);
+//        // 设置右下角全屏按钮图标
+//        videoPlayer.setEnlargeImageRes(android.R.color.transparent);
+//        videoPlayer.getBackButton().setVisibility(View.GONE);
+//
+//        controlDelegate = new VideoControlDelegate(this, videoPlayer);
+//        controlDelegate.subscribeData();
+//        controlDelegate.getExitPlayingEvent().observe(this, aBoolean -> {
+//            if (hadFloatVideo) {
+//                videoPlayer.hideAllWidget();
+//                changeVideo2Float();
+//            } else {
+//                destroyVideo();
+//            }
+//        });
+//
+//        videoPlayer.setOnPlayerPausedListener(controlDelegate);
+//        videoPlayer.setLooping(false);  // 循环播放
+//    }
+//
+//    @Override
+//    protected String getIndexURL() {
+//        return url;
+//    }
+//
+//    @Override
+//    protected String getJsInvokeName() {
+//        return "djbl2";
+//    }
+//
+//    @Override
+//    public void setAndroidToJSListener(AndroidToJS androidToJS) {
+//        super.setAndroidToJSListener(androidToJS);
+//        androidToJS.setAndroidToJSListener(this);
+//    }
+//
+//    @Override
+//    public boolean dispatchKeyEvent(KeyEvent event) {
+//        int keyCode = event.getKeyCode();
+//        if (isFullScreenVideo && event.getAction() == KeyEvent.ACTION_DOWN && videoPlayer.shouldOverrideKeyEvent(keyCode)) {
+//            Logger.d("当前按下键值:%s", keyCode);
+//            return controlDelegate.onKeyDown(keyCode, event);
+//        }
+//        return super.dispatchKeyEvent(event);
+//    }
+//
+//    @Override
+//    protected void onStop() {
+//        super.onStop();
+//        boolean isForeground = BaseApp.isRunningForeground(this);
+//        if (!isForeground) {
+//            BaseApp.exit();
+//        }
+//    }
+//
+//    @Override
+//    protected void onDestroy() {
+//        super.onDestroy();
+//        destroyVideo();
+//    }
+//
+//    @Override
+//    public void playFloatVideo(final String url, final String thumbnail, final int x, final int y, final int width, final int height, final String uid, final String sourceId, final String title, String examineId, String examineType) {
+//        isFullScreenVideo = false;
+//        this.hadFloatVideo = true;
+//        controlDelegate.setFullVideo(false);
+//        Logger.d("调用小窗口播放。地址(%s),坐标(%s, %s),宽高(%s, %s)", url, x, y, width, height);
+//        runOnUiThread(() -> playVideo(url, title, uid, sourceId, x, y, width, height));
+//    }
+//
+//    @Override
+//    public void playFullVideo(final String url, final String title, String thumbnail, final String uid, final String sourceId, final long playTime, final boolean hadFloatVideo, String examineId, String examineType) {
+//        this.hadFloatVideo = hadFloatVideo;
+//        runOnUiThread(() -> {
+//            if (hadFloatVideo) {
+//                changeVideo2Full();
+//            } else {
+//                playVideo(url, title, uid, sourceId, playTime);
+//            }
+//        });
+//    }
+//
+//    @Override
+//    public void stopFloatVideo() {
+//        runOnUiThread(this::destroyVideo);
+//    }
+//
+//    /**
+//     * 全屏播放逻辑
+//     */
+//    private void playVideo(String url, String title, String uid, String sourceId, long playTime) {
+//
+//        isFullScreenVideo = true;
+//        controlDelegate.setFullVideo(true);
+//
+//        if (videoPlayer.getParent() == null) {
+//            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+//            viewGroup.addView(videoPlayer);
+//        }
+//
+//        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+//        videoPlayer.setLayoutParams(params);
+//        videoPlayer.setX(0);
+//        videoPlayer.setY(0);
+//
+//        controlDelegate.setUid(uid);
+//        controlDelegate.setSourceId(sourceId);
+//
+//        videoPlayer.setUp(url, false, title);
+//        videoPlayer.startPlayLogic();
+//    }
+//
+//    /**
+//     * 指定视频窗口位置和大小的播放逻辑
+//     */
+//    private void playVideo(String url, String title, String uid, String sourceId, int x, int y, int width, int height) {
+//        initVideoParamsIfNoInit(x, y, width, height);
+//
+//        controlDelegate.setUid(uid);
+//        controlDelegate.setSourceId(sourceId);
+//
+//        videoPlayer.setUp(url, false, title);
+//        videoPlayer.startPlayLogic();
+//    }
+//
+//    private void initVideoParamsIfNoInit(int x, int y, int width, int height) {
+//        floatVideoWidth = width;
+//        floatVideoHeight = height;
+//        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+//        params.width = floatVideoWidth;
+//        params.height = floatVideoHeight;
+//        videoPlayer.setLayoutParams(params);
+//
+//        floatVideoX = x;
+//        floatVideoY = y;
+//        videoPlayer.setX(floatVideoX);
+//        videoPlayer.setY(floatVideoY);
+//
+//        if (videoPlayer.getParent() == null) {
+//            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+//            viewGroup.addView(videoPlayer);
+//        }
+//    }
+//
+//    /**
+//     * 小窗转全屏
+//     */
+//    private void changeVideo2Full() {
+//        if (isFullScreenVideo) {
+//            return;
+//        }
+//        if (videoPlayer != null) {
+//            isFullScreenVideo = true;
+//            controlDelegate.setFullVideo(true);
+//            getWebView().clearFocus();
+//            videoPlayer.requestFocus();
+//            animChanged(floatVideoX, 0, floatVideoY, 0,
+//                    floatVideoWidth, getResources().getDisplayMetrics().widthPixels,
+//                    floatVideoHeight, getResources().getDisplayMetrics().heightPixels);
+//            videoPlayer.resumePlay();
+//        }
+//    }
+//
+//    /**
+//     * 全屏转小窗
+//     */
+//    private void changeVideo2Float() {
+//        if (!isFullScreenVideo) {
+//            return;
+//        }
+//        if (videoPlayer != null) {
+//            isFullScreenVideo = false;
+//            controlDelegate.setFullVideo(false);
+//            videoPlayer.clearFocus();
+//            getWebView().requestFocus();
+//            animChanged(0, floatVideoX, 0, floatVideoY,
+//                    getResources().getDisplayMetrics().widthPixels, floatVideoWidth,
+//                    getResources().getDisplayMetrics().heightPixels, floatVideoHeight);
+//        }
+//    }
+//
+//    private void animChanged(int fromX, int toX, int fromY, int toY, int fromWidth, int toWidth, int fromHeight, int toHeight) {
+//        ValueAnimator animator = new ValueAnimator();
+//        animator.setValues(
+//                PropertyValuesHolder.ofFloat("x", fromX, toX),
+//                PropertyValuesHolder.ofFloat("y", fromY, toY),
+//                PropertyValuesHolder.ofInt("width", fromWidth, toWidth),
+//                PropertyValuesHolder.ofInt("height", fromHeight, toHeight)
+//        );
+//        animator.setDuration(200);
+//        animator.setInterpolator(new LinearInterpolator());
+//        animator.addUpdateListener(valueAnimator -> {
+//            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+//            params.width = (int) valueAnimator.getAnimatedValue("width");
+//            params.height = (int) valueAnimator.getAnimatedValue("height");
+//            videoPlayer.setLayoutParams(params);
+//
+//            videoPlayer.setX((Float) valueAnimator.getAnimatedValue("x"));
+//            videoPlayer.setY((Float) valueAnimator.getAnimatedValue("y"));
+//        });
+//        animator.start();
+//    }
+//
+//    private void destroyVideo() {
+//        isFullScreenVideo = false;
+//        controlDelegate.setFullVideo(false);
+//        if (videoPlayer != null && videoPlayer.getParent() != null) {
+//
+//            AndroidToJS.evaluateJavascript(getWebView(), AndroidToJS.JS_EVENT_PLAY_FINISH);
+//
+//            videoPlayer.onVideoDestroy();
+//
+//            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+//            viewGroup.removeView(videoPlayer);
+//        }
+//        GSYVideoManager.releaseAllVideos();
+//    }
+//}

+ 32 - 0
app/src/main/java/com/hc/webapp/model/VideoInfo.java

@@ -0,0 +1,32 @@
+package com.hc.webapp.model;
+
+public class VideoInfo {
+    public String url;
+    public int x; 
+    public int y; 
+    public int width; 
+    public int height;
+    public String uid; 
+    public String sourceId; 
+    public String title;
+    public String examineId;
+    public String examineType;
+    public int limitTime;
+
+
+    public VideoInfo(final String url, final int x, final int y, final int width, final int height,
+                     final String uid, final String sourceId, final String title,
+                     String examineId,String examineType,int limitTime){
+        this.url = url;
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
+        this.uid = uid;
+        this.sourceId = sourceId;
+        this.title = title;
+        this.examineId = examineId;
+        this.examineType = examineType;
+        this.limitTime = limitTime;
+    }
+}

+ 200 - 0
app/src/main/java/com/hc/webapp/other/ThirdPartPlatform.java

@@ -0,0 +1,200 @@
+package com.hc.webapp.other;
+
+import android.support.annotation.NonNull;
+
+import com.hc.request.core.CallServer;
+import com.hc.request.core.DefaultCallback;
+import com.hc.request.core.IHttpCallback;
+import com.orhanobut.logger.Logger;
+import com.yanzhenjie.nohttp.RequestMethod;
+import com.yanzhenjie.nohttp.rest.StringRequest;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Random;
+
+/**
+ * @author jewel
+ * @email jewelbao88@gmail.com
+ * @gitsite https://github.com/jewelbao
+ * @since 2019/1/9
+ */
+public class ThirdPartPlatform {
+
+    private static final int STEP_FIRST = 100;
+    private static final int STEP_SECOND = 200;
+    private static final int STEP_THIRD = 300;
+    private static final int STEP_FOURTH = 400;
+    private static final int STEP_FINAL = 500;
+
+    public void start(String firstStepUrl, String secondStepUrl, String thirdStepUrl, String fourStepUrl, int k, final IHttpCallback<String> callback) {
+        StringRequest request = new StringRequest(firstStepUrl, RequestMethod.GET);
+        CallServer.getInstance().requestString(STEP_FIRST, request, new DefaultCallback<String>() {
+
+            @Override
+            public void onSuccess(int what, @NonNull String data) {
+                //Log.d(TAG,"第一步:" + bodyStr);
+                Logger.d("智慧平台请求第一步成功:%s", data);
+                new Thread(() -> secondStep(secondStepUrl, thirdStepUrl, fourStepUrl, k, callback)).start();
+            }
+
+            @Override
+            public void onError(int what, Throwable e) {
+                callback.onError(STEP_FIRST, e);
+                Logger.e(e, "智慧平台请求发生异常");
+            }
+        });
+    }
+
+    private void secondStep(String secondStepUrl, String thirdStepUrl, String fourStepUrl, int k, final IHttpCallback<String> callback) {
+        if (callback == null) {
+            return;
+        }
+        try {
+            final int delayTime = getNum(2, 6);
+            Logger.d("延迟%s秒", delayTime);
+            Thread.sleep(delayTime * 1000);
+            StringRequest request = new StringRequest(secondStepUrl, RequestMethod.POST);
+            request.add("k", k);
+            CallServer.getInstance().requestString(STEP_SECOND, request, new DefaultCallback<String>() {
+
+                @Override
+                public void onSuccess(int what, @NonNull String data) {
+                    Logger.d("智慧平台请求第二步成功:%s", data);
+                    new Thread(() -> thirdStep(thirdStepUrl, fourStepUrl, callback)).start();
+                }
+
+                @Override
+                public void onError(int what, Throwable e) {
+                    callback.onError(STEP_SECOND, e);
+                    Logger.e(e, "智慧平台第二步请求发生异常");
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+            callback.onError(STEP_SECOND, e);
+            Logger.e(e, "智慧平台第二步逻辑处理异常");
+        }
+    }
+
+    private void thirdStep(String thirdStepUrl, String fourStepUrl, final IHttpCallback<String> callback) {
+        if (callback == null) {
+            return;
+        }
+        try {
+            final int delayTime = getNum(5, 9);
+            Logger.d("延迟%s秒", delayTime);
+            Thread.sleep(delayTime * 1000);
+            StringRequest request = new StringRequest(thirdStepUrl, RequestMethod.GET);
+            CallServer.getInstance().requestString(STEP_THIRD, request, new DefaultCallback<String>() {
+
+                @Override
+                public void onSuccess(int what, @NonNull String data) {
+                    Logger.d("智慧平台请求第三步成功:%s", data);
+                    thirdStepJudge(data, fourStepUrl, callback);
+                }
+
+                @Override
+                public void onError(int what, Throwable e) {
+                    callback.onError(STEP_THIRD, e);
+                    Logger.e(e, "智慧平台第三步请求发生异常");
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+            callback.onError(STEP_THIRD, e);
+            Logger.e(e, "智慧平台第三步逻辑处理异常");
+        }
+    }
+
+    private void thirdStepJudge(String data, String fourStepUrl, IHttpCallback<String> callback) {
+        try {
+            JSONObject thirdResult = new JSONObject(data);
+            if (thirdResult.has("result")) {
+                String result = thirdResult.getString("result");
+                if (result.equals("2")) {
+                    new Thread(() -> fourthStep(fourStepUrl, callback)).start();
+                } else {
+                    callback.onFail(STEP_THIRD, data);
+                }
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+            callback.onError(STEP_THIRD, e);
+            Logger.e(e, "智慧平台第三步逻辑处理异常");
+        }
+    }
+
+    private void fourthStep(String fourStepUrl, final IHttpCallback<String> callback) {
+        if (callback == null) {
+            return;
+        }
+        try {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("productid", "");
+            jsonObject.put("serviceid", "");
+            jsonObject.put("name", "");
+            jsonObject.put("price", "");
+            jsonObject.put("producttype", "");
+            jsonObject.put("starttime", "");
+            jsonObject.put("endtime", "");
+            jsonObject.put("continueable", "");
+            jsonObject.put("point", "");
+            jsonObject.put("authflag", "");
+            jsonObject.put("contentid", "");
+
+            StringRequest request = new StringRequest(fourStepUrl, RequestMethod.POST);
+            request.setDefineRequestBodyForJson(jsonObject.toString());
+            CallServer.getInstance().requestString(STEP_FOURTH, request, new DefaultCallback<String>() {
+
+                @Override
+                public void onSuccess(int what, @NonNull String data) {
+                    super.onSuccess(what, data);
+                    Logger.d("智慧平台请求第四步成功:%s", data);
+                    try {
+                        finalStep(data, callback);
+                    } catch (JSONException e) {
+                        e.printStackTrace();
+                        callback.onError(STEP_FINAL, e);
+                        Logger.e(e, "智慧平台最终请求发生异常");
+                    }
+                }
+
+                @Override
+                public void onError(int what, Throwable e) {
+                    super.onError(what, e);
+                    callback.onError(STEP_FOURTH, e);
+                    Logger.e(e, "智慧平台第四步请求发生异常");
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+            callback.onError(STEP_FOURTH, e);
+            Logger.e(e, "智慧平台第四步逻辑处理异常");
+        }
+    }
+
+    private void finalStep(String data, IHttpCallback<String> callback) throws JSONException {
+        if (callback == null) {
+            return;
+        }
+        JSONObject fourthResult = new JSONObject(data);
+        if (fourthResult.has("result")) {
+            String result = fourthResult.getString("result");
+            if (result.equals("true")) {
+                callback.onSuccess(STEP_FINAL, data);
+            } else {
+                callback.onFail(STEP_FINAL, data);
+            }
+        }
+    }
+
+    private int getNum(int startNum, int endNum) {
+        if (endNum > startNum) {
+            Random random = new Random();
+            return random.nextInt(endNum - startNum) + startNum;
+        }
+        return 0;
+    }
+}

+ 142 - 0
app/src/main/java/com/hc/webapp/store/LastPlayTimeStore.java

@@ -0,0 +1,142 @@
+package com.hc.webapp.store;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/18.
+ */
+
+public class LastPlayTimeStore {
+    private static LastPlayTimeStore instance = null;
+    private TvDB tvDB = null;
+
+    public LastPlayTimeStore(Context context){
+        tvDB = TvDB.getInstance(context);
+    }
+
+    public static final synchronized LastPlayTimeStore getInstance(Context context){
+        if(instance == null){
+            instance = new LastPlayTimeStore(context);
+        }
+        return instance;
+    }
+
+    public void onCreate(SQLiteDatabase db){
+        String createTableSql = "CREATE VIRTUAL TABLE IF NOT EXISTS " + SearchIndexColumns.tableName
+                +" USING fts3 "
+                + " ( "
+                + SearchIndexColumns.sourceId + " STRING ,"
+                + SearchIndexColumns.time + " STRING ,"
+                + SearchIndexColumns.insertTime + " DATETIME DEFAULT CURRENT_TIMESTAMP ) ";
+        try{
+            db.execSQL(createTableSql);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    public boolean tableIsExist(SQLiteDatabase db, String tableName){
+        boolean result = false;
+        if(tableName == null){
+            return false;
+        }
+        Cursor cursor = null;
+        try {
+            String sql = "select count(*) as c from Sqlite_master  where type ='table' and name ='"+tableName.trim()+"' ";
+            cursor = db.rawQuery(sql, null);
+            if(cursor.moveToNext()){
+                int count = cursor.getInt(0);
+                if(count>0){
+                    result = true;
+                }
+            }
+            cursor.close();
+        } catch (Exception e) {
+            // TODO: handle exception
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    public void insert(String time,String sourceId){
+        delete(sourceId);
+        SQLiteDatabase database = tvDB.getWritableDatabase();
+        if(!tableIsExist(database, SearchIndexColumns.tableName)){
+            return;
+        }
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(SearchIndexColumns.sourceId,sourceId);
+        contentValues.put(SearchIndexColumns.time,time);
+        SimpleDateFormat dateFormat = new SimpleDateFormat(
+                "yyyy-MM-dd HH:mm:ss");
+        Date nowDate = new Date();
+        contentValues.put(SearchIndexColumns.insertTime,dateFormat.format(nowDate));
+        database.insert(SearchIndexColumns.tableName,null,contentValues);
+    }
+
+    public void delete(String sourceId){
+        SQLiteDatabase database = tvDB.getWritableDatabase();
+        if(!tableIsExist(database, SearchIndexColumns.tableName)){
+            return;
+        }
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(SearchIndexColumns.sourceId,sourceId);
+        SimpleDateFormat dateFormat = new SimpleDateFormat(
+                "yyyy-MM-dd HH:mm:ss");
+        Date nowDate = new Date();
+        contentValues.put(SearchIndexColumns.insertTime,dateFormat.format(nowDate));
+        String[] deleteArgs = { sourceId };
+        database.delete(SearchIndexColumns.tableName, SearchIndexColumns.sourceId + " = ?",deleteArgs);
+    }
+
+    public void deleteAll(){
+        SQLiteDatabase database = tvDB.getWritableDatabase();
+        if(!tableIsExist(database, SearchIndexColumns.tableName)){
+            return;
+        }
+        database.delete(SearchIndexColumns.tableName,null,null);
+    }
+
+    public String getTimeBySourceId(String sourceId){
+        SQLiteDatabase sqLiteDatabase = tvDB.getReadableDatabase();
+        if(!tableIsExist(sqLiteDatabase, SearchIndexColumns.tableName)){
+            return null;
+        }
+        Cursor c;
+        String sql = "select * from " + SearchIndexColumns.tableName+ " where "+ SearchIndexColumns.sourceId+ " = ?";
+        String[] args = {sourceId};
+        c = sqLiteDatabase.rawQuery(sql,args);
+
+
+
+        c.moveToFirst();
+        if(c.getCount() == 0){
+            return "";
+        }
+
+        String time = c.getString(c.getColumnIndexOrThrow(SearchIndexColumns.time));
+        c.close();
+        return time;
+    }
+
+    /* -------------------------------------------------------------------------------------------- */
+    /* table columns interface */
+    public interface SearchIndexColumns{
+        //表名
+        String tableName = "last_play_store";
+
+        //字段定义
+
+        String sourceId = "sourceId";
+
+        String time = "time";
+
+        String insertTime = "insert_time";
+    }
+}

+ 38 - 0
app/src/main/java/com/hc/webapp/store/TvDB.java

@@ -0,0 +1,38 @@
+package com.hc.webapp.store;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/18.
+ */
+
+public class TvDB extends SQLiteOpenHelper {
+    public static final String DATABASENAME = "houchuan_tv.db";
+    private static final int VERSION = 1;
+    private static TvDB instance = null;
+    private static Context mContext;
+
+    public TvDB(Context context) {
+        super(context, DATABASENAME, null, VERSION);
+        mContext = context;
+    }
+
+    public static final synchronized TvDB getInstance(final Context context){
+        if(instance ==null){
+            instance = new TvDB(context);
+        }
+        return instance;
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        LastPlayTimeStore.getInstance(mContext).onCreate(db);
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+
+    }
+}

+ 109 - 0
app/src/main/java/com/hc/webapp/video/SysVideoPlayerActivity.java

@@ -0,0 +1,109 @@
+//package com.hc.webapp.video;
+//
+//import android.app.Activity;
+//import android.os.Build;
+//import android.os.Bundle;
+//import android.support.annotation.Nullable;
+//import android.view.KeyEvent;
+//import android.widget.Toast;
+//
+//import com.hc.sysvideo.BDVideoView;
+//import com.hc.webapp.R;
+//
+//public class SysVideoPlayerActivity extends Activity implements
+//        BDVideoView.BdPlayerListener {
+//
+//    private BDVideoView videoView;
+//
+//    @Override
+//    protected void onStart() {
+//        super.onStart();
+//        if(videoView != null) {
+//            videoView.onStart();
+//        }
+//    }
+//
+//    @Override
+//    protected void onCreate(@Nullable Bundle savedInstanceState) {
+//        super.onCreate(savedInstanceState);
+//        setContentView(R.layout.activity_video_player);
+//        init();
+//    }
+//
+//    private void init() {
+//        videoView = findViewById(R.id.video_player);
+//        videoView.setActivity(this);
+//
+//        VideoInfo info = new VideoInfo("测试", "http://10.43.111.4/88888888/16/20171218/268485555/index.m3u8?servicetype=0");
+//
+//        videoView.startPlayVideo(info);
+//        videoView.setBdPlayerListener(this);
+//    }
+//
+//    //遥控事件
+//    @Override
+//    public boolean onKeyDown(int keyCode, KeyEvent event) {
+//        switch (keyCode) {
+//            case KeyEvent.KEYCODE_DPAD_CENTER:      //播放/暂停
+//                playOrPause();
+//                return true;
+////            case KeyEvent.KEYCODE_DPAD_LEFT:
+////                if (videoView.canSeek()) {
+////                    seekBack();
+////                } else {
+////                    Toast.makeText(SysVideoPlayerActivity.this, "视频准备中,暂时不能拖动快进", Toast.LENGTH_SHORT).show();
+////                }
+////                return true;
+////            case KeyEvent.KEYCODE_DPAD_RIGHT:
+////                //seekForward();
+////                if (videoView.canSeek()) {
+////                    seekForward();
+////                } else {
+////                    Toast.makeText(SysVideoPlayerActivity.this, "视频准备中,暂时不能拖动快进", Toast.LENGTH_SHORT).show();
+////                }
+////                return true;
+////            case KeyEvent.KEYCODE_BACK:      //到顶跳到相应tab
+////                /* duduPlayer.pause();*/
+////                videoView.pause();
+////                if (!showVideoEndDialog) {
+////                    if (Build.VERSION.SDK_INT > 15) {
+////                        showVideoEndDialog();
+////                    } else {
+////                        SysVideoPlayerActivity.this.finish();
+////                    }
+////                    //Toast.makeText(this,"显示VideoEndDialog",Toast.LENGTH_SHORT).show();
+////                    return true;
+////                } else {
+////                    return false;
+////                }
+//        }
+//        return false;
+//    }
+//
+//    private void playOrPause(){
+//        videoView.playOrPause();
+//    }
+//
+//    @Override
+//    public void onComplete() {
+//
+//    }
+//
+//    @Override
+//    protected void onStop() {
+//        super.onStop();
+//        if(videoView != null) {
+//            videoView.onStop();
+//        }
+//        this.finish();
+//    }
+//
+//    @Override
+//    protected void onDestroy() {
+//        if(videoView != null) {
+//            videoView.onDestroy();
+//        }
+//        super.onDestroy();
+//    }
+//
+//}

+ 233 - 0
app/src/main/java/com/hc/webapp/video/VideoControlDelegate.java

@@ -0,0 +1,233 @@
+package com.hc.webapp.video;
+
+import android.arch.lifecycle.Observer;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+import android.webkit.WebView;
+import android.widget.Toast;
+
+import com.hc.lib.video.IVideoPlayer;
+import com.hc.lib.video.OnPlayerPausedListener;
+import com.hc.lib.video.VideoPauseDialog;
+import com.hc.viewmodel.BaseViewModel;
+import com.hc.viewmodel.SingleLiveEvent;
+import com.hc.viewmodel.UserViewModel;
+import com.hc.webapp.web.AndroidToJS;
+import com.hc.webapp.yst.MainActivity;
+import com.hc.webapp.yst.OttLoginUtil;
+
+public class VideoControlDelegate implements VideoPauseDialog.OnPlayItemSelectedListener, OnPlayerPausedListener {
+
+    public static final int PLAY_TIME_NO_LIMIT = -1; //  不限制播放时间
+
+    private FragmentActivity activity;
+    private IVideoPlayer videoPlayer;
+    private VideoPauseDialog pauseDialog;
+
+    private WebView webView;
+
+    private UserViewModel userViewModel;
+    private boolean hadCollectedVideo = false;
+
+    private String uid; // 用户
+    private String sourceId;  // 源ID
+
+    private long limitTime = PLAY_TIME_NO_LIMIT;
+
+    private SingleLiveEvent<String> eventSourceId;
+    private SingleLiveEvent<Boolean> exitPlayingEvent;
+
+    public VideoControlDelegate(FragmentActivity activity, IVideoPlayer videoPlayer) {
+        this.videoPlayer = videoPlayer;
+        this.activity = activity;
+        eventSourceId = new SingleLiveEvent<>();
+        exitPlayingEvent = new SingleLiveEvent<>();
+        userViewModel = BaseViewModel.obtainViewModel(activity, UserViewModel.class);
+    }
+
+    public void setWebView(WebView webView) {
+        this.webView = webView;
+    }
+
+    public void setFullVideo(boolean fullVideo) {
+        videoPlayer.setFullVideo(fullVideo);
+    }
+
+    public SingleLiveEvent<Boolean> getExitPlayingEvent() {
+        return exitPlayingEvent;
+    }
+
+    public void setUid(String uid) {
+        this.uid = uid;
+    }
+
+    public void setSourceId(String sourceId) {
+        this.sourceId = sourceId;
+        if (TextUtils.isEmpty(sourceId)) {
+            return;
+        }
+        eventSourceId.setValue(sourceId);
+    }
+
+    public void subscribeData() {
+        eventSourceId.observe(activity, new Observer<String>() {
+            @Override
+            public void onChanged(@Nullable String s) {
+                if (TextUtils.isEmpty(uid)) {
+                    return;
+                }
+                userViewModel.hadCollectedSource(uid, sourceId);
+            }
+        });
+
+        // 观察是否收藏数据源
+        userViewModel.hadCollectedSource.observe(activity, new Observer<Boolean>() {
+
+            @Override
+            public void onChanged(@Nullable Boolean result) {
+                hadCollectedVideo = result == null ? false : result;
+            }
+        });
+        // 观察是否收藏/取消收藏成功
+        userViewModel.isCollectedSuccess.observe(activity, new Observer<Boolean>() {
+            @Override
+            public void onChanged(@Nullable Boolean result) {
+                hadCollectedVideo = result == null ? false : result;
+                OttLoginUtil.getInstance().reportCollectedOrNotLog(hadCollectedVideo, sourceId);
+                if (pauseDialog != null) {
+                    pauseDialog.setIsCollected(hadCollectedVideo);
+                }
+            }
+        });
+
+        userViewModel.toastEvent.observe(activity, new Observer<String>() {
+            @Override
+            public void onChanged(@Nullable String s) {
+                Toast.makeText(activity, s, Toast.LENGTH_LONG).show();
+            }
+        });
+    }
+
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
+            //playResume(false);
+            videoPlayer.keyCodeBack();
+        } else {
+            videoPlayer.onKeyDown(keyCode, event);
+        }
+        return true;
+    }
+
+    protected void onResume() {
+        if (videoPlayer != null) {
+            videoPlayer.onVideoResume();
+        }
+    }
+
+    protected void onPause() {
+        if (videoPlayer != null) {
+            videoPlayer.onVideoPause();
+        }
+    }
+
+    public void onDestroy() {
+        if (videoPlayer != null) {
+            videoPlayer.onVideoDestroy();
+        }
+//        if (videoPlayer instanceof HCVideoPlayer) {
+//            GSYVideoManager.releaseAllVideos();
+//        }
+    }
+
+    private void showPauseDialog(boolean hadCollectedVideo,boolean isPlayCompleted) {
+        if (pauseDialog == null) {
+            pauseDialog = new VideoPauseDialog(videoPlayer.getContext(),isPlayCompleted);
+            pauseDialog.setOnPlayItemSelectedListener(this);
+        }
+        if (!pauseDialog.isShowing()) {
+            pauseDialog.show();
+        }
+        pauseDialog.setHasComplete(isPlayCompleted);
+        pauseDialog.setIsCollected(hadCollectedVideo);
+    }
+
+
+    @Override
+    public void playReStart() {
+        videoPlayer.restart();
+    }
+
+    @Override
+    public void playResume(boolean play) {
+        videoPlayer.pauseOrPlay(play);
+    }
+
+    @Override
+    public void playCollect() {
+        if (hadCollectedVideo) {
+            userViewModel.deleteCollection(uid, sourceId);
+        } else {
+            userViewModel.collectSource(uid, sourceId);
+        }
+    }
+
+    @Override
+    public void playExit(boolean playComplete) {
+        //判断视频是否播放完成,来判断是否要储存上次播放时间
+        videoPlayer.storeLastPlayTime();
+        exitPlayingEvent.setValue(true);
+    }
+
+    @Override
+    public void playFavorite(String sourceId, String title) {
+        MainActivity mainActivity =(MainActivity)activity;
+        mainActivity.favoritePlay(sourceId,title);
+    }
+
+    @Override
+    public void videoPaused() {
+        showPauseDialog(hadCollectedVideo, false);
+    }
+
+    @Override
+    public void videoCompleted(boolean showCompletedDialog) {
+        if (showCompletedDialog) {
+            showPauseDialog(hadCollectedVideo,  true);
+        } else {
+            AndroidToJS.evaluateJavascript(webView, AndroidToJS.JS_EVENT_PLAY_NEXT);
+        }
+    }
+
+    @Override
+    public void videoExit(boolean destroyVideo) {
+        //判断视频是否播放完成,来判断是否要储存上次播放时间
+        videoPlayer.storeLastPlayTime();
+
+        exitPlayingEvent.setValue(true);
+        if (destroyVideo) {
+            onDestroy();
+        }
+    }
+
+//    private String getPlayState(int state) {
+//        switch (state) {
+//            case GSYVideoView.CURRENT_STATE_NORMAL:
+//                return "正常";
+//            case GSYVideoView.CURRENT_STATE_PREPAREING:
+//                return "准备中";
+//            case GSYVideoView.CURRENT_STATE_PLAYING:
+//                return "播放中";
+//            case GSYVideoView.CURRENT_STATE_PLAYING_BUFFERING_START:
+//                return "开始缓冲";
+//            case GSYVideoView.CURRENT_STATE_PAUSE:
+//                return "暂停";
+//            case GSYVideoView.CURRENT_STATE_AUTO_COMPLETE:
+//                return "自动播放结束";
+//            case GSYVideoView.CURRENT_STATE_ERROR:
+//                return "错误状态";
+//        }
+//        return null;
+//    }
+}

+ 24 - 0
app/src/main/java/com/hc/webapp/video/VideoInfo.java

@@ -0,0 +1,24 @@
+//package com.hc.webapp.video;
+//
+//import com.hc.sysvideo.bean.IVideoInfo;
+//
+//public class VideoInfo implements IVideoInfo{
+//
+//    private String title;
+//    private String videoPath;
+//
+//    public VideoInfo(String title, String videoPath) {
+//        this.title = title;
+//        this.videoPath = videoPath;
+//    }
+//
+//    @Override
+//    public String getVideoTitle() {
+//        return title;
+//    }
+//
+//    @Override
+//    public String getVideoPath() {
+//        return videoPath;
+//    }
+//}

+ 631 - 0
app/src/main/java/com/hc/webapp/web/AndroidToJS.java

@@ -0,0 +1,631 @@
+package com.hc.webapp.web;
+
+import android.app.Activity;
+import android.arch.lifecycle.Observer;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringDef;
+import android.support.v4.app.FragmentActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+
+import com.hc.lib.MacUtil;
+import com.hc.lib.video.IVideoPlayer;
+import com.hc.model.FJYD.FJYDContentProvider;
+import com.hc.request.business.UserService;
+import com.hc.request.core.DefaultCallback;
+import com.hc.viewmodel.BaseViewModel;
+import com.hc.viewmodel.FJYDViewModel;
+import com.hc.webapp.BuildConfig;
+import com.hc.webapp.other.ThirdPartPlatform;
+import com.hc.webapp.yst.LocalStore;
+import com.hc.webapp.yst.OttLoginUtil;
+import com.hc.webapp.yst.PayActivity;
+import com.hc.webapp.yst.TrackUtil;
+import com.jewel.lib.android.ScreenAdapter;
+import com.orhanobut.logger.Logger;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
+import java.util.regex.Pattern;
+
+import static com.hc.webapp.video.VideoControlDelegate.PLAY_TIME_NO_LIMIT;
+
+@SuppressWarnings("unused")
+public class AndroidToJS {
+
+    public static final String JS_EVENT_BACK = "javascript:onBackEvent()";
+    public static final String JS_EVENT_PLAY_FINISH = "javascript:onPlayBackEvent()";
+    public static final String JS_EVENT_PLAY_START = "javascript:onPlayStartEvent(%s, %s)";
+    public static final String JS_EVENT_PLAY_NEXT = "javascript:onPlayNextEvent()";
+    public static final String JS_EVENT_PAY = "javascript:gotoPay()";
+    public static final String JS_EVENT_PAY_RESULT = "javascript:gotoPayResult()";
+
+    private static final String IS_TRUE = "1"; // 是
+    private String TAG = "androidToJs";
+
+    private int platformType = BuildConfig.platformType; //1:百事通,2:银河,3:未来
+
+    /**
+     * JS调用类型
+     */
+    @StringDef({JS_EVENT_BACK, JS_EVENT_PLAY_FINISH, JS_EVENT_PAY, JS_EVENT_PLAY_START, JS_EVENT_PLAY_NEXT})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface JsEvent {
+
+    }
+
+    private Context context;
+    private WebView webView;
+    private IVideoPlayer videoPlayer;
+    private FJYDContentProvider fjydContentProvider;
+    private FJYDViewModel fjydViewModel;
+    private ThirdPartPlatform thirdPartPlatform;
+    private PlayVideoListener playVideoListener;
+    private ThirdActivityManager thirdActivityManager;
+    private ThirdActivityManager mainActivityManager;
+    private int trackInitResult;
+    private int limitTime;
+    private int screenWidth, screenHeight;
+
+    public AndroidToJS(Context context, boolean initTrackUtil, boolean initViewModel) {
+        this.context = context;
+        fjydContentProvider = new FJYDContentProvider(context);
+        thirdPartPlatform = new ThirdPartPlatform();
+        screenWidth = ScreenAdapter.getScreenWidth(context);
+        screenHeight = ScreenAdapter.getScreenHeight(context);
+
+        if (initTrackUtil) {
+            trackInitResult = TrackUtil.init(context);
+        }
+
+        if (initViewModel) {
+            fjydViewModel = BaseViewModel.obtainViewModel((FragmentActivity) context, FJYDViewModel.class);
+            fjydViewModel.authFailEvent.observe((FragmentActivity) context, new Observer<String>() {
+                @Override
+                public void onChanged(@Nullable String s) {
+                    evaluateJavascript(webView, String.format(JS_EVENT_PLAY_START, 0, s));
+                }
+            });
+        }
+    }
+
+    public void setPlayVideoListener(PlayVideoListener playVideoListener) {
+        this.playVideoListener = playVideoListener;
+    }
+
+    public void setThirdActivityManager(ThirdActivityManager thirdActivityManager) {
+        this.thirdActivityManager = thirdActivityManager;
+    }
+
+    public void setMainActivityManager(ThirdActivityManager mainActivityManager) {
+        this.mainActivityManager = mainActivityManager;
+    }
+
+    public void setVideoPlayer(IVideoPlayer videoPlayer) {
+        this.videoPlayer = videoPlayer;
+    }
+
+    public void setWebView(WebView webView) {
+        this.webView = webView;
+    }
+
+    /**
+     * 全屏播放
+     *
+     * @param hadFloatVideo 当前H5页面是否有小窗
+     */
+    @JavascriptInterface
+    public void playFull(String url,String sourceId, String title,String hadFloatVideo,
+                         String examineId, String examineType) {
+        Logger.d("调用全屏播放。源ID(%s),标题(%s))", sourceId, title);
+        if (playVideoListener != null) {
+            limitTime = PLAY_TIME_NO_LIMIT;
+            /*if (isDigitsOnly(time)) {
+                limitTime = Integer.parseInt(time);
+            }*/
+            boolean hadFloat = TextUtils.equals(IS_TRUE, hadFloatVideo);
+            ((Activity) context).runOnUiThread(() -> playFull(url,sourceId, title, limitTime, hadFloat, examineId, examineType, true, false));
+        }
+    }
+
+
+    //测试用
+    @JavascriptInterface
+    public void playFull(String url, String sourceId, String title, String time, String hadFloatVideo, String isNextVideo, String showCompleteDialog, int seekTime) {
+        url = "http://111.20.105.60:6060/GZHC/32/HC_SXYD_Movie_1640?AuthInfo=fYRn6wHTB6eMAGUKu9tiy1%2BoDGkdNRH1eBdnpkXBr1uXi01TWCEl%2Fzmj166sZ1RueACMTnEjP0frBL2xVTz0ZJ3iOictBjY4f8JCCb0%2BAijeL2gMxcVwASPkY0a8jA6k&version=v1.0&virtualDomain=GZHC.vod_hpd.zte.com&stbid=0057030000010070181058B42DAE192D&terminalflag=1&userid=58B42DAE192D";
+        sourceId = "1640";
+        title = "053 圣诞奇趣蛋抓蛋机_超清";
+        String examineId = "10001";
+        String examineType = "program";
+        playFull(url,sourceId,title,hadFloatVideo,examineId,examineType);
+    }
+
+
+    /**
+     * 全屏播放
+     *
+     * @param hadFloatVideo   当前H5页面是否有小窗
+     * @param isShowCompleted 播放结束时是否显示弹窗,1表示显示结束弹窗,其他值表示继续播放下一条视频
+     * @param isNextVideo     是否为下一个视频,1表示当前播放的为下一个视频,其他值为第一个视频
+     */
+    @JavascriptInterface
+    public void playFull(String url,String sourceId, String title, String hadFloatVideo,
+                         String examineId, String examineType, String isShowCompleted, String isNextVideo) {
+        Logger.d("调用全屏播放。源ID(%s),标题(%s)", sourceId, title);
+        if (playVideoListener != null) {
+            limitTime = PLAY_TIME_NO_LIMIT;
+            boolean hadFloat = TextUtils.equals(IS_TRUE, hadFloatVideo);
+            boolean isShowDialog = TextUtils.equals(IS_TRUE, isShowCompleted);
+            boolean isCurrentNextVideo = TextUtils.equals(IS_TRUE, isNextVideo);
+            Logger.d("调用全屏播放。hadFloatVideo(%s),isNextVideo(%s),isShowCompleted(%s)", hadFloatVideo, isNextVideo, isShowCompleted);
+            Logger.d("调用全屏播放。有小窗(%s),当前为初始视频(%s),显示结束弹窗(%s)", hadFloat, !isCurrentNextVideo, isShowDialog);
+            ((Activity) context).runOnUiThread(() -> playFull(url,sourceId, title, limitTime, hadFloat, examineId, examineType, isShowDialog, isCurrentNextVideo));
+        }
+    }
+
+    private void playFull(String url,String sourceId, String title, int limitTime, boolean hadFloat,
+                          String examineId, String examineType, boolean isShowCompletedDialog, boolean isNextVideo) {
+        if (isNextVideo) { // 播放下一条视频时,直接在当前全屏窗口开启新视频的播放
+            playVideoListener.playFullVideo(url, title, getUser(), sourceId, limitTime, hadFloat, examineId, examineType, isShowCompletedDialog);
+        } else if (hadFloat) { // 有小窗时,直接切换成全屏
+            playVideoListener.playFullVideo(null, title, getUser(), sourceId, limitTime, hadFloat, examineId, examineType, isShowCompletedDialog);
+        } else { // 开启新的全屏播放窗口
+            playVideoListener.playFullVideo(url, title, getUser(), sourceId, limitTime, hadFloat, examineId, examineType, isShowCompletedDialog);
+        }
+    }
+
+
+    //测试用
+    @JavascriptInterface
+    public void playFloat(String url, String sourceId, String title,
+                          final String x, final String y, final String width, final String height, String needMute) {
+        url = "http://111.20.105.60:6060/GZHC/32/HC_SXYD_Movie_1640?AuthInfo=fYRn6wHTB6eMAGUKu9tiy1%2BoDGkdNRH1eBdnpkXBr1uXi01TWCEl%2Fzmj166sZ1RueACMTnEjP0frBL2xVTz0ZJ3iOictBjY4f8JCCb0%2BAijeL2gMxcVwASPkY0a8jA6k&version=v1.0&virtualDomain=GZHC.vod_hpd.zte.com&stbid=0057030000010070181058B42DAE192D&terminalflag=1&userid=58B42DAE192D";
+        sourceId = "1640";
+        title = "053 圣诞奇趣蛋抓蛋机_超清";
+        String examineId = "10001";
+        String examineType = "program";
+        playFloat(url,sourceId,title,x,y,width,height,examineId,examineType);
+    }
+
+
+    /**
+     * @param sourceId  素材ID
+     * @param title     视频标题
+     * @param x         小窗起始x坐标
+     * @param y         小窗起始y坐标
+     * @param width     小窗宽度
+     * @param height    小窗高度
+     */
+    @JavascriptInterface
+    public void playFloat(String url,String sourceId, String title,
+                          final String x, final String y, final String width, final String height,
+                          String examineId, String examineType) {
+        Logger.d("调用小窗口播放。源ID(%s),标题(%s))", sourceId, title);
+        Logger.d("调用小窗口播放。坐标(%s, %s),宽高(%s, %s)", x, y, width, height);
+
+        limitTime = PLAY_TIME_NO_LIMIT;
+       /* if (isDigitsOnly(time)) {
+            limitTime = Integer.parseInt(time);
+        }*/
+
+        if (isDigitsOnly(x) && isDigitsOnly(y) && isDigitsOnly(width) && isDigitsOnly(height) && playVideoListener != null) {
+
+            int transformX = (int) (Float.parseFloat(x) * screenWidth / 1280);
+            int transformY = (int) (Float.parseFloat(y) * screenHeight / 720);
+            int transformWidth = (int) (Float.parseFloat(width) * screenWidth / 1280);
+            int transformHeight = (int) (Float.parseFloat(height) * screenHeight / 720);
+
+            Logger.d("调用小窗口播放。转换坐标(%s, %s),宽高(%s, %s)", transformX, transformY, transformWidth, transformHeight);
+
+            ((Activity) context).runOnUiThread(() -> playFloat(url,sourceId, title,
+                    transformX, transformY, transformWidth, transformHeight,
+                    examineId, examineType, limitTime));
+        }
+    }
+
+    private void playFloat(String url,String sourceId, String title,
+                           final int x, final int y, final int width, final int height,
+                           String examineId, String examineType, int limitTime) {
+        playVideoListener.playFloatVideo(url,
+                x, y, width, height,
+                getUser(), sourceId, title, examineId, examineType, limitTime);
+    }
+
+    /**
+     * 智慧平台请求接口
+     *
+     * @param firstStepUrl  第一步请求url
+     * @param secondStepUrl 第二步请求url
+     * @param thirdStepUrl  第三步请求url
+     * @param fourStepUrl   第四步请求url
+     * @param k             第二步参数
+     */
+    @JavascriptInterface
+    public void zhPlatformRequest(String firstStepUrl, String secondStepUrl, String thirdStepUrl, String fourStepUrl, int k) {
+//        playVideoListener.zhPlatformRequest(firstStepUrl,secondStepUrl,thirdStepUrl,fourStepUrl,k);
+        thirdPartPlatform.start(firstStepUrl, secondStepUrl, thirdStepUrl, fourStepUrl, k, new DefaultCallback<String>() {
+
+            @Override
+            public void onSuccess(int what, @NonNull String data) {
+                super.onSuccess(what, data);
+                String userId = getUser();
+                if (TextUtils.isEmpty(userId)) {
+                    userId = "1506006516501";
+                }
+                UserService.updateOrder(userId);
+            }
+        });
+    }
+
+    /**
+     * 上传收藏/取消记录
+     * @param isCollected 是否收藏操作
+     * @param id 视频id
+     */
+    @JavascriptInterface
+    public void reportCollectedOrNotLog(boolean isCollected, String id) {
+        OttLoginUtil.getInstance().reportCollectedOrNotLog(isCollected, id);
+    }
+
+    /**
+     * 上传添加历史记录
+     *
+     * @param id 视频id
+     */
+    @JavascriptInterface
+    public void reportAddHistoryLog(String id) {
+        OttLoginUtil.getInstance().reportAddHistoryLog(id);
+    }
+
+    /**
+     * 上传清空历史记录
+     */
+    @JavascriptInterface
+    public void reportClearAllHistoryLog() {
+        OttLoginUtil.getInstance().reportClearAllHistoryLog();
+    }
+
+    /**
+     * 上传搜索日志
+     * @param keyword 关键字
+     */
+    @JavascriptInterface
+    public void reportSearchLog(String keyword) {
+        OttLoginUtil.getInstance().reportSearchLog(keyword);
+    }
+
+    /**
+     * 上传日志
+     * @param type 日志类型,详情请查看未来sdk提供的文档
+     * @param event 日志事件,详情请查看未来sdk提供的文档
+     */
+    @JavascriptInterface
+    public void reportLog(int type, String event) {
+        OttLoginUtil.getInstance().reportLog(type, event);
+    }
+
+    /**
+     * 埋点用户数据
+     *
+     * @param isVip 是否VIP,1表示VIP,其他为非VIP
+     * @param uid   用户ID
+     */
+    @JavascriptInterface
+    public void trackUser(String isVip, String uid) {
+        if (trackInitResult == 0) {
+            boolean vip = TextUtils.equals("1", isVip);
+            LocalStore.getInstance().putUserID(uid);
+            LocalStore.getInstance().putVip(vip);
+            TrackUtil.userEvent(vip, uid, true);
+        }
+    }
+
+    /**
+     * 关闭小窗播放
+     */
+    @JavascriptInterface
+    public void closeFloat() {
+        Logger.d("关闭小窗口播放。");
+        if (fjydViewModel != null) {
+            ((Activity) context).runOnUiThread(() -> fjydViewModel.videoUrl.setValueForVoid());
+        }
+        if (playVideoListener != null) {
+            playVideoListener.stopFloatVideo();
+        }
+    }
+
+    @JavascriptInterface
+    public String getSerialNum() {
+        String serial = getSystemProperty("ro.product.stb.serialnum");
+        Logger.d("序列号:%s", serial);
+        return serial;
+    }
+
+    @JavascriptInterface
+    public String getSTBId() {
+        String stbID = getSystemProperty("ro.product.stb.stbid");
+        Logger.d("STB_ID:%s", stbID);
+        if (TextUtils.isEmpty(stbID)) {
+            return getSerialNum();
+        }
+        return stbID;
+    }
+
+    private String getSystemProperty(String key) {
+        try {
+            Class<?> cls = Class.forName("android.os.SystemProperties");
+            Method m = cls.getDeclaredMethod("get", String.class, String.class);
+            return (String) m.invoke(null, key, "");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    @JavascriptInterface
+    public String getCurrentPlayTime() {
+        String currentTime = "0";
+        if (videoPlayer != null) {
+            currentTime = String.valueOf(videoPlayer.getCurrentTime());
+        }
+        Logger.d("当前播放时间:%s", currentTime);
+        return currentTime;
+    }
+
+    //陕西计费参数 start,add by xu lin 20190307
+    @JavascriptInterface
+    public String getUserId() {
+        return getUserName();
+    }
+
+    @JavascriptInterface
+    public String getEpgServer() {
+        return getUserEpgServer();
+    }
+
+    @JavascriptInterface
+    public String getToken() {
+        return getUserToken();
+    }
+
+    //陕西计费参数 end
+
+    @JavascriptInterface
+    public String getUser() {
+        return fjydContentProvider.getUserName();
+    }
+
+
+
+    @JavascriptInterface
+    public int getVipState() {
+        return 1;
+    }
+
+    @JavascriptInterface
+    public int getVersionCode() {
+        return BuildConfig.VERSION_CODE;
+    }
+
+    @JavascriptInterface
+    public String getVersionName() {
+        return BuildConfig.VERSION_NAME;
+    }
+
+    @JavascriptInterface
+    public String getMac() {
+        String mac = LocalStore.getInstance().getMac();
+        if(!TextUtils.isEmpty(mac)) {
+            return mac;
+        }
+        return MacUtil.getMac(context);
+    }
+
+    @JavascriptInterface
+    public int getPlatformType() {
+        return platformType;
+    }
+
+    @JavascriptInterface
+    public void pay(String url) {
+        //PayActivity.start(context, url);
+    }
+
+    @JavascriptInterface
+    public void payResult(String url) {
+        PayActivity.start(context, url);
+    }
+
+    @JavascriptInterface
+    public void finishPay() {
+        if (thirdActivityManager != null) {
+            thirdActivityManager.finishActivity();
+        }
+    }
+
+    @JavascriptInterface
+    public void appExit() {
+        Logger.d("退出程序");
+        ((Activity) context).runOnUiThread(() -> {
+                    if (mainActivityManager != null) {
+                        mainActivityManager.finishActivity();
+                    }
+                }
+        );
+
+    }
+
+    /**
+     * 埋点用户退出app数据
+     *
+     * @param isVip 是否VIP,1表示VIP,其他为非VIP
+     * @param uid   用户ID
+     */
+    @JavascriptInterface
+    public void trackUserOut(String isVip, String uid) {
+        if (trackInitResult == 0) {
+            TrackUtil.userEvent(TextUtils.equals("1", isVip), uid, false);
+        }
+    }
+
+    /*
+    * 陕西本地计费获取参数
+    * */
+    private String getUserName(){
+        try{
+            Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
+            Cursor cursor = context.getContentResolver().query(queryUri,new String[]{"value"},"name='username'",null,null);
+            cursor.moveToFirst();
+            String userName = cursor.getString(cursor.getColumnIndexOrThrow("value"));
+            Log.d(TAG,"userName:" + userName);
+            return userName;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    private String getUserToken(){
+        try{
+            Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
+            Cursor cursor = context.getContentResolver().query(queryUri,new String[]{"value"},"name='user_token'",null,null);
+            cursor.moveToFirst();
+            String userToken = cursor.getString(cursor.getColumnIndexOrThrow("value"));
+            //userToken = "nBoKXx@OHP3fUP6fmcypIgl135856057";
+            //userToken = "Se48ja9jiqjq-Stjhd4izfd";
+            Log.d(TAG,"userToken:" + userToken);
+            return userToken;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    private String getUserEpgServer(){
+        try{
+            Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
+            Cursor cursor = context.getContentResolver().query(queryUri,new String[]{"value"},"name='epg_server'",null,null);
+            cursor.moveToFirst();
+            String epgServer = cursor.getString(cursor.getColumnIndexOrThrow("value"));
+            //epgServer = "http://111.20.105.85:9330";
+            //epgServer = "http://111.20.42.163:33200";
+            Log.d(TAG,"epgServer:" + epgServer);
+            return epgServer;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    /**
+     * 不够位数的在前面补0,保留num的长度位数字
+     *
+     * @param length 代表拼接后code的长度,比如code为123,拼接后变为00000123
+     * @return 假如code为123,那么返回ps_haochuan00000123
+     */
+    public static String autoGenericCode(String code, int length) {
+        return "ps_haochuan" + String.format("%0" + length + "d", Integer.parseInt(code));
+    }
+
+    /**
+     * 调用js事件
+     *
+     * @param webView webView
+     * @param script  {@link AndroidToJS#JS_EVENT_BACK}、{@link AndroidToJS#JS_EVENT_PLAY_FINISH}
+     */
+    public static void evaluateJavascript(WebView webView, @JsEvent String script) {
+        if (webView == null) {
+            Logger.e("webView对象为空,JS事件调用无法执行");
+            return;
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            webView.evaluateJavascript(script, value -> {
+                //此处为 js 返回的结果
+                Log.d(com.hc.lib.TAG.TAG, value);
+            });
+        } else {
+            webView.loadUrl(script);
+        }
+    }
+
+    private boolean isDigitsOnly(String str) {
+        return isInteger(str) || isDouble(str);
+    }
+
+    // 判断整数(int)
+    private boolean isInteger(String str) {
+        if (null == str || "".equals(str)) {
+            return false;
+        }
+        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
+        return pattern.matcher(str).matches();
+    }
+
+    //判断浮点数(double和float)
+    private boolean isDouble(String str) {
+        if (null == str || "".equals(str)) {
+            return false;
+        }
+        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
+        return pattern.matcher(str).matches();
+    }
+
+
+    public interface PlayVideoListener {
+        /**
+         * 小窗播放视频
+         *
+         * @param url       视频地址
+         * @param x         小窗X坐标
+         * @param y         小窗Y坐标
+         * @param width     小窗宽度
+         * @param height    小窗高度
+         * @param limitTime 可播放时间。如果为{@link com.hc.webapp.video.VideoControlDelegate#PLAY_TIME_NO_LIMIT},代表无限制播放
+         */
+        void playFloatVideo(String url, int x, int y, int width, int height, String uid, String sourceId, String title, String examineId, String examineType, int limitTime);
+
+        /**
+         * 全屏播放
+         *
+         * @param url           视频地址
+         * @param title         视频标题
+
+         * @param uid           用户id
+         * @param sourceId      源ID
+         * @param limitTime     可播放时间。如果为{@link com.hc.webapp.video.VideoControlDelegate#PLAY_TIME_NO_LIMIT},代表无限制播放
+         * @param hadFloatVideo 当前H5页面是否有小窗
+         */
+        void playFullVideo(String url, String title, String uid, String sourceId, int limitTime,
+                           boolean hadFloatVideo, String examineId, String examineType, boolean isShowCompletedDialog);
+
+        /**
+         * 结束小窗播放
+         */
+        void stopFloatVideo();
+    }
+
+//    public interface ThirdPartPlatformManager {
+//        /**
+//         * 智慧平台请求接口
+//         *
+//         * @param firstStepUrl  第一步请求url
+//         * @param secondStepUrl 第二步请求url
+//         * @param thirdStepUrl  第三步请求url
+//         * @param fourStepUrl   第四步请求url
+//         * @param k             第二步参数
+//         */
+//        void zhPlatformRequest(String firstStepUrl, String secondStepUrl, String thirdStepUrl, String fourStepUrl, int k);
+//    }
+
+    public interface ThirdActivityManager {
+        void finishActivity();
+    }
+}

+ 291 - 0
app/src/main/java/com/hc/webapp/web/BaseWebActivity.java

@@ -0,0 +1,291 @@
+package com.hc.webapp.web;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+
+import com.hc.lib.HandlerUtil;
+import com.hc.webapp.BuildConfig;
+import com.orhanobut.logger.Logger;
+
+import org.json.JSONObject;
+
+@SuppressWarnings("unused")
+public abstract class BaseWebActivity extends AppCompatActivity {
+
+    public static final int REQUEST_PLAY_FINISH = 0x100;
+
+    private WebView webView;
+
+    private AndroidToJS onJsEvent;
+
+    private int platformType = BuildConfig.platformType; //1:百事通,2:银河,3:未来
+
+    protected boolean hasShowWebView = false;
+    protected boolean hasOneFloatViewToShow = true;
+
+    /**
+     * JS调用对象名
+     */
+    private String JsInvokeName = AndroidToJS.class.getSimpleName();
+    /**
+     * 是否监听返回按键,作用于{@link BaseWebActivity#onKeyDown(int, KeyEvent)}
+     */
+    private boolean shouldOverrideBackKeyEvent;
+    /**
+     * 是否监听返回按键,作用于{@link BaseWebActivity#onBackPressed()}
+     */
+    private boolean shouldOverrideBackPressToJS = true;
+
+    /**
+     * 获取启动页web地址
+     */
+    protected abstract String getIndexURL();
+
+    /**
+     * 获取JS调用对象名。
+     */
+    protected String getJsInvokeName() {
+        return JsInvokeName;
+    }
+
+    public AndroidToJS getJsEvent() {
+        return onJsEvent;
+    }
+
+    /**
+     * 设置是否监听返回按键
+     *
+     * @param shouldOverrideBackKeyEvent 默认为<code>false</code>
+     */
+    protected void setShouldOverrideBackKeyEvent(boolean shouldOverrideBackKeyEvent) {
+        this.shouldOverrideBackKeyEvent = shouldOverrideBackKeyEvent;
+    }
+
+    /**
+     * 设置是否替换返回键为JS调用
+     *
+     * @param shouldOverrideBackPressForJS 默认为<code>true</code>
+     */
+    public void setShouldOverrideBackPressToJS(boolean shouldOverrideBackPressForJS) {
+        this.shouldOverrideBackPressToJS = shouldOverrideBackPressForJS;
+    }
+
+    public void setAndroidToJSListener(AndroidToJS androidToJS) {
+    }
+
+    public WebView getWebView() {
+        return webView;
+    }
+
+    public boolean needInitTrackUtil() {
+        return true;
+    }
+
+    public boolean needInitViewModel() {
+        return true;
+    }
+
+    public void handleIntent(Intent intent) {
+
+    }
+
+    public void loadH5() {
+        if(webView == null) {
+            return;
+        }
+        String url = getIndexURL();
+        webView.loadUrl(getIndexURL());
+    }
+
+    public HCWebViewClient.WebViewErrorListener getWebViewErrorListener() {
+        return null;
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (getIntent() != null) {
+            handleIntent(getIntent());
+        }
+
+        webView = new WebView(getApplicationContext());
+        webView.setBackgroundColor(ContextCompat.getColor(this, android.R.color.transparent));
+//        webView.setBackgroundResource(R.drawable.img_start_bg);
+        setContentView(webView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+        webView.setSoundEffectsEnabled(false);
+        webView.setAnimationCacheEnabled(false);
+
+        initWebSetting(webView);
+    }
+
+    @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface", "AddJavascriptInterface"})
+    private void initWebSetting(WebView webView) {
+        WebSettings webSettings = webView.getSettings();
+        // 由H5端适配屏幕,具体参考文档:https://developer.chrome.com/multidevice/webview/pixelperfect
+        webSettings.setUseWideViewPort(true);
+        webSettings.setLoadWithOverviewMode(true);
+        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
+        // 设置JS交互
+        webSettings.setJavaScriptEnabled(true);
+
+        onJsEvent = new AndroidToJS(this, needInitTrackUtil(), needInitViewModel());
+        onJsEvent.setWebView(webView);
+        setAndroidToJSListener(onJsEvent);
+        webView.addJavascriptInterface(onJsEvent, getJsInvokeName());
+        Log.d("weilai","addJavascriptInterface");
+        // 设置WebClient
+        HCWebViewClient hcWebViewClient = new HCWebViewClient();
+        hcWebViewClient.setWebViewErrorListener(getWebViewErrorListener());
+        webView.setWebViewClient(hcWebViewClient);
+        webView.setWebChromeClient(new HCWebChromeClient());
+
+        webView.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url)
+            {
+                Log.d("MainActivity","onPageFinished");
+                hasShowWebView = true;
+                webView.setVisibility(View.VISIBLE);
+                if(hasOneFloatViewToShow){
+                    delayShowFloatView();
+                }
+                updateApk();
+            }
+
+            @Override
+            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+            }
+        });
+        // 设置是否开启web内容调试,具体调试方式查看:https://developers.google.com/web/tools/chrome-devtools/remote-debugging/?utm_source=dcc&utm_medium=redirect&utm_campaign=2016q3
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            WebView.setWebContentsDebuggingEnabled(BuildConfig.isDebug);
+        }
+    }
+
+    protected void updateApk(){
+        String url = "http://112.35.32.145:8090/index.php?m=Home&c=AndroidApi&a=uploadVersion&origin="+platformType;
+        GetRuquest getRuquest = new GetRuquest();
+        getRuquest.RequestAsync(url, new GetRequestListener() {
+            @Override
+            public void onResult(String msg) {
+                try{
+                    JSONObject jsonObject = new JSONObject(msg);
+                    int code = jsonObject.getInt("code");
+                    if(code == 0){
+                        JSONObject data = jsonObject.getJSONObject("data");
+                        int versionCode = data.getInt("versionCode");
+                        int currentVCode = BaseWebActivity.this.getPackageManager().getPackageInfo(
+                                BaseWebActivity.this.getPackageName(),0
+                        ).versionCode;
+                        boolean hasUpdate = false;
+                        if(versionCode > currentVCode){
+                            hasUpdate = true;
+                            Toast("版本有更新,后台正在下载中...");
+                            String versionName = data.getString("versionName");
+                            String url = data.getString("url");
+                            int size = data.getInt("size");
+                            String updateContent = data.getString("updateContent");
+                            String md5 = data.getString("md5");
+                            new DownloadInstall(BaseWebActivity.this).start(url,md5);
+                        }
+
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    private void Toast(String msg){
+        BaseWebActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Toast.makeText(BaseWebActivity.this,msg,Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    protected abstract void delayShowFloatView();
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (webView != null) {
+            webView.onResume();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (webView != null) {
+            webView.onPause();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (webView != null) {
+            webView.removeJavascriptInterface(JsInvokeName);
+            webView.clearCache(true);
+            webView.clearFormData();
+            webView.clearMatches();
+            webView.clearSslPreferences();
+            webView.clearDisappearingChildren();
+            webView.clearHistory();
+            webView.clearAnimation();
+            webView.loadUrl("about:blank");
+            webView.removeAllViews();
+
+            webView = null;
+        }
+        super.onDestroy();
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (shouldOverrideBackPressToJS) {
+            AndroidToJS.evaluateJavascript(webView, AndroidToJS.JS_EVENT_BACK);
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == RESULT_OK) {
+            switch (requestCode) {
+                case REQUEST_PLAY_FINISH:
+                    Logger.d("播放结束,调用javascript:onPlayBackEvent()");
+                    AndroidToJS.evaluateJavascript(webView, AndroidToJS.JS_EVENT_PLAY_FINISH);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}

+ 87 - 0
app/src/main/java/com/hc/webapp/web/DownloadInstall.java

@@ -0,0 +1,87 @@
+package com.hc.webapp.web;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.support.v4.content.FileProvider;
+
+import com.hc.webapp.BuildConfig;
+import com.liulishuo.filedownloader.BaseDownloadTask;
+import com.liulishuo.filedownloader.FileDownloadListener;
+import com.liulishuo.filedownloader.FileDownloader;
+import com.liulishuo.filedownloader.util.FileDownloadUtils;
+
+import java.io.File;
+
+public class DownloadInstall {
+    private String TAG = "DownloadInstall";
+    private Context context;
+    public  DownloadInstall(Context context){
+        this.context = context;
+    }
+    public void start(String url,String md5){
+        downloadApk(url,md5);
+    }
+
+    private void downloadApk(final String url,final String md5){
+        String filePath = FileDownloadUtils.getDefaultSaveRootPath();
+        FileDownloader.getImpl().create(url)
+                .setPath(filePath,true)
+                .setCallbackProgressTimes(300)
+                .setMinIntervalUpdateSpeed(400)
+                .setListener(new FileDownloadListener() {
+                    @Override
+                    protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
+
+                    }
+
+                    @Override
+                    protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
+
+                    }
+
+                    @Override
+                    protected void completed(BaseDownloadTask task) {
+                        File file = new File( FileDownloadUtils.getDefaultSaveFilePath(url));
+                        String apkMD5 = MD5.getFileMD5(file).toUpperCase();
+                        String updateD5 = md5.toUpperCase();
+                        if(!apkMD5.equals(updateD5)){
+                            file.delete();
+                            downloadApk(url,md5);
+                        }else{
+                            apkInstall(file);
+                        }
+                    }
+
+                    @Override
+                    protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {
+
+                    }
+
+                    @Override
+                    protected void error(BaseDownloadTask task, Throwable e) {
+                        e.printStackTrace();
+                    }
+
+                    @Override
+                    protected void warn(BaseDownloadTask task) {
+
+                    }
+                })
+                .start();
+    }
+
+    private void apkInstall(File apkFile){
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
+            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
+            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
+        }else{
+            intent.setDataAndType(Uri.fromFile(apkFile),
+                    "application/vnd.android.package-archive");
+        }
+        context.startActivity(intent);
+    }
+}

+ 5 - 0
app/src/main/java/com/hc/webapp/web/GetRequestListener.java

@@ -0,0 +1,5 @@
+package com.hc.webapp.web;
+
+public interface GetRequestListener {
+    public void onResult(String msg);
+}

+ 39 - 0
app/src/main/java/com/hc/webapp/web/GetRuquest.java

@@ -0,0 +1,39 @@
+package com.hc.webapp.web;
+
+import android.os.AsyncTask;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class GetRuquest {
+    OkHttpClient client = new OkHttpClient();
+    GetRequestListener listener;
+    private String RequestSynchro(String url) throws Exception{
+        Request request = new Request.Builder()
+                .url(url)
+                .build();
+
+        Response response = client.newCall(request).execute();
+        return response.body().string();
+    }
+
+    public void RequestAsync(String url,GetRequestListener listener){
+        this.listener =listener;
+        new RequestAsyncTask().execute(url);
+    }
+
+    class RequestAsyncTask extends AsyncTask<String,Integer,String>{
+
+        @Override
+        protected String doInBackground(String... strings) {
+            try{
+                String response = RequestSynchro(strings[0]);
+                listener.onResult(response);
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+            return "";
+        }
+    }
+}

+ 18 - 0
app/src/main/java/com/hc/webapp/web/HCWebChromeClient.java

@@ -0,0 +1,18 @@
+package com.hc.webapp.web;
+
+import android.util.Log;
+import android.webkit.ConsoleMessage;
+import android.webkit.WebChromeClient;
+
+import com.hc.lib.TAG;
+
+public class HCWebChromeClient extends WebChromeClient {
+
+    @Override
+    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+        Log.d(TAG.TAG, consoleMessage.message() + " -- From line "
+                + consoleMessage.lineNumber() + " of "
+                + consoleMessage.sourceId() );
+        return true;
+    }
+}

+ 71 - 0
app/src/main/java/com/hc/webapp/web/HCWebViewClient.java

@@ -0,0 +1,71 @@
+package com.hc.webapp.web;
+
+import android.util.Log;
+import android.webkit.RenderProcessGoneDetail;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.orhanobut.logger.Logger;
+
+/**
+ * 自定义WebViewClient控制器
+ */
+public class HCWebViewClient extends WebViewClient {
+
+    public static final String NETWORK_ACCESS_DENIED = "net::ERR_NETWORK_ACCESS_DENIED"; // 无网络请求权限
+    public static final String UNKNOWN_URL_SCHEME = "net::ERR_UNKNOWN_URL_SCHEME"; // 未知的URL
+    public static final String INTERNET_DISCONNECTED = "net::ERR_INTERNET_DISCONNECTED"; // 网络未连接
+
+    private WebViewErrorListener webViewErrorListener;
+
+    public void setWebViewErrorListener(WebViewErrorListener webViewErrorListener) {
+        this.webViewErrorListener = webViewErrorListener;
+    }
+
+
+//    @Override
+//    public boolean shouldOverrideUrlLoading(WebView view, String url) {
+//        if(BuildConfig.Domain.equals(Uri.parse(url).getHost())) { // url为指定域名的才处理
+//            view.loadUrl(url);
+//            return false;
+//        }
+//        // 非本公司Url的交由系统处理
+//        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+//        view.getContext().startActivity(intent);
+//        return true;
+//    }
+
+    /**
+     * 当浏览器渲染进程异常时的处理
+     */
+    @Override
+    public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
+        Logger.d("浏览器渲染进程异常:%s", detail.toString());
+        return super.onRenderProcessGone(view, detail);
+    }
+
+//    @Override
+//    public void onPageStarted(WebView view, String url, Bitmap favicon) {
+//        view.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
+//        super.onPageStarted(view, url, favicon);
+//    }
+//
+//    @Override
+//    public void onPageFinished(WebView view, String url) {
+//        super.onPageFinished(view, url);
+//        view.setLayerType(View.LAYER_TYPE_HARDWARE,null);
+//    }
+
+    @Override
+    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+        super.onReceivedError(view, errorCode, description, failingUrl);
+        Logger.d("网页请求错误:%s(错误码%s)", description, errorCode);
+        if(webViewErrorListener != null) {
+            webViewErrorListener.onReceiveError(view, errorCode, description, failingUrl);
+        }
+    }
+
+    public interface WebViewErrorListener {
+        void onReceiveError(WebView view, int errorCode, String description, String failingUrl);
+    }
+}

+ 50 - 0
app/src/main/java/com/hc/webapp/web/MD5.java

@@ -0,0 +1,50 @@
+package com.hc.webapp.web;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.MessageDigest;
+
+/**
+ * Created by yunhaipiaodi on 2017/10/18.
+ */
+
+public class MD5 {
+
+    public static String getFileMD5(File file) {
+        if (!file.isFile()) {
+            return null;
+        }
+        MessageDigest digest = null;
+        FileInputStream in = null;
+        byte buffer[] = new byte[1024];
+        int len;
+        try {
+            digest = MessageDigest.getInstance("MD5");
+            in = new FileInputStream(file);
+            while ((len = in.read(buffer, 0, 1024)) != -1) {
+                digest.update(buffer, 0, len);
+            }
+            in.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+        return bytesToHexString(digest.digest());
+    }
+
+    public static String bytesToHexString(byte[] src) {
+        StringBuilder stringBuilder = new StringBuilder("");
+        if (src == null || src.length <= 0) {
+            return null;
+        }
+        for (int i = 0; i < src.length; i++) {
+            int v = src[i] & 0xFF;
+            String hv = Integer.toHexString(v);
+            if (hv.length() < 2) {
+                stringBuilder.append(0);
+            }
+            stringBuilder.append(hv);
+        }
+        return stringBuilder.toString();
+    }
+}

文件差異過大導致無法顯示
+ 243 - 0
app/src/main/java/com/hc/webapp/yst/AdData.java


+ 139 - 0
app/src/main/java/com/hc/webapp/yst/LocalStore.java

@@ -0,0 +1,139 @@
+package com.hc.webapp.yst;
+
+import com.jewel.lib.android.SharedPre;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/26.
+ */
+@SuppressWarnings("unused")
+public class LocalStore {
+
+    private static LocalStore instance;
+
+    private String KEY_DEVICE_ID = "deviceId";
+    private String KEY_TEMPLATE_ID = "templateId";
+    private String KEY_PLATFORM_ID = "platformId";
+    private String KEY_MAC = "mac";
+    private String KEY_OTT_TOKEN = "ottToken";
+    private String KEY_SERVER_AD = "server_AD"; // 广告服务器
+    private String KEY_SERVER_YST_EPG = "server_YST_EPG"; // EPG服务器
+    private String KEY_SERVER_SEARCH = "server_SEARCH"; // 搜索服务器
+    private String KEY_SERVER_LOG = "server_LOG"; // 日志服务器
+    private String KEY_SERVER_CDN = "server_CDN"; // CDN调度
+    private String KEY_SERVER_UPDATE = "server_UPDATE"; // 升级服务器
+
+    private String KEY_OPEN_AD = "openAdJson"; // 开屏广告图片
+    private String KEY_OPEN_AD_IMAGE = "localOpenAdImage"; // 开屏广告图片
+
+    private String KEY_USER_ID = "userId";
+    private String KEY_IS_VIP = "isVip";
+
+    public static LocalStore getInstance() {
+        if (instance == null) {
+            instance = new LocalStore();
+        }
+        return instance;
+    }
+
+    public void putDeviceId(String deviceId) {
+        SharedPre.putString(KEY_DEVICE_ID, deviceId);
+    }
+
+    public void putTemplateId(String templateId) {
+        SharedPre.putString(KEY_TEMPLATE_ID, templateId);
+    }
+
+    public void putPlatformId(String platformId) {
+        SharedPre.putString(KEY_PLATFORM_ID, platformId);
+    }
+
+    public void putMac(String mac) {
+        SharedPre.putString(KEY_MAC, mac);
+    }
+
+    public void putOttToken(String ottToken) {
+        SharedPre.putString(KEY_OTT_TOKEN, ottToken);
+    }
+
+    public void putYST_EPG_Server(String server) {
+        SharedPre.putString(KEY_SERVER_YST_EPG, server);
+    }
+
+    public void putADServer(String server) {
+        SharedPre.putString(KEY_SERVER_AD, server);
+    }
+
+    public void putLogServer(String server) {
+        SharedPre.putString(KEY_SERVER_LOG, server);
+    }
+
+    public void putUpdateServer(String server) {
+        SharedPre.putString(KEY_SERVER_UPDATE, server);
+    }
+
+    public void putSearchServer(String server) {
+        SharedPre.putString(KEY_SERVER_SEARCH, server);
+    }
+
+    public void putUserID(String id) {
+        SharedPre.putString(KEY_USER_ID, id);
+    }
+
+    public void putVip(boolean isVip) {
+        SharedPre.putBoolean(KEY_IS_VIP, isVip);
+    }
+
+    public String getDeviceId() {
+        return SharedPre.getString(KEY_DEVICE_ID, "");
+    }
+    public String getTemplateId() {
+        return SharedPre.getString(KEY_TEMPLATE_ID, "");
+    }
+    public String getPlatformId() {
+        return SharedPre.getString(KEY_PLATFORM_ID, "");
+    }
+    public String getMac() {
+        return SharedPre.getString(KEY_MAC, "");
+    }
+    public String getOttToken() {
+        return SharedPre.getString(KEY_OTT_TOKEN, "");
+    }
+    public String getYST_EPG_Server() {
+        return SharedPre.getString(KEY_SERVER_YST_EPG, "");
+    }
+    public String getADServer() {
+        return SharedPre.getString(KEY_SERVER_AD, "");
+    }
+    public String getLogServer() {
+        return SharedPre.getString(KEY_SERVER_LOG, "");
+    }
+    public String getUpdateServer() {
+        return SharedPre.getString(KEY_SERVER_UPDATE, "");
+    }
+    public String getSearchServer() {
+        return SharedPre.getString(KEY_SERVER_SEARCH, "");
+    }
+
+    public String getUserID() {
+        return SharedPre.getString(KEY_USER_ID, "");
+    }
+    public boolean isVip() {
+        return SharedPre.getBoolean(KEY_IS_VIP, false);
+    }
+
+    public void putOpenAdJson(String openAdJson) {
+        SharedPre.putString(KEY_OPEN_AD, openAdJson);
+    }
+
+    public String getOpenAdJson() {
+        return SharedPre.getString(KEY_OPEN_AD, "");
+    }
+
+    public void putOpenAdImage(String localImgPath) {
+        SharedPre.putString(KEY_OPEN_AD_IMAGE, localImgPath);
+    }
+
+    public String getOpenAdImage() {
+        return SharedPre.getString(KEY_OPEN_AD_IMAGE, "");
+    }
+}

+ 617 - 0
app/src/main/java/com/hc/webapp/yst/MainActivity.java

@@ -0,0 +1,617 @@
+package com.hc.webapp.yst;
+
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.LinearInterpolator;
+import android.webkit.WebView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.hc.lib.http.GetRequest;
+import com.hc.lib.http.GetRequestListener;
+import com.hc.viewmodel.BaseViewModel;
+import com.hc.viewmodel.UserViewModel;
+import com.hc.webapp.BaseApp;
+import com.hc.webapp.BuildConfig;
+import com.hc.webapp.R;
+import com.hc.webapp.model.VideoInfo;
+import com.hc.webapp.store.LastPlayTimeStore;
+import com.hc.webapp.video.VideoControlDelegate;
+import com.hc.webapp.web.AndroidToJS;
+import com.hc.webapp.web.BaseWebActivity;
+import com.hc.webapp.web.HCWebViewClient;
+import com.jewel.lib.android.CompatUtil;
+import com.jewel.lib.android.HandlerUtil;
+import com.jewel.lib.android.SharedPre;
+import com.jewel.lib.android.live.SingleLiveEvent;
+import com.jewel.lib.java.StringUtil;
+import com.jewel.util.view.inject.ViewInjectFactory;
+import com.orhanobut.logger.Logger;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class MainActivity extends BaseWebActivity implements OttLoginUtil.OnOttListener,
+        AndroidToJS.PlayVideoListener, HCWebViewClient.WebViewErrorListener, AndroidToJS.ThirdActivityManager {
+
+    final String url = com.hc.model.BuildConfig.Domain + com.hc.model.BuildConfig.port + "/h5v2/index.html";
+    private static final String KEY_INTENT = "params";
+
+    private SingleLiveEvent<String> loginMsg = new SingleLiveEvent<>();
+//    public static final String[] urls = {"http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4",
+//            "https://hnh5pic.oss-cn-shenzhen.aliyuncs.com/20180910_test.ts"};
+
+    private YSTVideoPlayer YSTVideoPlayer;
+    private VideoControlDelegate controlDelegate;
+    private UserViewModel userViewModel;
+    private View messageView;
+
+    private boolean isFinish = false;
+
+    private int floatVideoX = -1, floatVideoY = -1;
+    private int floatVideoWidth = -1, floatVideoHeight = -1;
+    private boolean isFullScreenVideo = false;
+    private boolean hadFloatVideo = false;
+
+    private String newUrl = null;
+
+    private int adCount = 5;
+
+    private VideoInfo lastVideoInfo;
+
+    String TAG ="MainActivity";
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        observer();
+        Log.d("weilai","loadH5");
+        loadH5();
+
+        String adImage = LocalStore.getInstance().getOpenAdImage();
+        if (!TextUtils.isEmpty(adImage)) {
+            ImageView imageView = new ImageView(this);
+            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
+            imageView.setImageDrawable(Drawable.createFromPath(adImage));
+            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+            viewGroup.addView(imageView);
+
+            TextView textView = new TextView(this);
+            textView.setText(StringUtil.get(getApplicationContext(), R.string.ad_finish, adCount));
+            textView.setBackgroundResource(R.drawable.bg_ad_time);
+            textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
+            textView.setPadding(10, 10 ,10, 10);
+            textView.setTextColor(CompatUtil.getColor(getApplicationContext(), android.R.color.black));
+            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+            layoutParams.gravity = Gravity.RIGHT;
+            layoutParams.topMargin = 20;
+            layoutParams.rightMargin = 20;
+            viewGroup.addView(textView, layoutParams);
+            HandlerUtil.runOnUiThreadDelay(new Runnable() {
+                @Override
+                public void run() {
+                    if(adCount <= 0) {
+                        imageView.setImageDrawable(null);
+                        viewGroup.removeView(imageView);
+                        viewGroup.removeView(textView);
+                        OttLoginUtil.getInstance().reportAd();
+                    } else {
+                        adCount --;
+                        textView.setText(StringUtil.get(getApplicationContext(), R.string.ad_finish, adCount));
+                        HandlerUtil.runOnUiThreadDelay(this, 1000);
+                    }
+                }
+            }, 1000);
+        }
+
+        YSTVideoPlayer = new YSTVideoPlayer(MainActivity.this);
+        YSTVideoPlayer.setWebView(getWebView());
+        controlDelegate = new VideoControlDelegate(this, YSTVideoPlayer);
+        controlDelegate.setWebView(getWebView());
+        controlDelegate.subscribeData();
+        controlDelegate.getExitPlayingEvent().observe(this, aBoolean -> {
+            if (hadFloatVideo) {
+                YSTVideoPlayer.hideAllWidget();
+                changeVideo2Float();
+            } else {
+                destroyVideo();
+            }
+        });
+        YSTVideoPlayer.setOnPlayerPausedListener(controlDelegate);
+        getJsEvent().setVideoPlayer(YSTVideoPlayer);
+
+        ottLogin();
+
+        if (BuildConfig.isDebug) {
+            /*Logger.d("序列号(%s), STB(%s), MAC(%s)", getJsEvent().getSerialNum(),
+                    getJsEvent().getSTBId(),
+                    getJsEvent().getMac());
+            Logger.d("用户(%s), Token(%s)", getJsEvent().getUser(),
+                    getJsEvent().getToken());*/
+        }
+
+    }
+
+    private void observer() {
+        userViewModel = BaseViewModel.obtainViewModel(this, UserViewModel.class);
+        // 第一次使用app
+        if (SharedPre.getBoolean("FirstUse", true)) {
+            SharedPre.putBoolean("FirstUse", false);
+            userViewModel.newUse(getJsEvent().getMac());
+        }
+    }
+
+    private void ottLogin() {
+        loginMsg.observe(this, result -> {
+            Log.e("OTT", "认证结果:" + result);
+            new AlertDialog.Builder(this)
+                    .setTitle("ott认证失败")
+                    .setMessage("" + result)
+                    .setPositiveButton("确定", (dialog, which) -> {
+                        dialog.dismiss();
+                        finish();
+                    })
+                    .show();
+        });
+        new Thread(() -> OttLoginUtil.getInstance().init(MainActivity.this, MainActivity.this)).start();
+    }
+
+    @Override
+    public void handleIntent(Intent intent) {
+        super.handleIntent(intent);
+        newUrl = intent.getStringExtra(KEY_INTENT);
+        Logger.d("获取新地址:%s", newUrl);
+    }
+
+    @Override
+    protected String getIndexURL() {
+        if (TextUtils.isEmpty(newUrl)) {
+            Logger.d("请求地址:%s", url);
+            return url;
+        }
+        try {
+            String indexUrl = newUrl.replaceAll(";", "&");
+            Logger.d("转换后的新地址:%s", indexUrl);
+            return url + "?" + indexUrl;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return url;
+    }
+
+    /*@Override
+    protected String getJsInvokeName() {
+        return "AndroidToJS";
+    }*/
+
+    @Override
+    public HCWebViewClient.WebViewErrorListener getWebViewErrorListener() {
+        return this;
+    }
+
+    @Override
+    public void setAndroidToJSListener(AndroidToJS androidToJS) {
+        super.setAndroidToJSListener(androidToJS);
+        androidToJS.setPlayVideoListener(this);
+        androidToJS.setMainActivityManager(this);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        int keyCode = event.getKeyCode();
+        Logger.d("当前按下键值:%s", keyCode);
+        if (isFullScreenVideo && YSTVideoPlayer.shouldOverrideKeyEvent(keyCode)) {
+            return controlDelegate.onKeyDown(keyCode, event);
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public void playFloatVideo(String url, int x, int y, int width, int height, String uid, String sourceId, String title, String examineId, String examineType, int limitTime) {
+        if(url.isEmpty() || url == null){
+            Toast.makeText(this,"视频链接错误!",Toast.LENGTH_SHORT).show();
+            return;
+        }
+        if(!hasShowWebView){
+            hasOneFloatViewToShow = true;
+            lastVideoInfo = new VideoInfo(url,x,y,width,height,uid,sourceId,title,examineId,examineType,limitTime);
+            return;
+        }
+        isFullScreenVideo = false;
+        this.hadFloatVideo = true;
+        controlDelegate.setFullVideo(false);
+        userViewModel.getSingleBooleanEvent().setValue(true);
+        Logger.d("调用小窗口播放。地址(%s),坐标(%s, %s),宽高(%s, %s)", url, x, y, width, height);
+        runOnUiThread(() -> playVideo(url, title, uid, sourceId, x, y, width, height, examineId, examineType, limitTime));
+    }
+
+    @Override
+    public void playFullVideo(String url, String title, String uid, String sourceId, int limitTime, boolean hadFloatVideo, String examineId, String examineType, boolean isShowCompletedDialog) {
+        this.hadFloatVideo = hadFloatVideo;
+        runOnUiThread(() -> {
+//            getWebView().setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+            if (hadFloatVideo && TextUtils.isEmpty(url)) {
+                changeVideo2Full(limitTime, isShowCompletedDialog);
+            } else {
+                playVideo(url, title, uid, sourceId, limitTime, examineId, examineType, isShowCompletedDialog);
+            }
+        });
+    }
+
+    @Override
+    public void stopFloatVideo() {
+        runOnUiThread(this::destroyVideo);
+    }
+
+    /**
+     * 全屏播放逻辑
+     */
+    private void playVideo(String url, String title, String uid, String sourceId, int limitTime, String examineId, String examineType, boolean isShowCompletedDialog) {
+
+        isFullScreenVideo = true;
+        controlDelegate.setFullVideo(true);
+
+        if (YSTVideoPlayer.getParent() == null) {
+            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+            viewGroup.addView(YSTVideoPlayer);
+        }
+
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+        YSTVideoPlayer.setLayoutParams(params);
+        YSTVideoPlayer.setX(0);
+        YSTVideoPlayer.setY(0);
+
+        controlDelegate.setUid(uid);
+        controlDelegate.setSourceId(sourceId);
+
+
+        VideoData data = videoDataFactory(url,title,sourceId,limitTime,examineId,examineType);
+        String lastTimePosition = new LastPlayTimeStore(this).getTimeBySourceId(sourceId);
+        if(lastTimePosition != null){
+            if(!lastTimePosition.isEmpty()){
+                data.setLastTimePosition(Integer.parseInt(lastTimePosition));
+            }
+        }
+        YSTVideoPlayer.setShowCompletedDialog(isShowCompletedDialog);
+        YSTVideoPlayer.setData(data,this);
+    }
+
+    private VideoData videoDataFactory(String url, String title, String sourceId, int limitTime, String examineId, String examineType){
+        VideoData data = new VideoData();
+        data.setId(sourceId);
+        data.setUrl(url);
+        data.setTitle(title);
+        data.setLimitTime(limitTime * 1000);
+        data.setExamineId(examineId);
+        data.setExamineType(examineType);
+        return data;
+    }
+
+    /**
+     * 指定视频窗口位置和大小的播放逻辑
+     */
+    private void playVideo(String url, String title, String uid, String sourceId, int x, int y, int width, int height,
+                           String examineId, String examineType, int limitTime) {
+        initVideoParamsIfNotInit(x, y, width, height);
+
+        controlDelegate.setUid(uid);
+        controlDelegate.setSourceId(sourceId);
+
+        VideoData data = new VideoData();
+        data.setId(sourceId);
+        data.setUrl(url);
+        data.setTitle(title);
+        data.setLimitTime(limitTime * 1000);
+        data.setExamineId(examineId);
+        data.setExamineType(examineType);
+        YSTVideoPlayer.setData(data,this);
+        YSTVideoPlayer.hideAllWidget();
+    }
+
+    private void initVideoParamsIfNotInit(int x, int y, int width, int height) {
+        floatVideoWidth = width;
+        floatVideoHeight = height;
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        params.width = floatVideoWidth;
+        params.height = floatVideoHeight;
+        YSTVideoPlayer.setLayoutParams(params);
+
+        floatVideoX = x;
+        floatVideoY = y;
+        YSTVideoPlayer.setX(floatVideoX);
+        YSTVideoPlayer.setY(floatVideoY);
+
+        if (YSTVideoPlayer.getParent() == null) {
+            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+            viewGroup.addView(YSTVideoPlayer);
+        }
+    }
+
+    /**
+     * 小窗转全屏
+     */
+    private void changeVideo2Full(int limitTime, boolean isShowCompletedDialog) {
+        if (isFullScreenVideo) {
+            return;
+        }
+        if (YSTVideoPlayer != null && YSTVideoPlayer.getIcntvPlayer() != null) {
+            if (limitTime > 0 && YSTVideoPlayer.isNeedToPay()) {
+                AndroidToJS.evaluateJavascript(getWebView(), AndroidToJS.JS_EVENT_PAY);
+            } else {
+                isFullScreenVideo = true;
+                controlDelegate.setFullVideo(true);
+//            getWebView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                getWebView().clearFocus();
+                YSTVideoPlayer.requestFocus();
+                animChanged(floatVideoX, 0, floatVideoY, 0,
+                        floatVideoWidth, getResources().getDisplayMetrics().widthPixels,
+                        floatVideoHeight, getResources().getDisplayMetrics().heightPixels);
+                YSTVideoPlayer.setShowCompletedDialog(isShowCompletedDialog);
+                YSTVideoPlayer.pauseOrPlay(true);
+            }
+        }
+    }
+
+    /**
+     * 全屏转小窗
+     */
+    private void changeVideo2Float() {
+        if (!isFullScreenVideo) {
+            return;
+        }
+        if (YSTVideoPlayer != null) {
+            AndroidToJS.evaluateJavascript(getWebView(), AndroidToJS.JS_EVENT_PLAY_FINISH);
+            isFullScreenVideo = false;
+            controlDelegate.setFullVideo(false);
+            YSTVideoPlayer.pauseOrPlay(true);
+            YSTVideoPlayer.clearFocus();
+            getWebView().requestFocus();
+            animChanged(0, floatVideoX, 0, floatVideoY,
+                    getResources().getDisplayMetrics().widthPixels, floatVideoWidth,
+                    getResources().getDisplayMetrics().heightPixels, floatVideoHeight);
+        }
+    }
+
+    private void animChanged(int fromX, int toX, int fromY, int toY, int fromWidth, int toWidth, int fromHeight, int toHeight) {
+        ValueAnimator animator = new ValueAnimator();
+        animator.setValues(
+                PropertyValuesHolder.ofFloat("x", fromX, toX),
+                PropertyValuesHolder.ofFloat("y", fromY, toY),
+                PropertyValuesHolder.ofInt("width", fromWidth, toWidth),
+                PropertyValuesHolder.ofInt("height", fromHeight, toHeight)
+        );
+        animator.setDuration(200);
+        animator.setInterpolator(new LinearInterpolator());
+        animator.addUpdateListener(valueAnimator -> {
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+            params.width = (int) valueAnimator.getAnimatedValue("width");
+            params.height = (int) valueAnimator.getAnimatedValue("height");
+            YSTVideoPlayer.setLayoutParams(params);
+
+            YSTVideoPlayer.setX((Float) valueAnimator.getAnimatedValue("x"));
+            YSTVideoPlayer.setY((Float) valueAnimator.getAnimatedValue("y"));
+        });
+        animator.start();
+    }
+
+    @Override
+    protected void delayShowFloatView() {
+        //Log.d(TAG,"delayShowFloatView");
+        if(lastVideoInfo != null){
+            playFloatVideo(lastVideoInfo.url,lastVideoInfo.x,lastVideoInfo.y,lastVideoInfo.width,lastVideoInfo.height,
+                    lastVideoInfo.uid,lastVideoInfo.sourceId,lastVideoInfo.title,lastVideoInfo.examineId,lastVideoInfo.examineType,
+                    lastVideoInfo.limitTime);
+            hasOneFloatViewToShow = false;
+        }
+    }
+
+    private void destroyVideo() {
+        if (isFullScreenVideo) {
+            AndroidToJS.evaluateJavascript(getWebView(), AndroidToJS.JS_EVENT_PLAY_FINISH);
+        }
+        isFullScreenVideo = false;
+        controlDelegate.setFullVideo(false);
+//        getWebView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        if (YSTVideoPlayer != null && YSTVideoPlayer.getParent() != null) {
+
+            YSTVideoPlayer.onVideoDestroy();
+
+            ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
+            viewGroup.removeView(YSTVideoPlayer);
+        }
+    }
+
+    /*
+     * 视频窗口暂停对话框猜你喜欢视频播放
+     * */
+
+    public void favoritePlay(String sourceId,String title){
+        new LastPlayTimeStore(this).insert(title,sourceId);
+        String url = "http://112.35.32.145:8090/index.php?m=Home&c=Order&a=authorize&sourceId="
+                + sourceId + "&EpgServer=" + getUserEpgServer() + "&token=" + getUserToken();
+        new GetRequest().RequestAsync(url, new GetRequestListener() {
+            @Override
+            public void onResult(String msg) {
+                try{
+                    JSONObject jsonObject = new JSONObject(msg);
+                    if(jsonObject.getInt("code") == 0){
+                        String data = jsonObject.getString("data");
+                        JSONObject dataObject = new JSONObject(data);
+                        if(dataObject.getString("returncode").equals("0")){
+                            if(dataObject.has("urls")){
+                                JSONArray urls = dataObject.getJSONArray("urls");
+                                String playUrl = urls.getJSONObject(0).getString("playurl");
+                                playUrl = "http://111.20.105.60:6060/GZHC/32/HC_SXYD_Movie_1640?AuthInfo=fYRn6wHTB6eMAGUKu9tiy1%2BoDGkdNRH1eBdnpkXBr1uXi01TWCEl%2Fzmj166sZ1RueACMTnEjP0frBL2xVTz0ZJ3iOictBjY4f8JCCb0%2BAijeL2gMxcVwASPkY0a8jA6k&version=v1.0&virtualDomain=GZHC.vod_hpd.zte.com&stbid=0057030000010070181058B42DAE192D&terminalflag=1&userid=58B42DAE192D";
+                                VideoData data1 = videoDataFactory(playUrl,"测试","1618",-1,"10001","program");
+                                MainActivity.this.runOnUiThread(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        YSTVideoPlayer.switchVideo(data1);
+                                    }
+                                });
+                            }else{
+                                Log.i(TAG,"没有获取到播放链接");
+                            }
+                        }else{
+                            Log.i(TAG,"鉴权失败");
+                        }
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    /*
+    * 获取机顶盒信息
+    * */
+    private String getUserName(){
+        try{
+            Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
+            Cursor cursor = getContentResolver().query(queryUri,new String[]{"value"},"name='username'",null,null);
+            cursor.moveToFirst();
+            String userName = cursor.getString(cursor.getColumnIndexOrThrow("value"));
+            Log.d(TAG,"userName:" + userName);
+            return userName;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    private String getUserToken(){
+        try{
+            Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
+            Cursor cursor = getContentResolver().query(queryUri,new String[]{"value"},"name='user_token'",null,null);
+            cursor.moveToFirst();
+            String userToken = cursor.getString(cursor.getColumnIndexOrThrow("value"));
+            //userToken = "Se48ja9jiqjq-Stjhd4izfd";
+            Log.d(TAG,"userToken:" + userToken);
+            return userToken;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    private String getUserEpgServer(){
+        try{
+            Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
+            Cursor cursor = getContentResolver().query(queryUri,new String[]{"value"},"name='epg_server'",null,null);
+            cursor.moveToFirst();
+            String epgServer = cursor.getString(cursor.getColumnIndexOrThrow("value"));
+            //epgServer = "http://111.20.42.163:33200";
+            Log.d(TAG,"epgServer:" + epgServer);
+            return epgServer;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    ////////////////////////////////////OTT登陆/////////////////////////////////////
+
+
+    @Override
+    public void onOttLoginSuccess() {
+//        loginMsg.setValue("OTT登陆成功");
+    }
+
+    @Override
+    public void onOttLoginFail(String msg) {
+        loginMsg.setValue(msg);
+    }
+
+    @Override
+    public void onOttLoginError(Throwable throwable) {
+        loginMsg.setValue(throwable == null ? "发生未知异常" : throwable.getMessage());
+    }
+
+    ////////////////////////////////////网页加载异常/////////////////////////////////////
+
+    @Override
+    public void onReceiveError(WebView view, int errorCode, String description, String failingUrl) {
+        if (messageView == null) {
+            messageView = View.inflate(this, R.layout.layout_tip_view, null);
+        }
+        switch (description) {
+            case HCWebViewClient.NETWORK_ACCESS_DENIED:
+                ((TextView) messageView.findViewById(R.id.tv_message)).setText("没有网络权限");
+                break;
+            case HCWebViewClient.UNKNOWN_URL_SCHEME:
+                ((TextView) messageView.findViewById(R.id.tv_message)).setText(String.format("%s\n该地址无法访问,请联系客服", failingUrl));
+                break;
+            case HCWebViewClient.INTERNET_DISCONNECTED:
+                ((TextView) messageView.findViewById(R.id.tv_message)).setText("网络未链接,请重新加载");
+                break;
+            default:
+                ((TextView) messageView.findViewById(R.id.tv_message)).setText("未定义的错误,请重新加载或联系客服");
+                break;
+        }
+        view.loadUrl("about:blank");
+        ViewInjectFactory.getInstance().inject(this, messageView);
+    }
+
+
+    public void reloadWeb(View view) {
+        ViewInjectFactory.getInstance().revert(this);
+        getWebView().loadUrl(getIndexURL());
+    }
+
+    public void exitApp(View view) {
+        finish();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        destroyVideo();
+        boolean isForeground = BaseApp.isRunningForeground(this);
+        if (!isForeground) {
+            TrackUtil.userEvent(LocalStore.getInstance().isVip(), LocalStore.getInstance().getUserID(), false);
+            Handler handler = new Handler(getMainLooper());
+            handler.postDelayed(() -> {
+                TrackUtil.exitApp();
+                if (!isFinish) {
+                    BaseApp.exit();
+                }
+            }, 500);
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        YSTVideoPlayer.onVideoDestroy();
+    }
+
+    @Override
+    protected void onDestroy() {
+        ViewInjectFactory.getInstance().destroy(this);
+        super.onDestroy();
+    }
+
+    @Override
+    public void finishActivity() {
+        isFinish = true;
+        finish();
+    }
+}

+ 377 - 0
app/src/main/java/com/hc/webapp/yst/OttLoginUtil.java

@@ -0,0 +1,377 @@
+package com.hc.webapp.yst;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.hc.request.core.DownloadServer;
+import com.hc.webapp.BuildConfig;
+import com.jewel.lib.android.HandlerUtil;
+import com.jewel.lib.java.FileUtil;
+import com.orhanobut.logger.Logger;
+import com.yanzhenjie.nohttp.Headers;
+import com.yanzhenjie.nohttp.RequestMethod;
+import com.yanzhenjie.nohttp.download.DownloadListener;
+import com.yanzhenjie.nohttp.download.DownloadRequest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+
+import tv.icntv.adsdk.AdSDK;
+import tv.icntv.logsdk.logSDK;
+import tv.icntv.ottlogin.loginSDK;
+
+import tv.newtv.upgradesdk.upgradeSDK;
+
+/**
+ * Created by jewel on 2019/1/8.
+ */
+@SuppressWarnings("unused")
+public class OttLoginUtil {
+    private static OttLoginUtil instance;
+    private DownloadRequest downloadRequest;
+    private String channelCode ="2626061001";
+    private String appKey = "a9a403148bc93d0a06c08b82c7c59a6b";
+    private String appSecret = "699bf23437a0490b42a7562a6d436f2b";
+
+
+    public static OttLoginUtil getInstance() {
+        if (instance == null) {
+            instance = new OttLoginUtil();
+        }
+        return instance;
+    }
+
+    public void init(Context c, OnOttListener loginListener) {
+        Context context = c.getApplicationContext();
+        try {
+            loginSDK.getInstance().sdkInit(loginSDK.TYPE_COMMON,channelCode,appKey,appSecret, context);
+            //开始认证
+            String loginRet = loginSDK.getInstance().deviceLogin();
+
+            if (loginRet.equals("1")) {
+                initOttInfo(context, loginListener,false);
+            }
+            else {
+                initOttFail(loginRet, loginListener);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            HandlerUtil.runOnUiThread(() -> loginListener.onOttLoginError(e));
+        }
+    }
+
+    private void initOttInfo(Context context, OnOttListener loginListener,boolean accessError) {
+        // 认证成功,可获取认证信息
+        StringBuffer tf = new StringBuffer();// 获取设备 ID
+        loginSDK.getInstance().getDeviceID(tf);       //设备ID
+        String deviceID = tf.toString();
+        if(deviceID == null){
+            return;
+        }
+        if(deviceID.isEmpty()){
+            return;
+        }
+        LocalStore.getInstance().putDeviceId(deviceID);
+
+        loginSDK.getInstance().getTemplateID(tf);
+        String templateID = tf.toString();
+        LocalStore.getInstance().putTemplateId(templateID);
+
+        loginSDK.getInstance().getAppKey(tf);
+        String appKey = tf.toString();
+        LocalStore.getInstance().putPlatformId(appKey);
+
+
+        loginSDK.getInstance().getValueByKey("EXT_GET_LOGIN_MAC", tf);
+        String mac = tf.toString();
+        LocalStore.getInstance().putMac(mac);
+
+        if (BuildConfig.isDebug) {
+            Logger.e("deviceId=%s, appKey=%s, mac=%s", deviceID, appKey, mac);
+        }
+
+        loginSDK.getInstance().getToken(tf);
+        String token = tf.toString();
+        LocalStore.getInstance().putOttToken(token);
+
+        loginSDK.getInstance().getServerAddress("YST-EPG", tf);
+        String serverYST = tf.toString();
+        LocalStore.getInstance().putYST_EPG_Server(serverYST);
+
+        loginSDK.getInstance().getServerAddress("AD", tf);
+        String serverAD = tf.toString();
+        LocalStore.getInstance().putADServer(serverAD);
+
+        loginSDK.getInstance().getServerAddress("USER_LOG", tf);
+        String serverLog = tf.toString();
+        LocalStore.getInstance().putLogServer(serverLog);
+
+        loginSDK.getInstance().getServerAddress("DEVICE_UPDATE", tf);
+        String serverUpdate = tf.toString();
+        LocalStore.getInstance().putUpdateServer(serverUpdate);
+
+        loginSDK.getInstance().getServerAddress("SEARCH", tf);
+        String serverSearch = tf.toString();
+        LocalStore.getInstance().putSearchServer(serverSearch);
+
+        updateVersionOnUiThread(serverUpdate,getVersionCode(context)); // 认证后更新apk--福建移动禁止自升级
+        initLog(serverLog, templateID, deviceID, appKey, loginListener);
+        initAD(context, serverAD, deviceID, appKey);
+    }
+
+    private int getVersionCode(Context context){
+        try{
+            return context.getPackageManager().getPackageInfo(context.getPackageName(),0).versionCode;
+        }catch (Exception e){
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    private void initLog(String serverLog, String templateID, String deviceID, String platformID, OnOttListener loginListener) {
+        logSDK.getInstance().sdkInit(serverLog, "", deviceID, channelCode, appKey);
+        reportHomeLog();
+        HandlerUtil.runOnUiThread(loginListener::onOttLoginSuccess);
+    }
+
+    private void reportHomeLog() {
+        reportLog(88, String.format("0,%s", BuildConfig.VERSION_NAME));//上报进入 APK 日志
+        reportLog(0, "0");//进入首页
+    }
+
+    public void reportExitLog() {
+        reportLog(88, "1");//上报退出 APK 日志
+    }
+
+    /**
+     * 上传收藏/取消记录
+     *
+     * @param isCollected 是否收藏操作
+     * @param id          视频id
+     */
+    public void reportCollectedOrNotLog(boolean isCollected, String id) {
+        reportLog(5, String.format("%s, %s", isCollected ? 0 : 1, id));
+    }
+
+    /**
+     * 上传添加历史记录
+     *
+     * @param id 视频id
+     */
+    public void reportAddHistoryLog(String id) {
+        reportLog(15, String.format("0, %s", id));
+    }
+
+    /**
+     * 上传清空历史记录
+     */
+    public void reportClearAllHistoryLog() {
+        reportLog(15, "2, 0");
+    }
+
+    /**
+     * 上传搜索日志
+     *
+     * @param keyword 关键字
+     */
+    public void reportSearchLog(String keyword) {
+        reportLog(2, keyword);
+    }
+
+    /**
+     * 上传日志
+     * @param type 日志类型,详情请查看未来sdk提供的文档
+     * @param event 日志事件,详情请查看未来sdk提供的文档
+     */
+    public void reportLog(int type, String event) {
+        try {
+            logSDK.getInstance().logUpload(type, event);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void initAD(Context context, String serverAD, String deviceID, String platformID) {
+        boolean adInitResult = AdSDK.getInstance().init(serverAD, deviceID, appKey, channelCode,null,context);
+        if (adInitResult) {
+            StringBuffer sb = new StringBuffer();
+            AdSDK.getInstance().getAD("open,before,middle,after", null, null, null, null, null, sb);
+            Logger.e("广告来了:%s", sb.toString());
+            AdData adData = JSON.parseObject(sb.toString(), AdData.class);
+            if (adData.success()) {
+                AdData.AdspacesBean.OpenBean openAd = adData.getOpenAD();
+                if (openAd != null) {
+                    String adImage = adData.getOpenADImage();
+                    if (TextUtils.isEmpty(adImage)) {
+                        deleteAd();
+                    } else {
+                        saveAD(context, openAd, adImage);
+                    }
+                } else {
+                    deleteAd();
+                }
+            }
+        }
+    }
+
+    private void saveAD(Context context, AdData.AdspacesBean.OpenBean openAd, String adImage) {
+        LocalStore.getInstance().putOpenAdJson(JSON.toJSONString(openAd));
+        String folder = context.getCacheDir().getPath() + File.separator + "ad";
+        String filename = String.valueOf(adImage.hashCode());
+        String adImagePath = folder + File.separator + filename;
+        if (downloadRequest != null) {
+            downloadRequest.cancel();
+        }
+        downloadRequest = new DownloadRequest(adImage, RequestMethod.GET, folder, filename, true, true);
+        downloadRequest.setCancelSign(context);
+        DownloadServer.getInstance().download(0, downloadRequest, new DownloadListener() {
+            @Override
+            public void onDownloadError(int what, Exception exception) {
+                Logger.e(exception.getCause(), "下载异常");
+                downloadRequest = null;
+            }
+
+            @Override
+            public void onStart(int what, boolean isResume, long rangeSize, Headers responseHeaders, long allCount) {
+
+            }
+
+            @Override
+            public void onProgress(int what, int progress, long fileCount, long speed) {
+                Logger.e("下载广告图片进度:%s, 文件大小:%s", progress, fileCount);
+            }
+
+            @Override
+            public void onFinish(int what, String filePath) {
+                downloadRequest = null;
+                LocalStore.getInstance().putOpenAdImage(adImagePath);
+            }
+
+            @Override
+            public void onCancel(int what) {
+
+            }
+        });
+    }
+
+    public void reportAd() {
+        String openAdJson = LocalStore.getInstance().getOpenAdJson();
+        if (TextUtils.isEmpty(openAdJson)) {
+            return;
+        }
+        try {
+            AdData.AdspacesBean.OpenBean openBean = JSON.parseObject(openAdJson, AdData.AdspacesBean.OpenBean.class);
+            AdData.AdspacesBean.OpenBean.MaterialsBean materialsBean = AdData.getOpenMaterials(openBean);
+            if (materialsBean == null) {
+                return;
+            }
+            boolean reportAD = AdSDK.getInstance().report(openBean.getMid(), openBean.getAid(), materialsBean.getId(),
+                    "", "", "", "");
+            if (reportAD && BuildConfig.isDebug) {
+                Logger.e("上传广告日志:%s", openAdJson);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void deleteAd() {
+        LocalStore.getInstance().putOpenAdJson("");
+        String adImagePath = LocalStore.getInstance().getOpenAdImage();
+        if (TextUtils.isEmpty(adImagePath)) {
+            return;
+        }
+        FileUtil.deleteForce(adImagePath);
+        LocalStore.getInstance().putOpenAdImage("");
+    }
+
+    private void updateVersion(String updateSer,int versionCode) {
+        try {
+            StringBuffer strBuff = new StringBuffer();
+            int upgradeCode = upgradeSDK.getInstance().J_getAppUpgradeInfo(updateSer,appKey,channelCode,String.valueOf(versionCode),strBuff);
+            String returnData = strBuff.toString();
+            if(upgradeCode == 0){
+                try{
+                    JSONObject updateJson = JSONObject.parseObject(returnData);
+                    int upgradeVersionCode = Integer.parseInt(updateJson.getString("versionCode"));
+                    if(upgradeVersionCode > versionCode){
+                        String upgradeAddr = updateJson.getString("packageAddr");
+                        updateApk(upgradeAddr);
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+
+            }else{
+
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void updateApk(String upgradeAddr){
+
+    }
+
+    private void updateVersionOnUiThread(final String updateSer,final int versionCode) {
+        HandlerUtil.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                updateVersion(updateSer,versionCode);
+            }
+        });
+    }
+
+    private void initOttFail(String loginRet, OnOttListener loginListener) {
+        // 认证失败,上报错误日志,提示框展示
+        loginSDK.getInstance().logUpload(); // 失败后上报认证错误日志,用于远程问题定位 String msg = loginSDK.getInstance().loginStatusToMsg(loginRet);
+        String msg = loginSDK.getInstance().loginStatusToMsg(loginRet);
+
+        HandlerUtil.runOnUiThread(() -> loginListener.onOttLoginFail(msg));
+        //Log.d("loginSdk","认证返回" + loginRet + ": " + msg); // 可展示认证返回码及其对应描述信息
+    }
+
+    //获取ini文档路径
+    private String getOttIniFilePath(Context context) {
+        String fileFolder = context.getFilesDir().toString() + "/ini";
+        String filePath = fileFolder + "/DeviceInfo.ini";
+        try {
+            File folder = new File(fileFolder);
+            if (!folder.exists()) {
+                boolean mkDirs = folder.mkdirs();
+            }
+
+            File deviceFile = new File(filePath);
+            if (!deviceFile.exists()) {
+                //Toast.makeText(this,"文件未存在,创建文件",Toast.LENGTH_LONG).show();
+                boolean createNewFile = deviceFile.createNewFile();
+                InputStream is = context.getAssets().open("DeviceInfo.ini");
+                FileOutputStream fos = new FileOutputStream(deviceFile);
+                byte[] buffer = new byte[1024];
+                int byteCount;
+                while ((byteCount = is.read(buffer)) != -1) {//循环从输入流读取 buffer字节
+                    fos.write(buffer, 0, byteCount);//将读取的输入流写入到输出流
+                }
+                fos.flush();//刷新缓冲区
+                is.close();
+                fos.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return context.getFilesDir().toString();
+    }
+
+    public interface OnOttListener {
+        void onOttLoginSuccess();
+
+        void onOttLoginFail(String msg);
+
+        void onOttLoginError(Throwable throwable);
+    }
+
+}

+ 77 - 0
app/src/main/java/com/hc/webapp/yst/PayActivity.java

@@ -0,0 +1,77 @@
+package com.hc.webapp.yst;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import com.hc.webapp.web.AndroidToJS;
+import com.hc.webapp.web.BaseWebActivity;
+
+public class PayActivity extends BaseWebActivity implements AndroidToJS.ThirdActivityManager{
+
+    public static final String KEY_URL_PAY = "url_pay";
+    private String payUrl;
+
+    public static void start(Context context, String url) {
+        Intent intent = new Intent(context, PayActivity.class);
+        intent.putExtra(KEY_URL_PAY, url);
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        loadH5();
+    }
+
+    @Override
+    protected void delayShowFloatView() {
+
+    }
+
+    @Override
+    public boolean needInitTrackUtil() {
+        return false;
+    }
+
+    @Override
+    public boolean needInitViewModel() {
+        return false;
+    }
+
+    @Override
+    protected String getJsInvokeName() {
+        return "djbl2";
+    }
+
+    @Override
+    public void setAndroidToJSListener(AndroidToJS androidToJS) {
+        super.setAndroidToJSListener(androidToJS);
+        androidToJS.setThirdActivityManager(this);
+    }
+
+    @Override
+    public void handleIntent(Intent intent) {
+        super.handleIntent(intent);
+        payUrl = intent.getStringExtra(KEY_URL_PAY);
+        setShouldOverrideBackPressToJS(false);
+    }
+
+    @Override
+    protected String getIndexURL() {
+        if(TextUtils.isEmpty(payUrl)) {
+            Toast.makeText(this, "支付页地址不存在", Toast.LENGTH_LONG).show();
+            finish();
+            return null;
+        }
+        return payUrl;
+    }
+
+    @Override
+    public void finishActivity() {
+        finish();
+    }
+}

+ 116 - 0
app/src/main/java/com/hc/webapp/yst/TrackUtil.java

@@ -0,0 +1,116 @@
+package com.hc.webapp.yst;
+
+import android.content.Context;
+
+import com.hc.webapp.BuildConfig;
+import com.knowyou_jni.single.SDKUtil;
+import com.orhanobut.logger.Logger;
+
+import java.util.HashMap;
+
+/**
+ * 易视腾埋点统计工具
+ */
+public class TrackUtil {
+
+    private static final String APP_KEY = "8f7fb28cdaa948be6afb6d365c6f4280";
+
+    /**
+     * 初始化SDK
+     */
+    public static int init(Context context) {
+        Logger.d("埋点初始化");
+        return SDKUtil.getInstance().ky_initWithAppKey(context.getApplicationContext(), APP_KEY, BuildConfig.VERSION_NAME);
+    }
+
+    /**
+     * 退出App
+     */
+    public static void exitApp() {
+        int result = SDKUtil.getInstance().ky_quit();
+        Logger.d("App退出事件埋点结果:%s", result);
+        OttLoginUtil.getInstance().reportExitLog();
+    }
+
+    /**
+     * 用户事件
+     *
+     * @param isVip 是否vip
+     * @param uid   用户账号
+     */
+    public static void userEvent(boolean isVip, String uid, boolean login) {
+        HashMap<String, Object> eventMap = new HashMap<>();
+        eventMap.put(UserEvent.appName, "NewTV电竞部落");
+        eventMap.put(UserEvent.appType, UserEvent.app_type);
+        eventMap.put(UserEvent.order, isVip ? UserEvent.order_done : UserEvent.order_none);
+        eventMap.put(UserEvent.status, login ? UserEvent.status_login : UserEvent.status_logout);
+        eventMap.put(UserEvent.id, uid);
+        int result = SDKUtil.getInstance().ky_trackCustom(eventMap);
+        Logger.d("用户事件埋点结果【%s】:%s", eventMap.toString(), result);
+    }
+
+    /**
+     * 播放事件
+     *
+     * @param event    事件-播放开始/结束/暂停/继续
+     * @param id       节目ID
+     * @param name     节目名称
+     * @param progress 节目当前进度(0~1之间)
+     */
+    public static void playEvent(int event, String id, String name, String progress, int totalTime) {
+        HashMap<String, Object> eventMap = new HashMap<>();
+        eventMap.put(PlayEvent.appName, "NewTV电竞部落");
+        eventMap.put(PlayEvent.id, id);
+        eventMap.put(PlayEvent.name, name);
+        eventMap.put(PlayEvent.progress, progress);
+        switch (event) {
+            case PlayEvent.EVENT_START:
+                Logger.d("播放开始事件埋点:%s", eventMap.toString());
+                SDKUtil.getInstance().ky_playStart(eventMap);
+//                logSDK.getInstance().logUpload(4, String.format("%s,0,%s,0,0,%s", 0, id, totalTime));
+                break;
+            case PlayEvent.EVENT_END:
+                Logger.d("播放结束事件埋点:%s", eventMap.toString());
+                SDKUtil.getInstance().ky_playEnd(eventMap);
+//                logSDK.getInstance().logUpload(4, String.format("%s,0,%s,0,0,%s,%s,%s", 3, id, totalTime, progress, 0));
+                break;
+            case PlayEvent.EVENT_PAUSE:
+                Logger.d("播放暂停事件埋点:%s", eventMap.toString());
+                SDKUtil.getInstance().ky_playPause(eventMap);
+//                logSDK.getInstance().logUpload(4, String.format("%s,0,%s,0,0,%s,%s", 2, id, totalTime, progress));
+                break;
+            case PlayEvent.EVENT_RESUME:
+                Logger.d("播放恢复事件埋点:%s", eventMap.toString());
+                SDKUtil.getInstance().ky_playResume(eventMap);
+//                logSDK.getInstance().logUpload(4, String.format("%s,0,%s,0,0,%s,%s", 12, id, totalTime, progress));
+                break;
+        }
+    }
+
+    public static class PlayEvent {
+        public static final int EVENT_START = 1;
+        public static final int EVENT_END = 0;
+        public static final int EVENT_PAUSE = 2;
+        public static final int EVENT_RESUME = 3;
+
+        private static final String appName = "APP_NAME";
+        private static final String id = "SONG_ID";
+        private static final String name = "SONG_NAME";
+        private static final String progress = "SONG_PROGRESS";
+    }
+
+    private static class UserEvent {
+
+        private static final String appName = "APP_NAME";
+        private static final String appType = "APP_TYPE";
+        private static final String status = "USER_LOGIN";
+        private static final String id = "USER_ID";
+        private static final String order = "USER_ORDER";
+
+        private static final String status_login = "1";
+        private static final String status_logout = "0";
+        private static final String order_none = "未订购";
+        private static final String order_done = "已订购";
+        private static final String app_type = "电子竞技";
+    }
+}

+ 203 - 0
app/src/main/java/com/hc/webapp/yst/VideoData.java

@@ -0,0 +1,203 @@
+package com.hc.webapp.yst;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+import java.io.Serializable;
+
+@SuppressWarnings("unused")
+public class VideoData implements Serializable {
+
+    public static final String F_SOURCE = "1018";
+    /**
+     * 准备状态
+     */
+    public static final int STATUS_PREPARE = -1;
+    /**
+     * 测试中
+     */
+    public static final int STATUS_LOADING = 0;
+    /**
+     * 测试成功
+     */
+    public static final int STATUS_SUCCESS = 1;
+    /**
+     * 测试失败
+     */
+    public static final int STATUS_FAIL = 2;
+    /**
+     * 未定义错误
+     */
+    public static final int STATUS_UNKNOWN = 3;
+    /**
+     * 超时
+     */
+    public static final int STATUS_TIME_OUT = 4;
+
+    /**
+     * 视频ID
+     */
+    @JSONField(name = "source_id")
+    private String id;
+    /**
+     * 视频标题
+     */
+    @JSONField(name = "source_name")
+    private String title;
+    /**
+     * 视频地址
+     */
+    @JSONField(name = "url")
+    private String url;
+    /**
+     * 限制播放时间
+     */
+    private int limitTime;
+    /**
+     * 视频分类
+     */
+    private String category;
+    /**
+     * 测试状态
+     */
+    private int testStatus = STATUS_PREPARE;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+
+    public String getDate() {
+        return date;
+    }
+
+    public void setDate(String date) {
+        this.date = date;
+    }
+
+    public int getTestStatus() {
+        return testStatus;
+    }
+
+    public void setTestStatus(int testStatus) {
+        this.testStatus = testStatus;
+    }
+
+    public int getLimitTime() {
+        return limitTime;
+    }
+
+    public void setLimitTime(int limitTime) {
+        this.limitTime = limitTime;
+    }
+
+    public int getLastTimePosition(){return lastTimePosition;}
+
+    public void setLastTimePosition(int lastTimePosition){this.lastTimePosition=lastTimePosition;}
+
+    ////////////////////////////CNTV数据///////////////////////////////
+    public static final String PLAY_TYPE_NORMAL = "0"; // 点播类型
+    public static final String PLAY_TYPE_LIVE = "1"; // 直播类型
+
+    @JSONField(name = "examine_id")
+    private String examineId = "";   //未来审核ID
+    @JSONField(name = "type")
+    private String examineType = "";   //审核类型
+    private String appId = "5c822a55ae0db"; //未来电视视频播放ID
+    private String fSource = F_SOURCE;  //日志数据来源,新版本已经被遗弃
+    private String playType = PLAY_TYPE_NORMAL; // 0为点播,1为直播,新版本已经被遗弃
+
+    @JSONField(name = "examine_status")
+    private String examineStatus; // 审核状态
+    /**
+     * 视频日期
+     */
+    @JSONField(name = "examine_at")
+    private String date;
+
+    /*
+    * 上次播放时间记录
+    * */
+    private int lastTimePosition = 0;
+
+    /**
+     * 该素材是否免费
+     */
+    private String isFee = "";
+
+    public String getExamineId() {
+        return examineId;
+    }
+
+    public String getExamineType() {
+        return examineType;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public String getfSource() {
+        return fSource;
+    }
+
+    public void setExamineId(String examineId) {
+        this.examineId = examineId;
+    }
+
+    public void setExamineType(String examineType) {
+        this.examineType = examineType;
+    }
+
+    public String getPlayType() {
+        return playType;
+    }
+
+    public void setPlayType(String playType) {
+        this.playType = playType;
+    }
+
+    public String getExamineStatus() {
+        return examineStatus;
+    }
+
+    public void setExamineStatus(String examineStatus) {
+        this.examineStatus = examineStatus;
+    }
+
+    public String getIsFee() {
+        return isFee;
+    }
+
+    public void setIsFee(String isFee) {
+        this.isFee = isFee;
+    }
+
+    ////////////////////////////CNTV数据///////////////////////////////
+}

文件差異過大導致無法顯示
+ 1006 - 0
app/src/main/java/com/hc/webapp/yst/YSTVideoPlayer.java


二進制
app/src/main/res/drawable-hdpi/anniu_2.png


二進制
app/src/main/res/drawable-hdpi/btn_icon_right.png


二進制
app/src/main/res/drawable-hdpi/btn_icon_stop.png


二進制
app/src/main/res/drawable-hdpi/cancel_collect_focus.png


二進制
app/src/main/res/drawable-hdpi/cancel_collect_normal.png


二進制
app/src/main/res/drawable-hdpi/collect_normal.png


二進制
app/src/main/res/drawable-hdpi/collect_normal_focus.png


二進制
app/src/main/res/drawable-hdpi/continue_play_focus.png


二進制
app/src/main/res/drawable-hdpi/continue_play_normal.png


二進制
app/src/main/res/drawable-hdpi/exit_play_focus.png


二進制
app/src/main/res/drawable-hdpi/exit_play_normal.png


二進制
app/src/main/res/drawable-hdpi/img_bear_point.png


二進制
app/src/main/res/drawable-hdpi/loading.png


二進制
app/src/main/res/drawable-hdpi/more_video.png


二進制
app/src/main/res/drawable-hdpi/more_video_back.png


二進制
app/src/main/res/drawable-hdpi/pause_dialog_back.png


二進制
app/src/main/res/drawable-hdpi/replay_focus.png


二進制
app/src/main/res/drawable-hdpi/replay_normal.png


二進制
app/src/main/res/drawable-hdpi/seek.png


二進制
app/src/main/res/drawable-hdpi/seek_back.png


二進制
app/src/main/res/drawable-hdpi/start_pause.png


二進制
app/src/main/res/drawable-hdpi/start_pause_back.png


二進制
app/src/main/res/drawable-ldpi/anniu_2.png


二進制
app/src/main/res/drawable-ldpi/btn_icon_right.png


二進制
app/src/main/res/drawable-ldpi/btn_icon_stop.png


二進制
app/src/main/res/drawable-ldpi/cancel_collect_focus.png


二進制
app/src/main/res/drawable-ldpi/cancel_collect_normal.png


二進制
app/src/main/res/drawable-ldpi/collect_normal.png


二進制
app/src/main/res/drawable-ldpi/collect_normal_focus.png


二進制
app/src/main/res/drawable-ldpi/continue_play_focus.png


二進制
app/src/main/res/drawable-ldpi/continue_play_normal.png


+ 28 - 0
app/src/main/res/drawable-ldpi/dudu_video_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="#FFD8D8D8"/>
+            <size android:height="@dimen/progress_back_height"/>
+            <corners android:radius="@dimen/progress_back_radius"/>
+        </shape>
+    </item>
+    <item android:id="@android:id/secondaryProgress">
+        <clip>
+            <shape>
+                <solid android:color="@color/style_color"/>
+                <size android:height="@dimen/progress_back_height"/>
+                <corners android:radius="@dimen/progress_back_radius"/>
+            </shape>
+        </clip>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape>
+                <solid android:color="#FFFFF0C6"/>
+                <size android:height="@dimen/progress_back_height"/>
+                <corners android:radius="@dimen/progress_back_radius"/>
+            </shape>
+        </clip>
+    </item>
+</layer-list>

二進制
app/src/main/res/drawable-ldpi/exit_play_focus.png


二進制
app/src/main/res/drawable-ldpi/exit_play_normal.png


二進制
app/src/main/res/drawable-ldpi/img_bear_point.png


二進制
app/src/main/res/drawable-ldpi/loading.png


二進制
app/src/main/res/drawable-ldpi/more_video.png


二進制
app/src/main/res/drawable-ldpi/more_video_back.png


二進制
app/src/main/res/drawable-ldpi/pause_dialog_back.png


二進制
app/src/main/res/drawable-ldpi/replay_focus.png


二進制
app/src/main/res/drawable-ldpi/replay_normal.png


二進制
app/src/main/res/drawable-ldpi/seek.png


二進制
app/src/main/res/drawable-ldpi/seek_back.png


二進制
app/src/main/res/drawable-ldpi/start_pause.png


二進制
app/src/main/res/drawable-ldpi/start_pause_back.png


+ 0 - 0
app/src/main/res/drawable-mdpi-1280x720/anniu_2.png


部分文件因文件數量過多而無法顯示