lyn vor 6 Jahren
Commit
265c3a32ef
100 geänderte Dateien mit 3394 neuen und 0 gelöschten Zeilen
  1. 65 0
      .gitignore
  2. 29 0
      .idea/codeStyles/Project.xml
  3. 38 0
      .idea/misc.xml
  4. 13 0
      .idea/modules.xml
  5. 12 0
      .idea/runConfigurations.xml
  6. 6 0
      .idea/vcs.xml
  7. 2 0
      README.md
  8. 0 0
      adb
  9. 1 0
      app/.gitignore
  10. 68 0
      app/build.gradle
  11. 1 0
      app/debug/output.json
  12. 136 0
      app/proguard-rules.pro
  13. 1 0
      app/release/output.json
  14. 26 0
      app/src/androidTest/java/com/hc/webapp/ExampleInstrumentedTest.java
  15. 73 0
      app/src/main/AndroidManifest.xml
  16. 5 0
      app/src/main/java/com/hc/webapp/BackEventListener.java
  17. 115 0
      app/src/main/java/com/hc/webapp/BaseApp.java
  18. 464 0
      app/src/main/java/com/hc/webapp/MainActivity.java
  19. 6 0
      app/src/main/java/com/hc/webapp/NetworkConnectChangedListener.java
  20. 125 0
      app/src/main/java/com/hc/webapp/NetworkConnectChangedReceiver.java
  21. 26 0
      app/src/main/java/com/hc/webapp/model/VideoInfo.java
  22. 109 0
      app/src/main/java/com/hc/webapp/video/SysVideoPlayerActivity.java
  23. 225 0
      app/src/main/java/com/hc/webapp/video/VideoControlDelegate.java
  24. 24 0
      app/src/main/java/com/hc/webapp/video/VideoInfo.java
  25. 440 0
      app/src/main/java/com/hc/webapp/web/AndroidToJS.java
  26. 452 0
      app/src/main/java/com/hc/webapp/web/BaseWebActivity.java
  27. 5 0
      app/src/main/java/com/hc/webapp/web/GetRequestListener.java
  28. 39 0
      app/src/main/java/com/hc/webapp/web/GetRuquest.java
  29. 18 0
      app/src/main/java/com/hc/webapp/web/HCWebChromeClient.java
  30. 29 0
      app/src/main/java/com/hc/webapp/web/HCWebViewClient.java
  31. BIN
      app/src/main/res/drawable-hdpi/img_start_bg.jpg
  32. BIN
      app/src/main/res/drawable-ldpi/img_start_bg.jpg
  33. BIN
      app/src/main/res/drawable-mdpi-1280x720/img_start_bg.jpg
  34. BIN
      app/src/main/res/drawable-mdpi-1920x1080/img_start_bg.jpg
  35. BIN
      app/src/main/res/drawable-mdpi/img_start_bg.jpg
  36. 34 0
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  37. BIN
      app/src/main/res/drawable-xhdpi/img_start_bg.jpg
  38. BIN
      app/src/main/res/drawable-xxhdpi/img_start_bg.jpg
  39. BIN
      app/src/main/res/drawable/cancel_collect.png
  40. BIN
      app/src/main/res/drawable/collect_success.png
  41. BIN
      app/src/main/res/drawable/ic_launcher_app.png
  42. BIN
      app/src/main/res/drawable/notice.png
  43. 20 0
      app/src/main/res/layout/activity_main.xml
  44. 12 0
      app/src/main/res/layout/activity_player.xml
  45. 58 0
      app/src/main/res/layout/dialog_download.xml
  46. 189 0
      app/src/main/res/layout/layout_video_control.xml
  47. 5 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  48. 5 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  49. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  50. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_app.png
  51. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  52. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  53. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_app.png
  54. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  55. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  56. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_app.png
  57. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  58. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  59. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_app.png
  60. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  61. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  62. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_app.png
  63. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  64. 5 0
      app/src/main/res/values-hdpi/dimens.xml
  65. 5 0
      app/src/main/res/values-ldpi/dimens.xml
  66. 5 0
      app/src/main/res/values-mdpi-1280x720/dimens.xml
  67. 5 0
      app/src/main/res/values-mdpi-1920x1080/dimens.xml
  68. 5 0
      app/src/main/res/values-xhdpi/dimens.xml
  69. 5 0
      app/src/main/res/values-xxhdpi/dimens.xml
  70. 5 0
      app/src/main/res/values-xxxhdpi/dimens.xml
  71. 4 0
      app/src/main/res/values-xxxhdpi/strings.xml
  72. 14 0
      app/src/main/res/values/colors.xml
  73. 4 0
      app/src/main/res/values/dimens.xml
  74. 3 0
      app/src/main/res/values/strings.xml
  75. 15 0
      app/src/main/res/values/styles.xml
  76. 52 0
      app/src/test/java/com/hc/webapp/ExampleUnitTest.java
  77. 152 0
      build.gradle
  78. 1 0
      core/.gitignore
  79. BIN
      core/.idea/caches/build_file_checksums.ser
  80. 29 0
      core/.idea/codeStyles/Project.xml
  81. 19 0
      core/.idea/gradle.xml
  82. 11 0
      core/.idea/libraries/Gradle__android_arch_core_common_1_1_1_jar.xml
  83. 12 0
      core/.idea/libraries/Gradle__android_arch_core_runtime_1_1_1.xml
  84. 11 0
      core/.idea/libraries/Gradle__android_arch_lifecycle_common_1_1_1_jar.xml
  85. 12 0
      core/.idea/libraries/Gradle__android_arch_lifecycle_livedata_1_1_1.xml
  86. 12 0
      core/.idea/libraries/Gradle__android_arch_lifecycle_livedata_core_1_1_1.xml
  87. 12 0
      core/.idea/libraries/Gradle__android_arch_lifecycle_runtime_1_1_1.xml
  88. 12 0
      core/.idea/libraries/Gradle__android_arch_lifecycle_viewmodel_1_1_1.xml
  89. 10 0
      core/.idea/libraries/Gradle__com_android_support_animated_vector_drawable_28_0_0.xml
  90. 10 0
      core/.idea/libraries/Gradle__com_android_support_appcompat_v7_28_0_0.xml
  91. 10 0
      core/.idea/libraries/Gradle__com_android_support_asynclayoutinflater_28_0_0.xml
  92. 10 0
      core/.idea/libraries/Gradle__com_android_support_cardview_v7_28_0_0.xml
  93. 9 0
      core/.idea/libraries/Gradle__com_android_support_collections_28_0_0_jar.xml
  94. 10 0
      core/.idea/libraries/Gradle__com_android_support_constraint_constraint_layout_1_1_3.xml
  95. 9 0
      core/.idea/libraries/Gradle__com_android_support_constraint_constraint_layout_solver_1_1_3_jar.xml
  96. 10 0
      core/.idea/libraries/Gradle__com_android_support_coordinatorlayout_28_0_0.xml
  97. 10 0
      core/.idea/libraries/Gradle__com_android_support_cursoradapter_28_0_0.xml
  98. 10 0
      core/.idea/libraries/Gradle__com_android_support_customview_28_0_0.xml
  99. 10 0
      core/.idea/libraries/Gradle__com_android_support_design_28_0_0.xml
  100. 0 0
      core/.idea/libraries/Gradle__com_android_support_documentfile_28_0_0.xml

+ 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>

+ 13 - 0
.idea/modules.xml

@@ -0,0 +1,13 @@
+<?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$/core/core.iml" filepath="$PROJECT_DIR$/core/core.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.iml" filepath="$PROJECT_DIR$/sxyd_dudu.iml" />
+      <module fileurl="file://$PROJECT_DIR$/sysvideo/sysvideo.iml" filepath="$PROJECT_DIR$/sysvideo/sysvideo.iml" />
+    </modules>
+  </component>
+</project>

+ 12 - 0
.idea/runConfigurations.xml

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

+ 6 - 0
.idea/vcs.xml

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

+ 2 - 0
README.md

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

+ 0 - 0
adb


+ 1 - 0
app/.gitignore

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

+ 68 - 0
app/build.gradle

@@ -0,0 +1,68 @@
+apply plugin: 'com.android.application'
+
+android {
+    signingConfigs {
+        config {
+            keyAlias 'hc'
+            keyPassword 'hc123456'
+            storeFile file('C:/dev/project/android/hcGit/hcKeyStore.jks')
+            storePassword 'hc123456'
+        }
+    }
+    compileSdkVersion versions.compileSdk
+    defaultConfig {
+        applicationId "com.sxyd.dudutoy"
+        minSdkVersion versions.minSdk
+        targetSdkVersion versions.targetSdk
+        versionCode 1
+        versionName "v1.0.1"
+        ndk {
+            //APP的build.gradle设置支持的SO库架构
+            abiFilters 'armeabi', 'armeabi-v7a'
+        }
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        debug {
+            buildConfigField "Boolean", "isDebug", "true"
+//            zipAlignEnabled true
+//            shrinkResources true
+//            debuggable true
+            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('com.jewel.lib:JLib:1.0.9') {
+        exclude group: "com.android.support"
+    }
+    implementation 'com.squareup.okhttp3:okhttp:3.12.1'
+}

+ 1 - 0
app/debug/output.json

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

+ 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":1,"versionName":"v1.0.1","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());
+    }
+}

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

@@ -0,0 +1,73 @@
+<?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.SEND_SMS" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+    <!-- 未来电视所需权限 -->
+    <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" />
+
+    <uses-permission android:name="android.permission.GET_TASKS" />
+
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+
+    <uses-permission android:name="com.starcor.hunan.ReadUserinfo" />
+
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+
+    <uses-permission android:name="com.huawei.hmt.provider.stbconfig.permission.READ" />
+
+    <uses-permission android:name="com.huawei.hmt.provider.stbconfig.permission.WRITE" />
+
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application
+        android:name=".BaseApp"
+        android:allowBackup="true"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/ic_launcher_app"
+        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" />
+
+                <!-- 供第三方调用 -->
+                <action android:name="com.hc.fj.dj" />
+                <category android:name=" android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>

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

@@ -0,0 +1,5 @@
+package com.hc.webapp;
+
+public interface BackEventListener {
+    public void dialogShow(boolean hasShow);
+}

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

@@ -0,0 +1,115 @@
+package com.hc.webapp;
+
+import android.app.ActivityManager;
+import android.app.Application;
+import android.content.Context;
+
+import com.hc.lib.TAG;
+import com.jewel.lib.android.SharedPre;
+import com.liulishuo.filedownloader.FileDownloader;
+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 {
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        SharedPre.init(this, getPackageName());
+        initHttp();
+        initLogger();
+        initVideo();
+        FileDownloader.setupOnApplicationOnCreate(this);
+    }
+
+    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(false)
+                )
+                // 配置Cookie,默认保存数据库DBCookieStore,开发者可以自己实现CookieStore接口。
+                .cookieStore(
+                        // 如果不维护cookie,setEnable(false)禁用。
+                        new DBCookieStore(this).setEnable(false)
+                )
+                // 配置网络层,默认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() {
+
+//        GSYVideoManager.instance().setCurrentVideoHeight(Resources.getSystem().getDisplayMetrics().heightPixels);
+//        GSYVideoManager.instance().setCurrentVideoWidth(Resources.getSystem().getDisplayMetrics().widthPixels);
+
+//        PlayerFactory.setPlayManager(IjkPlayerManager.class);
+//        GSYVideoType.setRenderType(GSYVideoType.GLSURFACE);
+//        GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_FULL);
+//        GSYVideoType.enableMediaCodec();
+//        GSYVideoType.enableMediaCodecTexture();
+//
+//        VideoOptionModel videoOptionModel =
+//                new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop",  30);
+//        List<VideoOptionModel> list = new ArrayList<>();
+//        list.add(videoOptionModel);
+//        GSYVideoManager.instance().setOptionModelList(list);
+//        CacheFactory.setCacheManager(ExoPlayerCacheManager.class);
+    }
+
+    /**
+     * 判断应用是否处于前台
+     *
+     * @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;
+    }
+
+
+
+    public static void exit() {
+        android.os.Process.killProcess(android.os.Process.myPid());   //获取PID
+        System.exit(0);
+    }
+
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 464 - 0
app/src/main/java/com/hc/webapp/MainActivity.java


+ 6 - 0
app/src/main/java/com/hc/webapp/NetworkConnectChangedListener.java

@@ -0,0 +1,6 @@
+package com.hc.webapp;
+
+public interface NetworkConnectChangedListener {
+    public void onConnected();
+    public void onDisConnected();
+}

+ 125 - 0
app/src/main/java/com/hc/webapp/NetworkConnectChangedReceiver.java

@@ -0,0 +1,125 @@
+package com.hc.webapp;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.widget.Toast;
+
+public class NetworkConnectChangedReceiver extends BroadcastReceiver {
+    private NetworkConnectChangedListener networkConnectChangedListener;
+    private String TAG = "NetworkConnectChanged";
+    private Context context;
+
+    public NetworkConnectChangedReceiver(Context context,NetworkConnectChangedListener networkConnectChangedListener){
+        this.context = context;
+        this.networkConnectChangedListener = networkConnectChangedListener;
+    }
+
+    private void MyToast(final String msg){
+        Activity activity = (Activity)context;
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Toast.makeText(context,msg,Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    private String getConnectionType(int type) {
+        String connType = "";
+        if (type == ConnectivityManager.TYPE_MOBILE) {
+            connType = "3G网络数据";
+        } else if (type == ConnectivityManager.TYPE_WIFI) {
+            connType = "WIFI网络";
+        }
+
+        return connType;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        //MyToast("action:" + intent.getAction());
+        /*if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {// 监听wifi的打开与关闭,与wifi的连接无关
+            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
+            Log.e(TAG, "wifiState:" + wifiState);
+            MyToast("wifiState:" + wifiState);
+            switch (wifiState) {
+                case WifiManager.WIFI_STATE_DISABLED:
+                    Log.d(TAG,"WIFI_STATE_DISABLED");
+                    break;
+                case WifiManager.WIFI_STATE_DISABLING:
+                    Log.d(TAG,"WIFI_STATE_DISABLING");
+                    break;
+            }
+        }
+        // 监听wifi的连接状态即是否连上了一个有效无线路由
+        if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+            Parcelable parcelableExtra = intent
+                    .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+            if (null != parcelableExtra) {
+                // 获取联网状态的NetWorkInfo对象
+                NetworkInfo networkInfo = (NetworkInfo) parcelableExtra;
+                //获取的State对象则代表着连接成功与否等状态
+                NetworkInfo.State state = networkInfo.getState();
+                //判断网络是否已经连接
+                boolean isConnected = state == NetworkInfo.State.CONNECTED;
+                Log.e(TAG, "isConnected:" + isConnected);
+                MyToast("isConnected:" + isConnected);
+                if (isConnected) {
+                } else {
+
+                }
+            }
+        }
+        // 监听网络连接,包括wifi和移动数据的打开和关闭,以及连接上可用的连接都会接到监
+        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+            //获取联网状态的NetworkInfo对象
+            NetworkInfo info = intent
+                    .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+            if (info != null) {
+                //如果当前的网络连接成功并且网络连接可用
+                if (NetworkInfo.State.CONNECTED == info.getState() && info.isAvailable()) {
+                    if (info.getType() == ConnectivityManager.TYPE_WIFI
+                            || info.getType() == ConnectivityManager.TYPE_MOBILE) {
+                        Log.i(TAG, getConnectionType(info.getType()) + "连上");
+                        MyToast(getConnectionType(info.getType()) + "连上");
+                    }
+                } else {
+                    Log.i(TAG, getConnectionType(info.getType()) + "断开");
+                   MyToast(getConnectionType(info.getType()) + "断开");
+                }
+            }
+
+        }*/
+
+        boolean isConnected = isNetworkAvailable(context);
+        if(isConnected){
+            //MyToast("连上");
+            networkConnectChangedListener.onConnected();
+        }else {
+            //MyToast("断开");
+            networkConnectChangedListener.onDisConnected();
+        }
+    }
+
+    public boolean isNetworkAvailable(Context context) {
+        ConnectivityManager manager = (ConnectivityManager) context
+                .getApplicationContext().getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
+
+        if (manager == null) {
+            return false;
+        }
+
+        NetworkInfo networkinfo = manager.getActiveNetworkInfo();
+
+        if (networkinfo == null || !networkinfo.isAvailable()) {
+            return false;
+        }
+
+        return true;
+    }
+}

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

@@ -0,0 +1,26 @@
+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 boolean needMute;
+
+    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, boolean needMute){
+        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.needMute = needMute;
+    }
+}

+ 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();
+//    }
+//
+//}

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

@@ -0,0 +1,225 @@
+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.util.Log;
+import android.view.KeyEvent;
+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.BackEventListener;
+import com.hc.webapp.MainActivity;
+
+public class VideoControlDelegate implements VideoPauseDialog.OnPlayItemSelectedListener, OnPlayerPausedListener {
+
+    private FragmentActivity activity;
+    private IVideoPlayer videoPlayer;
+    private VideoPauseDialog pauseDialog;
+
+    private UserViewModel userViewModel;
+    private boolean hadCollectedVideo = false;
+
+    private String uid; // 用户
+    private String sourceId;  // 源ID
+
+    private SingleLiveEvent<String> eventSourceId;
+    private SingleLiveEvent<Boolean> exitPlayingEvent;
+    private SingleLiveEvent<Boolean> playNextEvent;
+    private BackEventListener backEventListener;
+    private MainActivity mainActivity;
+
+    private boolean isBackPause = false;
+    String TAG = "video_control";
+
+    public VideoControlDelegate(FragmentActivity activity, IVideoPlayer videoPlayer) {
+        this.videoPlayer = videoPlayer;
+        this.activity = activity;
+        mainActivity = (MainActivity)activity;
+        eventSourceId = new SingleLiveEvent<>();
+        exitPlayingEvent = new SingleLiveEvent<>();
+        playNextEvent = new SingleLiveEvent<>();
+        userViewModel = BaseViewModel.obtainViewModel(activity, UserViewModel.class);
+    }
+
+    public void setBackEventListener(BackEventListener backEventListener){
+        this.backEventListener = backEventListener;
+    }
+
+    public void setFullVideo(boolean fullVideo) {
+        videoPlayer.setFullVideo(fullVideo);
+        videoPlayer.setLoop(!fullVideo);
+    }
+
+    public void setLimitTime(long limitTime) {
+        videoPlayer.setLimitTime(limitTime);
+    }
+
+    public SingleLiveEvent<Boolean> getExitPlayingEvent() {
+        return exitPlayingEvent;
+    }
+
+    public SingleLiveEvent<Boolean> getPlayNextEvent() {
+        return playNextEvent;
+    }
+
+    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;
+                Log.d(TAG,"hadCollectedSource is onChanged,hadCollectedVideo is" + (hadCollectedVideo?"true":"false"));
+            }
+        });
+        // 观察是否收藏/取消收藏成功
+        userViewModel.isCollectedSuccess.observe(activity, new Observer<Boolean>() {
+            @Override
+            public void onChanged(@Nullable Boolean result) {
+                hadCollectedVideo = result == null ? false : result;
+                if (pauseDialog != null) {
+                    Log.d(TAG,"pauseDialog is not null");
+                    pauseDialog.setIsCollected(hadCollectedVideo);
+                }else{
+                    Log.d(TAG,"pauseDialog is null");
+                }
+            }
+        });
+
+        userViewModel.toastEvent.observe(activity, new Observer<String>() {
+            @Override
+            public void onChanged(@Nullable String s) {
+               /* if(s.contains("添加成功")){
+                    mainActivity.collectSuccess();
+                }else if(s.contains("删除成功")){
+                    mainActivity.cancelCollectSuccess();
+                }*/
+                //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);
+
+        }
+        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();
+        }
+    }
+
+    private void showPauseDialog(boolean hadCollectedVideo,boolean hasComplete) {
+        Log.d(TAG,"showPauseDialog ,hadCollectedVideo is" + (hadCollectedVideo?"true":"false"));
+        if (pauseDialog == null) {
+            pauseDialog = new VideoPauseDialog(videoPlayer.getContext(),hasComplete);
+            pauseDialog.setOnPlayItemSelectedListener(this);
+        }
+
+        if (!pauseDialog.isShowing()) {
+            pauseDialog.show();
+        }
+        pauseDialog.setHasComplete(hasComplete);
+        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() {
+        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() {
+        showPauseDialog(hadCollectedVideo,true);
+    }
+
+    @Override
+    public void videoToNext() {
+        playNextEvent.setValue(true);
+    }
+
+    @Override
+    public void videoExit() {
+        exitPlayingEvent.setValue(true);
+        onDestroy();
+    }
+
+}

+ 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;
+//    }
+//}

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

@@ -0,0 +1,440 @@
+package com.hc.webapp.web;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringDef;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+import android.widget.TextView;
+
+import com.hc.lib.DownloadUtils;
+import com.hc.lib.MacUtil;
+import com.hc.model.YNYD.YNYDContentProvider;
+import com.hc.model.YNYD.YNYDService;
+import com.hc.request.Config;
+import com.hc.request.core.DefaultCallback;
+import com.hc.webapp.BuildConfig;
+import com.jewel.lib.java.StringUtil;
+import com.orhanobut.logger.Logger;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.regex.Pattern;
+
+import static com.hc.lib.video.IVideoPlayer.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()";
+    private static final String JS_EVENT_AUTH_RESULT = "javascript:onAuthResult(%s, %s)";
+    public static final String JS_EVENT_PLAY_NEXT = "javascript:onPlayNextEvent()";
+
+    private static final String HAD_FLOAT_VIDEO = "1"; // 当前H5页面存在小窗视频
+    private static final String NEED_MUTE = "0";
+
+    String TAG ="AndroidToJS";
+
+//    private String testVideo = "http://hnh5pic.oss-cn-shenzhen.aliyuncs.com/3.mp4";
+//    private String testVideo = "http://163.com-www-letv.com/20180509/457_79ed60e3/index.m3u8";
+    private String testVideo = "http://192.168.2.112/000079/000079.m3u8";
+
+    /**
+     * JS调用类型
+     */
+    @StringDef({JS_EVENT_BACK, JS_EVENT_PLAY_FINISH, JS_EVENT_PLAY_NEXT})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface JsEvent {
+
+    }
+
+    private Context context;
+    private WebView webView;
+    private YNYDContentProvider contentProvider;
+    private YNYDService service;
+    private PlayVideoListener playVideoListener;
+    private long playTime = PLAY_TIME_NO_LIMIT;
+
+    public AndroidToJS(Context context, WebView webView) {
+        this.context = context;
+        this.webView = webView;
+        contentProvider = new YNYDContentProvider(context);
+        service = new YNYDService(context);
+    }
+
+    public void setPlayVideoListener(PlayVideoListener playVideoListener) {
+        this.playVideoListener = playVideoListener;
+    }
+
+    /**
+     * 全屏播放
+     *
+     * @param time               可播放时间。如果为{@link com.hc.lib.video.IVideoPlayer#PLAY_TIME_NO_LIMIT},代表无限制播放
+     * @param hadFloatVideo      当前H5页面是否有小窗
+     * @param isNextVideo        是否为下一个视频,1表示当前播放的为下一个视频,其他值为第一个视频
+     * @param showCompleteDialog 是否显示播放结束弹窗,1表示显示结束弹窗,其他值为不显示结束弹窗,显示结束弹窗时不会调用JS方法中的请求下一个视频方法
+     */
+    @JavascriptInterface
+    public void playFull(String url, String sourceId, String title, String time, String hadFloatVideo, String isNextVideo, String showCompleteDialog) {
+        Logger.d("调用全屏播放。源ID(%s),标题(%s),播放地址(%s)", sourceId, title, url);
+        if (playVideoListener != null) {
+
+            playTime = PLAY_TIME_NO_LIMIT;
+            if (isDigitsOnly(time)) {
+                playTime = Long.parseLong(time);
+            }
+            boolean hadFloat = TextUtils.equals(HAD_FLOAT_VIDEO, hadFloatVideo);
+            boolean isCurrentNextVideo = TextUtils.equals(HAD_FLOAT_VIDEO, isNextVideo);
+            boolean isShowCompleteDialog = TextUtils.equals(HAD_FLOAT_VIDEO, showCompleteDialog);
+            Logger.d("调用全屏播放。有小窗(%s),当前为非初始视频(%s),显示结束弹窗(%s)", hadFloat, isCurrentNextVideo, isShowCompleteDialog);
+            ((Activity) context).runOnUiThread(() -> playFull(url, sourceId, title, playTime, hadFloat, isCurrentNextVideo, isShowCompleteDialog, 0));
+        }
+    }
+
+    /**
+     * 全屏播放
+     *
+     * @param time               可播放时间。如果为{@link com.hc.lib.video.IVideoPlayer#PLAY_TIME_NO_LIMIT},代表无限制播放
+     * @param hadFloatVideo      当前H5页面是否有小窗
+     * @param isNextVideo        是否为下一个视频,1表示当前播放的为下一个视频,其他值为第一个视频
+     * @param showCompleteDialog 是否显示播放结束弹窗,1表示显示结束弹窗,其他值为不显示结束弹窗,显示结束弹窗时不会调用JS方法中的请求下一个视频方法
+     * @param seekTime        需要快进的时间
+     */
+    @JavascriptInterface
+    public void playFull(String url, String sourceId, String title, String time, String hadFloatVideo, String isNextVideo, String showCompleteDialog, int seekTime) {
+        Logger.d("调用全屏播放。源ID(%s),标题(%s),播放地址(%s)", sourceId, title, url);
+        if (playVideoListener != null) {
+
+            playTime = PLAY_TIME_NO_LIMIT;
+            if (isDigitsOnly(time)) {
+                playTime = Long.parseLong(time);
+            }
+            boolean hadFloat = TextUtils.equals(HAD_FLOAT_VIDEO, hadFloatVideo);
+            boolean isCurrentNextVideo = TextUtils.equals(HAD_FLOAT_VIDEO, isNextVideo);
+            boolean isShowCompleteDialog = TextUtils.equals(HAD_FLOAT_VIDEO, showCompleteDialog);
+            Logger.d("调用全屏播放。有小窗(%s),当前为非初始视频(%s),显示结束弹窗(%s),快进时间(%s)", hadFloat, isCurrentNextVideo, isShowCompleteDialog, seekTime);
+            ((Activity) context).runOnUiThread(() -> playFull(url, sourceId, title, playTime, hadFloat, isCurrentNextVideo, isShowCompleteDialog, seekTime));
+        }
+    }
+
+    private void playFull(String url, String sourceId, String title, long time, boolean hadFloat, boolean isNextVideo, boolean showCompleteDialog, int seekTime) {
+        if (isNextVideo) { // 播放下一条视频时,直接在当前全屏窗口开启新视频的播放
+            playVideoListener.playFullVideo(url, title, getUserName(), sourceId, time, hadFloat, showCompleteDialog, seekTime);
+        } else if (hadFloat) { // 有小窗时,直接切换成全屏
+            playVideoListener.playFullVideo(null, title, getUserName(), sourceId, time, true, showCompleteDialog, 0);
+        } else { // 开启新的全屏播放窗口
+            playVideoListener.playFullVideo(url, title, getUserName(), sourceId, time, false, showCompleteDialog, seekTime);
+        }
+    }
+
+    /**
+     * @param url      播放地址
+     * @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 needMute) {
+        Logger.d("调用小窗口播放。播放地址(%s), 源ID(%s),标题(%s)", url, sourceId, title);
+        Logger.d("调用小窗口播放。坐标(%s, %s),宽高(%s, %s)", x, y, width, height);
+        boolean isMute = TextUtils.equals(NEED_MUTE, needMute);
+        Logger.d("调用小窗口播放。需要静音:%s", isMute);
+        if (isDigitsOnly(x) && isDigitsOnly(y) && isDigitsOnly(width) && isDigitsOnly(height) && playVideoListener != null) {
+            ((Activity) context).runOnUiThread(() -> playFloat(url, sourceId, title,
+                    (int) Float.parseFloat(x),
+                    (int) Float.parseFloat(y),
+                    (int) Float.parseFloat(width),
+                    (int) Float.parseFloat(height), isMute));
+        }
+    }
+
+    private void playFloat(String url, String sourceId, String title, final int x, final int y, final int width, final int height, boolean needMute) {
+        playVideoListener.playFloatVideo(url,
+                x, y, width, height,
+                getUserName(), sourceId, title, needMute);
+    }
+
+    /**
+     * 关闭小窗播放
+     */
+    @JavascriptInterface
+    public void closeFloat() {
+        Logger.d("关闭小窗口播放。");
+        if (playVideoListener != null) {
+            playVideoListener.stopFloatVideo();
+        }
+    }
+
+    /**
+     * 获取EPG结果
+     */
+    @JavascriptInterface
+    public void getEPGAuthResult(String body) {
+        service.auth(body, new DefaultCallback<String>() {
+            @Override
+            public void onSuccess(int what, @NonNull String data) {
+                super.onSuccess(what, data);
+                evaluateJavascript(webView, StringUtil.get(JS_EVENT_AUTH_RESULT, data, Config.RESPONSE_SUCCESS));
+            }
+
+            @Override
+            public void onFail(int what, String msg) {
+                super.onFail(what, msg);
+                evaluateJavascript(webView, StringUtil.get(JS_EVENT_AUTH_RESULT, msg, Config.RESPONSE_ERROR));
+            }
+
+            @Override
+            public void onError(int what, Throwable e) {
+                super.onError(what, e);
+                evaluateJavascript(webView, StringUtil.get(JS_EVENT_AUTH_RESULT, e.getMessage(), Config.RESPONSE_ERROR));
+            }
+        });
+    }
+
+    @JavascriptInterface
+    public String getUserId() {
+        return getUserName();
+    }
+
+    @JavascriptInterface
+    public String getUser() {
+        return contentProvider.getUserName();
+    }
+
+    @JavascriptInterface
+    public String getEpgServer() {
+        return getUserEpgServer();
+    }
+
+    @JavascriptInterface
+    public String getPlatform() {
+        return contentProvider.getPlatform();
+    }
+
+    @JavascriptInterface
+    public String getToken() {
+        return getUserToken();
+    }
+
+    @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() {
+        return MacUtil.getMac(context);
+    }
+
+    @JavascriptInterface
+    public void pay() {
+    }
+
+    @JavascriptInterface
+    public void appExit() {
+        ((Activity) context).runOnUiThread(() -> ((Activity) context).finish());
+        System.exit(0);
+    }
+
+    @JavascriptInterface
+    public void update(String apkUrl) {
+        ((Activity) context).runOnUiThread(() -> download(apkUrl));
+    }
+
+    @JavascriptInterface
+    public void install(String apkPath) {
+        ((Activity) context).runOnUiThread(() -> installApk(apkPath));
+    }
+
+    @JavascriptInterface
+    public void uninstall() {
+        ((Activity) context).runOnUiThread(() -> {
+            Uri uri = Uri.fromParts("package", context.getPackageName(), null);
+            Intent intent = new Intent(Intent.ACTION_DELETE, uri);
+            context.startActivity(intent);
+        });
+    }
+
+    private void download(String apkUrl) {
+        Dialog dialog = new Dialog(context);
+        dialog.setCancelable(false);
+        dialog.setCanceledOnTouchOutside(false);
+        TextView progressText = new TextView(context);
+        progressText.setText("开始下载新版本");
+        progressText.setTextColor(context.getResources().getColor(android.R.color.black));
+        progressText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
+        dialog.setContentView(progressText);
+        dialog.setTitle("新版本更新");
+        DownloadUtils.download(apkUrl, context.getPackageName() + getVersionCode(), "apk", new DownloadUtils.DownloadProgressListener() {
+            @Override
+            public void onDownloadStart(String fileName) {
+                dialog.show();
+            }
+
+            @Override
+            public void onDownloadProgress(int progress) {
+                if (dialog != null && dialog.isShowing()) {
+                    progressText.setText(String.format("下载中...%s%s", progress, "%"));
+                }
+            }
+
+            @Override
+            public void onDownloadSuccessful(String filePath) {
+                if (dialog != null && dialog.isShowing()) {
+                    dialog.dismiss();
+                }
+                installApk(filePath);
+            }
+        });
+    }
+
+    private void installApk(String filePath) {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//4.0以上系统弹出安装成功打开界面
+        context.startActivity(intent);
+    }
+
+    /**
+     * 调用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();
+    }
+
+    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"));
+            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"));
+            Log.d(TAG,"epgServer:" + epgServer);
+            return epgServer;
+        }catch (Exception e){
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+
+    public interface PlayVideoListener {
+        /**
+         * 小窗播放视频
+         *
+         * @param url      视频地址
+         * @param x        小窗X坐标
+         * @param y        小窗Y坐标
+         * @param width    小窗宽度
+         * @param height   小窗高度
+         * @param needMute 是否静音
+         */
+        void playFloatVideo(String url, int x, int y, int width, int height, String uid, String sourceId, String title, boolean needMute);
+
+        /**
+         * 全屏播放
+         *
+         * @param url           视频地址
+         * @param title         视频标题
+         * @param uid           用户id
+         * @param sourceId      源ID
+         * @param playTime      可播放时间。如果为{@link com.hc.lib.video.IVideoPlayer#PLAY_TIME_NO_LIMIT},代表无限制播放
+         * @param hadFloatVideo 当前H5页面是否有小窗
+         * @param seekTime 全屏时需要快进的时间
+         */
+        void playFullVideo(String url, String title, String uid, String sourceId, long playTime, boolean hadFloatVideo, boolean showCompleteDialog, int seekTime);
+
+        /**
+         * 结束小窗播放
+         */
+        void stopFloatVideo();
+    }
+}

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

@@ -0,0 +1,452 @@
+package com.hc.webapp.web;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+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.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import com.hc.webapp.BuildConfig;
+import com.hc.webapp.NetworkConnectChangedListener;
+import com.hc.webapp.NetworkConnectChangedReceiver;
+import com.hc.webapp.R;
+
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+@SuppressWarnings("unused")
+public abstract class BaseWebActivity extends AppCompatActivity {
+
+    public static final int REQUEST_PLAY_FINISH = 0x100;
+
+    private WebView webView;
+    private ImageView noticeImage;
+    protected FrameLayout webViewContainer;
+    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;
+
+    /**
+     * 监听网络状态广播
+     */
+    private NetworkConnectChangedReceiver networkConnectChangedReceiver;
+
+    /**
+     * 获取启动页web地址
+     */
+    protected abstract String getIndexURL();
+
+    /**
+     * 获取JS调用对象名。
+     */
+    protected String getJsInvokeName() {
+        return JsInvokeName;
+    }
+
+    /**
+     * 设置是否监听返回按键
+     *
+     * @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 setPlayVideoListener(AndroidToJS androidToJS) {
+    }
+
+    public WebView getWebView() {
+        return webView;
+    }
+
+    public void handleIntent(Intent intent) {
+
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+    }
+
+    //检查网络是否可用,add by 许林2018/12/5
+    public boolean isNetworkAvailable(Context context) {
+        ConnectivityManager manager = (ConnectivityManager) context
+                .getApplicationContext().getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
+
+        if (manager == null) {
+            return false;
+        }
+
+        NetworkInfo networkinfo = manager.getActiveNetworkInfo();
+
+        if (networkinfo == null || !networkinfo.isAvailable()) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private void showNoNetImage(){
+        BaseWebActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                noticeImage.setVisibility(View.VISIBLE);
+            }
+        });
+        new Timer().schedule(new TimerTask() {
+            @Override
+            public void run() {
+                BaseWebActivity.this.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        noticeImage.setVisibility(View.INVISIBLE);
+                    }
+                });
+            }
+        },2000);
+    }
+
+    protected void showCancelCollectImage(){
+        BaseWebActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                noticeImage.setImageResource(R.drawable.cancel_collect);
+                noticeImage.setVisibility(View.VISIBLE);
+            }
+        });
+        new Timer().schedule(new TimerTask() {
+            @Override
+            public void run() {
+                BaseWebActivity.this.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        noticeImage.setVisibility(View.INVISIBLE);
+                    }
+                });
+            }
+        },2000);
+    }
+
+    protected void showCollectSuccessImage(){
+        BaseWebActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                RelativeLayout layout = new RelativeLayout(BaseWebActivity.this);
+                layout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
+                ImageView imageView = new ImageView(BaseWebActivity.this);
+                int imageWidth = getResources().getDimensionPixelSize(R.dimen.notice_width);
+                int imageHeight = getResources().getDimensionPixelSize(R.dimen.notice_height);
+                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(imageWidth,imageHeight);
+                layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+                layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
+                layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
+                int marginBottom = getResources().getDimensionPixelSize(R.dimen.notice_bottom_distance);
+                layoutParams.setMargins(0,0,0,marginBottom);
+                imageView.setLayoutParams(layoutParams);
+                layout.addView(imageView);
+                webViewContainer.addView(layout);
+            }
+        });
+        new Timer().schedule(new TimerTask() {
+            @Override
+            public void run() {
+                BaseWebActivity.this.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        noticeImage.setVisibility(View.INVISIBLE);
+                    }
+                });
+            }
+        },2000);
+    }
+
+    private void CheckNetWorkLoop(CheckNetWorkListener listener){
+        if(!isNetworkAvailable(this)){
+            showNoNetImage();
+            new Timer().schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    CheckNetWorkLoop(listener);
+                }
+            },5000);
+            listener.checkResult(false);
+        }else{
+            listener.checkResult(true);
+        }
+    }
+
+    interface CheckNetWorkListener{
+        public void checkResult(boolean result);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_main);
+        //hasOneFloatViewToShow = true;
+        if (getIntent() != null) {
+            handleIntent(getIntent());
+        }
+
+
+        webViewContainer = findViewById(R.id.webview_container);
+        noticeImage = findViewById(R.id.notice_image);
+
+
+        webView = new WebView(this);
+        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));
+        webViewContainer.addView(webView,new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
+        initWebSetting(webView);
+        webView.setVisibility(View.INVISIBLE);
+
+        if(!isNetworkAvailable(this)){
+            setShouldOverrideBackPressToJS(false);
+            CheckNetWorkLoop(new CheckNetWorkListener() {
+                @Override
+                public void checkResult(boolean result) {
+                    if(result){
+                        setShouldOverrideBackPressToJS(true);
+                        BaseWebActivity.this.runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                webView.loadUrl(getIndexURL());
+                            }
+                        });
+                    }else{
+                        setShouldOverrideBackPressToJS(false);
+                    }
+                }
+            });
+        }else{
+            setShouldOverrideBackPressToJS(true);
+            webView.loadUrl(getIndexURL());
+        }
+    }
+
+    /*
+     * add by xulin 20181221 start
+     * */
+    private void registerReceiver(){
+        registerNetworkConnectChangedReceiver(new NetworkConnectChangedListener() {
+            @Override
+            public void onConnected() {
+                hideNoNet();
+            }
+
+            @Override
+            public void onDisConnected() {
+                showNoNet();
+            }
+        });
+    }
+
+    protected void showNoNet(){
+        BaseWebActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                destroyWebView();
+                destroyVideoView();
+                noticeImage.setVisibility(View.VISIBLE);
+            }
+        });
+    };
+
+    private void destroyWebView(){
+        if (webView != null) {
+            webView.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    protected abstract void destroyVideoView();
+
+    protected void hideNoNet(){
+        BaseWebActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                reloadWebView();
+                noticeImage.setVisibility(View.VISIBLE);
+            }
+        });
+    };
+
+    private void reloadWebView(){
+        webView.setVisibility(View.VISIBLE);
+        webView.loadUrl(getIndexURL());
+    }
+
+    private void registerNetworkConnectChangedReceiver(NetworkConnectChangedListener networkConnectChangedListener){
+        new Timer().schedule(new TimerTask() {
+            @Override
+            public void run() {
+                IntentFilter filter = new IntentFilter();
+                filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+                filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+                filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+                networkConnectChangedReceiver = new NetworkConnectChangedReceiver(BaseWebActivity.this,networkConnectChangedListener);
+                registerReceiver(networkConnectChangedReceiver, filter);
+            }
+        },2000);
+    }
+
+    /*
+     * add by xulin 20181221 end
+     * */
+
+    @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_NO_CACHE);
+        // 设置JS交互
+        webSettings.setJavaScriptEnabled(true);
+
+        AndroidToJS onJsEvent = new AndroidToJS(this, webView);
+        setPlayVideoListener(onJsEvent);
+        webView.addJavascriptInterface(onJsEvent, getJsInvokeName());
+        // 设置WebClient
+        webView.setWebViewClient(new HCWebViewClient());
+        webView.setWebChromeClient(new HCWebChromeClient());
+
+        webView.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url)
+            {
+                hasShowWebView = true;
+                webView.setVisibility(View.VISIBLE);
+                if(hasOneFloatViewToShow){
+                    delayShowFloatView();
+                }
+            }
+
+            @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 abstract void delayShowFloatView();
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (webView != null) {
+            webView.onResume();
+        }
+    }
+
+//    @Override
+//    public boolean onKeyDown(int keyCode, KeyEvent event) {
+//        if (shouldOverrideBackKeyEvent) {
+//            if (keyCode == KeyEvent.KEYCODE_BACK && webView != null && webView.canGoBack()) {
+//                webView.goBack();
+//                return true;
+//            }
+//        }
+//        return super.onKeyDown(keyCode, event);
+//    }
+
+    @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;
+        }
+        unregisterReceiver(networkConnectChangedReceiver);
+        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;
+//            }
+//        }
+//    }
+}

+ 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;
+    }
+}

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

@@ -0,0 +1,29 @@
+package com.hc.webapp.web;
+
+import android.webkit.WebViewClient;
+
+/**
+ * 自定义WebViewClient控制器
+ */
+public class HCWebViewClient extends WebViewClient {
+
+//    @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) {
+//        return super.onRenderProcessGone(view, detail);
+//    }
+}

BIN
app/src/main/res/drawable-hdpi/img_start_bg.jpg


BIN
app/src/main/res/drawable-ldpi/img_start_bg.jpg


BIN
app/src/main/res/drawable-mdpi-1280x720/img_start_bg.jpg


BIN
app/src/main/res/drawable-mdpi-1920x1080/img_start_bg.jpg


BIN
app/src/main/res/drawable-mdpi/img_start_bg.jpg


Datei-Diff unterdrückt, da er zu groß ist
+ 34 - 0
app/src/main/res/drawable-v24/ic_launcher_foreground.xml


BIN
app/src/main/res/drawable-xhdpi/img_start_bg.jpg


BIN
app/src/main/res/drawable-xxhdpi/img_start_bg.jpg


BIN
app/src/main/res/drawable/cancel_collect.png


BIN
app/src/main/res/drawable/collect_success.png


BIN
app/src/main/res/drawable/ic_launcher_app.png


BIN
app/src/main/res/drawable/notice.png


+ 20 - 0
app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/webview_container">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <ImageView
+            android:layout_width="@dimen/notice_width"
+            android:layout_height="@dimen/notice_height"
+            android:id="@+id/notice_image"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="@dimen/notice_bottom_distance"
+            android:src="@drawable/notice"
+            android:visibility="invisible"/>
+    </RelativeLayout>
+</FrameLayout>

+ 12 - 0
app/src/main/res/layout/activity_player.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"-->
+    <!--android:layout_width="match_parent"-->
+    <!--android:layout_height="match_parent">-->
+
+    <com.hc.lib.video.HCVideoPlayer xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/player"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+
+<!--</FrameLayout>-->

+ 58 - 0
app/src/main/res/layout/dialog_download.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@android:color/white">
+
+    <TextView
+        android:id="@+id/tv_progress_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:padding="20dp"
+        android:textColor="@android:color/black"
+        android:textSize="30sp"
+        tools:text="标题" />
+
+    <View
+        android:id="@+id/centerLine"
+        android:layout_width="1dp"
+        android:layout_height="1dp"
+        android:layout_centerInParent="true" />
+
+    <ProgressBar
+        android:id="@+id/progress"
+        style="?android:progressBarStyleHorizontal"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_below="@+id/tv_progress_title"
+        android:layout_margin="20dp"
+        android:max="100"
+        android:progress="0"
+        android:progressDrawable="@android:drawable/progress_horizontal" />
+
+    <Button
+        android:id="@+id/btn_cancel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/progress"
+        android:layout_toLeftOf="@+id/centerLine"
+        android:layout_toStartOf="@+id/centerLine"
+        android:text="取消"
+        android:textColor="@android:color/white"
+        android:textSize="28sp"
+        android:visibility="gone"/>
+
+    <Button
+        android:id="@+id/btn_submit"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/progress"
+        android:layout_toEndOf="@+id/centerLine"
+        android:layout_toRightOf="@+id/centerLine"
+        android:text="安装"
+        android:textColor="@android:color/holo_red_light"
+        android:textSize="28sp"
+        android:visibility="gone"/>
+</RelativeLayout>

+ 189 - 0
app/src/main/res/layout/layout_video_control.xml

@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:ignore="SpUsage,ContentDescription">
+
+    <!--视频容器-->
+    <FrameLayout
+        android:id="@+id/video_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@android:color/background_dark" />
+
+    <!--顶部栏-->
+    <RelativeLayout
+        android:id="@+id/top_bar"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/player_top_bar_height"
+        android:background="@drawable/tv_player_title_back"
+        android:visibility="invisible">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_title_margin_left"
+            android:layout_marginStart="@dimen/player_top_title_margin_left"
+            android:textColor="@color/font_white"
+            android:textSize="@dimen/player_top_title_text_size"
+            android:textStyle="bold" />
+
+        <ImageView
+            android:id="@+id/imageView"
+            android:layout_width="@dimen/player_top_image_size"
+            android:layout_height="@dimen/player_top_image_size"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_image1_margin_left"
+            android:layout_marginStart="@dimen/player_top_image1_margin_left"
+            android:src="@drawable/icon_tips_ok" />
+
+        <TextView
+            android:id="@+id/textView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_text1_margin_left"
+            android:layout_marginStart="@dimen/player_top_text1_margin_left"
+            android:text="@string/enter_control_tip"
+            android:textColor="@color/font_white_normal"
+            android:textSize="@dimen/player_top_text1_size" />
+
+        <ImageView
+            android:layout_width="@dimen/player_top_image_size"
+            android:layout_height="@dimen/player_top_image_size"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_image2_margin_left"
+            android:layout_marginStart="@dimen/player_top_image2_margin_left"
+            android:src="@drawable/icon_tips_l" />
+
+        <ImageView
+            android:layout_width="@dimen/player_top_image_size"
+            android:layout_height="@dimen/player_top_image_size"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_image3_margin_left"
+            android:layout_marginStart="@dimen/player_top_image3_margin_left"
+            android:src="@drawable/icon_tips_r" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_text2_margin_left"
+            android:layout_marginStart="@dimen/player_top_text2_margin_left"
+            android:text="@string/lr_control_tip"
+            android:textColor="@color/font_white_normal"
+            android:textSize="@dimen/player_top_text2_size" />
+
+        <LinearLayout
+            android:id="@+id/more_videos"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_centerVertical="true"
+            android:layout_marginLeft="@dimen/player_top_menu_margin_left"
+            android:layout_marginStart="@dimen/player_top_menu_margin_left"
+            android:orientation="horizontal">
+
+            <ImageView
+                android:layout_width="@dimen/player_top_image_size"
+                android:layout_height="@dimen/player_top_image_size"
+                android:layout_gravity="center_vertical"
+                android:src="@drawable/icon_tips_d" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginLeft="@dimen/player_top_menu_text_margin_left"
+                android:layout_marginStart="@dimen/player_top_menu_text_margin_left"
+                android:text="@string/menu"
+                android:textColor="@color/font_white_normal"
+                android:textSize="@dimen/player_top_text2_size" />
+        </LinearLayout>
+    </RelativeLayout>
+
+    <!--加载模块-->
+    <FrameLayout
+        android:id="@+id/loading"
+        android:layout_width="@dimen/player_loading_width"
+        android:layout_height="@dimen/player_loading_height"
+        android:layout_gravity="center"
+        android:background="@drawable/loading_back"
+        android:visibility="visible">
+
+        <ImageView
+            android:id="@+id/loading_animation"
+            android:layout_width="@dimen/player_loading_image_width"
+            android:layout_height="@dimen/player_loading_image_height"
+            android:layout_gravity="center" />
+    </FrameLayout>
+
+    <!--底部栏-->
+    <RelativeLayout
+        android:id="@+id/bottom_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom"
+        android:background="#BF000000"
+        android:visibility="invisible">
+
+        <TextView
+            android:id="@+id/pay_notice"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/player_bottom_notice_text_margin_left"
+            android:layout_marginStart="@dimen/player_bottom_notice_text_margin_left"
+            android:text="@string/free_see_tip"
+            android:textColor="@color/font_white"
+            android:textSize="@dimen/player_bottom_notice_text_size" />
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/player_bottom_height"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true">
+
+            <ImageView
+                android:id="@+id/play_pause"
+                android:layout_width="@dimen/player_bottom_play_pause_btn_size"
+                android:layout_height="@dimen/player_bottom_play_pause_btn_size"
+                android:layout_centerVertical="true"
+                android:layout_marginLeft="@dimen/player_bottom_play_pause_btn_margin_left"
+                android:layout_marginStart="@dimen/player_bottom_play_pause_btn_margin_left"
+                android:src="@drawable/icon_pause" />
+
+            <SeekBar
+                android:id="@+id/seek_bar"
+                android:layout_width="@dimen/player_bottom_seek_bar_width"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:layout_marginLeft="@dimen/player_bottom_seek_bar_margin_left"
+                android:layout_marginStart="@dimen/player_bottom_seek_bar_margin_left"
+                android:focusable="true"
+                android:gravity="center"
+                android:max="100"
+                android:maxHeight="@dimen/player_bottom_seek_bar_height"
+                android:minHeight="@dimen/player_bottom_seek_bar_height"
+                android:paddingBottom="@dimen/player_bottom_seek_bar_padding"
+                android:paddingLeft="@dimen/player_bottom_seek_bar_padding_horizontal"
+                android:paddingRight="@dimen/player_bottom_seek_bar_padding_horizontal"
+                android:paddingTop="@dimen/player_bottom_seek_bar_padding"
+                android:progressDrawable="@drawable/tv_seek_progress"  />
+
+            <TextView
+                android:id="@+id/time_current"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:layout_marginLeft="@dimen/player_bottom_current_time_margin_left"
+                android:layout_marginStart="@dimen/player_bottom_current_time_margin_left"
+                android:text="@string/playing_time"
+                android:textColor="@color/font_white"
+                android:textSize="@dimen/player_bottom_text_size" />
+        </RelativeLayout>
+
+    </RelativeLayout>
+</FrameLayout>

+ 5 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

+ 5 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_app.png


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_app.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_app.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_app.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_app.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png


+ 5 - 0
app/src/main/res/values-hdpi/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">50.0dp</dimen>
+    <dimen name="notice_width">320.0dp</dimen>
+    <dimen name="notice_height">100.0dp</dimen>
+</resources>

+ 5 - 0
app/src/main/res/values-ldpi/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">100.0dp</dimen>
+    <dimen name="notice_width">640.0dp</dimen>
+    <dimen name="notice_height">200.0dp</dimen>
+</resources>

+ 5 - 0
app/src/main/res/values-mdpi-1280x720/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">50.0dp</dimen>
+    <dimen name="notice_width">320.0dp</dimen>
+    <dimen name="notice_height">100.0dp</dimen>
+</resources>

+ 5 - 0
app/src/main/res/values-mdpi-1920x1080/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">75.0dp</dimen>
+    <dimen name="notice_width">480.0dp</dimen>
+    <dimen name="notice_height">150.0dp</dimen>
+</resources>

+ 5 - 0
app/src/main/res/values-xhdpi/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">37.5dp</dimen>
+    <dimen name="notice_width">240dp</dimen>
+    <dimen name="notice_height">75dp</dimen>
+</resources>

+ 5 - 0
app/src/main/res/values-xxhdpi/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">25.0dp</dimen>
+    <dimen name="notice_width">160.0dp</dimen>
+    <dimen name="notice_height">50.0dp</dimen>
+</resources>

+ 5 - 0
app/src/main/res/values-xxxhdpi/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <dimen name="notice_bottom_distance">18.75dp</dimen>
+    <dimen name="notice_width">120.0dp</dimen>
+    <dimen name="notice_height">37.5dp</dimen>
+</resources>

+ 4 - 0
app/src/main/res/values-xxxhdpi/strings.xml

@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">嘟嘟玩具</string>
+    <string name="loading_text">精彩即将呈现\n…</string>
+</resources>

+ 14 - 0
app/src/main/res/values/colors.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+
+    <color name="font_white">#eaebec</color>
+    <color name="font_white_normal">#bdc1c5</color>
+    <color name="font_white_secondary">#7f868e</color>
+    <color name="billboard_focus">#fcfa2b</color>
+    <color name="transparent">#00ffffff</color>
+    <color name="billboard_item_selected">#ff31d0ff</color>
+    <color name="un_focus">#1B466A</color>
+</resources>

+ 4 - 0
app/src/main/res/values/dimens.xml

@@ -0,0 +1,4 @@
+<resources>
+
+
+</resources>

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

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

+ 15 - 0
app/src/main/res/values/styles.xml

@@ -0,0 +1,15 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+
+        <item name="android:windowBackground">@drawable/img_start_bg</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
+</resources>

+ 52 - 0
app/src/test/java/com/hc/webapp/ExampleUnitTest.java

@@ -0,0 +1,52 @@
+package com.hc.webapp;
+
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Random;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+
+    @Test
+    public void random() {
+        for (int i = 0; i < 100; i++) {
+            System.out.println(new Random().nextInt(2));
+        }
+    }
+
+    @Test
+    public void test() {
+        String url = "http://27.31.208.36:33200/EPG/";
+        try {
+            URL u = new URL(url);
+            System.out.println(u.getAuthority());
+            System.out.println(u.getProtocol());
+        } catch (MalformedURLException e) {
+            String value[] = url.split("/");
+            for (int i = 0; i < value.length; i++) {
+                System.out.println(value[i]);
+            }
+        }
+    }
+
+    @Test
+    public void append() {
+        System.out.println( autoGenericCode("123", 8));
+    }
+
+    private String autoGenericCode(String code, int length) {
+        return "ps_haochuan" + String.format("%0" + length + "d", Integer.parseInt(code));
+    }
+}

+ 152 - 0
build.gradle

@@ -0,0 +1,152 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    // lib版本号
+    ext.versions = [
+            'minSdk'            : 17,
+            'targetSdk'         : 27,
+            'compileSdk'        : 27,
+            'Java'              : JavaVersion.VERSION_1_8,
+            'supportLibrary'    : '27.1.1',
+            'butterknife'       : '8.8.1',
+            'retrofit'          : '2.4.0',
+            'SmartRefreshLayout': '1.0.4-alpha-9',
+            'leakcanary'        : '1.5.1',
+            'objectbox'         : '1.0.1',
+            'lifecycle'         : '1.1.0',
+            'gsyVideoPlayer'    : '6.0.1'
+    ]
+
+    // 引用的lib
+    ext.lib = [
+            /**  常备底层库*/
+            support                      : [
+                    v4          : "com.android.support:support-v4:${versions.supportLibrary}",
+                    v7          : "com.android.support:appcompat-v7:${versions.supportLibrary}",
+                    design      : "com.android.support:design:${versions.supportLibrary}",
+                    recyclerview: "com.android.support:recyclerview-v7:${versions.supportLibrary}",
+                    cardview    : "com.android.support:cardview-v7:${versions.supportLibrary}",
+                    multidex    : 'com.android.support:multidex:1.0.2',
+                    percent     : "com.android.support:percent:${versions.supportLibrary}",
+                    constraint  : 'com.android.support.constraint:constraint-layout:1.1.0-beta6',
+                    guava       : 'com.google.guava:guava:22.0-android',
+            ],
+            test                         : [
+                    junit   : 'junit:junit:4.12',
+                    runner  : 'com.android.support.test:runner:1.0.2',
+                    espresso: 'com.android.support.test.espresso:espresso-core:3.0.2',
+            ],
+            // 谷歌开发架构组件
+            lifecycle                    : [
+                    runtime   : "android.arch.lifecycle:runtime:${versions.lifecycle}",
+                    extensions: "android.arch.lifecycle:extensions:${versions.lifecycle}",
+                    compiler  : "android.arch.lifecycle:compiler:${versions.lifecycle}",
+            ],
+            // 注解框架
+            butterknife                  : [
+                    core    : "com.jakewharton:butterknife:${versions.butterknife}",
+                    compiler: "com.jakewharton:butterknife-compiler:${versions.butterknife}",
+            ],
+
+            retrofit2                    : [
+                    core   : "com.squareup.retrofit2:retrofit:${versions.retrofit}",
+                    rxjava2: "com.squareup.retrofit2:adapter-rxjava2:${versions.retrofit}",
+                    gson   : "com.squareup.retrofit2:converter-gson:${versions.retrofit}",
+
+                    logger : 'com.squareup.okhttp3:logging-interceptor:3.9.1'
+            ],
+
+            rxjava2                      : 'io.reactivex.rxjava2:rxjava:2.1.16',
+            rxAndroid                    : 'io.reactivex.rxjava2:rxandroid:2.0.2',
+
+            baseRecyclerViewAdapterHelper: 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30',  // recyclerView适配器
+            // Image loader
+            glide                        : [
+                    'core'    : 'com.github.bumptech.glide:glide:4.6.1',
+                    'compiler': 'com.github.bumptech.glide:compiler:4.6.1'
+            ],
+            log                          : 'com.orhanobut:logger:2.2.0',  // 日志打印
+            greendao                     : 'org.greenrobot:greendao:3.2.2', // 数据库
+
+            jewel                        : [
+                    'inject': 'com.jewel.util:ViewInject:1.0.1',
+            ],
+
+            // 内存泄漏分析
+            leakcanary                   : [
+                    'debug'  : "com.squareup.leakcanary:leakcanary-android:${versions.leakcanary}",
+                    'release': "com.squareup.leakcanary:leakcanary-android-no-op:${versions.leakcanary}",
+            ],
+            http                         : 'com.yanzhenjie.nohttp:nohttp:1.1.9',
+            json                         : 'com.alibaba:fastjson:1.2.9',
+            gson                         : 'com.google.code.gson:gson:2.8.0',
+
+            lombok                       : 'org.projectlombok:lombok:1.16.20', // 实体注解工具, @http : https://projectlombok.org/setup/android
+            /**  常备UI库*/
+            //刷新容器
+            SmartRefreshLayout           : [
+                    'core'  : "com.scwang.smartrefresh:SmartRefreshLayout:${versions.SmartRefreshLayout}",
+                    'header': "com.scwang.smartrefresh:SmartRefreshHeader:${versions.SmartRefreshLayout}",
+            ],
+            fragmentation                : [
+                    'core'     : 'me.yokeyword:fragmentation:1.3.3',
+                    'swipeback': 'me.yokeyword:fragmentation-swipeback:1.3.3'
+            ],
+            utilcode                     : 'com.blankj:utilcode:1.13.6',  // 常用工具类 @Git地址:https://github.com/Blankj/AndroidUtilCode
+
+            lottie                       : 'com.airbnb.android:lottie:2.5.4', // json动画 @Git:https://github.com/airbnb/lottie-android
+            /** 以下为根据项目需求引入的非通用库 */
+            // 视频播放器:https://github.com/CarGuo/GSYVideoPlayer
+            video                        : [
+                    // 完整版
+                    GSYVideoPlayer :"com.shuyu:GSYVideoPlayer:${versions.gsyVideoPlayer}",
+                    // 可选配置版
+//                    player: "com.shuyu:gsyVideoPlayer-java:${versions.gsyVideoPlayer}",
+//                    //是否需要ExoPlayer模式
+//                    exo2  : "com.shuyu:GSYVideoPlayer-exo2:${versions.gsyVideoPlayer}",
+//                    //根据你的需求
+//                    armv5 : "com.shuyu:gsyVideoPlayer-armv5:${versions.gsyVideoPlayer}",
+//                    armv7a: "com.shuyu:gsyVideoPlayer-armv7a:${versions.gsyVideoPlayer}",
+//                    arm64 : "com.shuyu:gsyVideoPlayer-arm64:${versions.gsyVideoPlayer}",
+//                    x64   : "com.shuyu:gsyVideoPlayer-x64:${versions.gsyVideoPlayer}",
+//                    x86   : "com.shuyu:gsyVideoPlayer-x86:${versions.gsyVideoPlayer}",
+            ],
+            materialDialogs              : 'com.afollestad.material-dialogs:core:0.9.6.0',  // material 风格的对话框,@Git地址:https://github.com/afollestad/material-dialogs
+
+            crash                        : [
+                    'crashreport_upgrade': "com.tencent.bugly:crashreport_upgrade:latest.release", // bugly app update and crash report lib
+                    'nativecrashreport'  : "com.tencent.bugly:nativecrashreport:latest.release", // bugly Native Crash report lib
+            ],
+    ]
+
+    repositories {
+        jcenter()
+        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
+        mavenCentral()
+        google()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.1.4'
+//        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+        maven { url "https://jitpack.io" }
+        maven { url 'https://maven.google.com' }
+        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
+        maven { url 'http://maven.aliyun.com/nexus/content/repositories/releases/' }
+        flatDir {
+            dirs 'libs'
+        }
+        google()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 1 - 0
core/.gitignore

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

BIN
core/.idea/caches/build_file_checksums.ser


+ 29 - 0
core/.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>

+ 19 - 0
core/.idea/gradle.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$/.." />
+            <option value="$PROJECT_DIR$/../app" />
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/../exoplayer" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 11 - 0
core/.idea/libraries/Gradle__android_arch_core_common_1_1_1_jar.xml

@@ -0,0 +1,11 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.core:common:1.1.1@jar">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.1.1/e55b70d1f5620db124b3e85a7f4bdc7bd48d9f95/common-1.1.1.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.1.1/ae9b923fc99c1fc5a7a9b6cedc6df8b2b8529c54/common-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 12 - 0
core/.idea/libraries/Gradle__android_arch_core_runtime_1_1_1.xml

@@ -0,0 +1,12 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.core:runtime-1.1.1">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/runtime-1.1.1.aar/a2f5de99793d04ac8f9a0a3706909606/jars/classes.jar!/" />
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/runtime-1.1.1.aar/a2f5de99793d04ac8f9a0a3706909606/res" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.core/runtime/1.1.1/25df553df10af32bede9dd768a2d15299543d84/runtime-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 11 - 0
core/.idea/libraries/Gradle__android_arch_lifecycle_common_1_1_1_jar.xml

@@ -0,0 +1,11 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.lifecycle:common:1.1.1@jar">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.1.1/207a6efae6a3555e326de41f76bdadd9a239cbce/common-1.1.1.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.1.1/bcdaa509a856d1430e736b102f899aa9870a8f83/common-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 12 - 0
core/.idea/libraries/Gradle__android_arch_lifecycle_livedata_1_1_1.xml

@@ -0,0 +1,12 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.lifecycle:livedata-1.1.1">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/livedata-1.1.1.aar/615508c980bf94080e39d1cb88e8e1cf/jars/classes.jar!/" />
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/livedata-1.1.1.aar/615508c980bf94080e39d1cb88e8e1cf/res" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/livedata/1.1.1/bf27acaa4953c98cd519756ed7b7caacf94407d4/livedata-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 12 - 0
core/.idea/libraries/Gradle__android_arch_lifecycle_livedata_core_1_1_1.xml

@@ -0,0 +1,12 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.lifecycle:livedata-core-1.1.1">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/livedata-core-1.1.1.aar/ddc7fe6266259ad3b31633fe9b12ea30/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/livedata-core-1.1.1.aar/ddc7fe6266259ad3b31633fe9b12ea30/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/livedata-core/1.1.1/c38818e006ea7a408c05e3090364332d46494ef/livedata-core-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 12 - 0
core/.idea/libraries/Gradle__android_arch_lifecycle_runtime_1_1_1.xml

@@ -0,0 +1,12 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.lifecycle:runtime-1.1.1">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/runtime-1.1.1.aar/f43b1bb7465e3ed1509efde1d13866f9/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/runtime-1.1.1.aar/f43b1bb7465e3ed1509efde1d13866f9/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/runtime/1.1.1/8e4214221b3797b863dc9998d16abb4af043e784/runtime-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 12 - 0
core/.idea/libraries/Gradle__android_arch_lifecycle_viewmodel_1_1_1.xml

@@ -0,0 +1,12 @@
+<component name="libraryTable">
+  <library name="Gradle: android.arch.lifecycle:viewmodel-1.1.1">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/viewmodel-1.1.1.aar/9259c17829d73a7c8347316ad5f442d6/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/viewmodel-1.1.1.aar/9259c17829d73a7c8347316ad5f442d6/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/viewmodel/1.1.1/d1cc8e805317f171be63c68341f499acda7e42d6/viewmodel-1.1.1-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_animated_vector_drawable_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:animated-vector-drawable-28.0.0">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-28.0.0.aar/547824d2495ae92cf76997f4edf68693/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-28.0.0.aar/547824d2495ae92cf76997f4edf68693/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_appcompat_v7_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:appcompat-v7-28.0.0">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/appcompat-v7-28.0.0.aar/ffc9ba6acfcc8bb2becf8675e92b1511/jars/classes.jar!/" />
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/appcompat-v7-28.0.0.aar/ffc9ba6acfcc8bb2becf8675e92b1511/res" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_asynclayoutinflater_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:asynclayoutinflater-28.0.0">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/asynclayoutinflater-28.0.0.aar/767b3a44618e4f2ea82a3969a034304e/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/asynclayoutinflater-28.0.0.aar/767b3a44618e4f2ea82a3969a034304e/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_cardview_v7_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:cardview-v7-28.0.0">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/cardview-v7-28.0.0.aar/e4ee8e898ed030072df56c90a6bd7afb/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/cardview-v7-28.0.0.aar/e4ee8e898ed030072df56c90a6bd7afb/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
core/.idea/libraries/Gradle__com_android_support_collections_28_0_0_jar.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:collections:28.0.0@jar">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.android.support/collections/28.0.0/c1bcdade4d3cc2836130424a3f3e4182c666a745/collections-28.0.0.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_constraint_constraint_layout_1_1_3.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support.constraint:constraint-layout-1.1.3">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/bdbecada5185586f958c200ff0908959/jars/classes.jar!/" />
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/bdbecada5185586f958c200ff0908959/res" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
core/.idea/libraries/Gradle__com_android_support_constraint_constraint_layout_solver_1_1_3_jar.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.3@jar">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.android.support.constraint/constraint-layout-solver/1.1.3/bde0667d7414c16ed62d3cfe993cff7f9d732373/constraint-layout-solver-1.1.3.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_coordinatorlayout_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:coordinatorlayout-28.0.0">
+    <CLASSES>
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/coordinatorlayout-28.0.0.aar/718f7a13da26c9577eb69d6431cc4e0f/jars/classes.jar!/" />
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/coordinatorlayout-28.0.0.aar/718f7a13da26c9577eb69d6431cc4e0f/res" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_cursoradapter_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:cursoradapter-28.0.0">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/cursoradapter-28.0.0.aar/7bf3b1300c4cc6aaf9e02e5c2598c560/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/cursoradapter-28.0.0.aar/7bf3b1300c4cc6aaf9e02e5c2598c560/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_customview_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:customview-28.0.0">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/customview-28.0.0.aar/917e0559ee9987b9691868d7a26cb9f1/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/customview-28.0.0.aar/917e0559ee9987b9691868d7a26cb9f1/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 10 - 0
core/.idea/libraries/Gradle__com_android_support_design_28_0_0.xml

@@ -0,0 +1,10 @@
+<component name="libraryTable">
+  <library name="Gradle: com.android.support:design-28.0.0">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/design-28.0.0.aar/8ffd132fe0314514460a3f7d6ef70bd8/res" />
+      <root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/design-28.0.0.aar/8ffd132fe0314514460a3f7d6ef70bd8/jars/classes.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 0 - 0
core/.idea/libraries/Gradle__com_android_support_documentfile_28_0_0.xml


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.