lyn 6 éve
commit
377de90bed
100 módosított fájl, 3001 hozzáadás és 0 törlés
  1. 9 0
      .gitignore
  2. 19 0
      .idea/gradle.xml
  3. 33 0
      .idea/misc.xml
  4. 10 0
      .idea/modules.xml
  5. 12 0
      .idea/runConfigurations.xml
  6. 6 0
      .idea/vcs.xml
  7. 1 0
      TvSDK_Lib_Project/.gitignore
  8. 26 0
      TvSDK_Lib_Project/build.gradle
  9. BIN
      TvSDK_Lib_Project/libs/odin.jar
  10. BIN
      TvSDK_Lib_Project/libs/tv_pay_static.jar
  11. 17 0
      TvSDK_Lib_Project/proguard-rules.pro
  12. 16 0
      TvSDK_Lib_Project/src/main/AndroidManifest.xml
  13. BIN
      TvSDK_Lib_Project/src/main/res/drawable-hdpi/ic_launcher.png
  14. BIN
      TvSDK_Lib_Project/src/main/res/raw/odin_plugin_ability_1x0x3.apk
  15. BIN
      TvSDK_Lib_Project/src/main/res/raw/odin_plugin_tv_1x0x0.apk
  16. 11 0
      TvSDK_Lib_Project/src/main/res/values-v11/styles.xml
  17. 12 0
      TvSDK_Lib_Project/src/main/res/values-v14/styles.xml
  18. 5 0
      TvSDK_Lib_Project/src/main/res/values/strings.xml
  19. 20 0
      TvSDK_Lib_Project/src/main/res/values/styles.xml
  20. 1 0
      app/.gitignore
  21. 54 0
      app/build.gradle
  22. 86 0
      app/proguard-rules.pro
  23. BIN
      app/release/dudutoy.apk
  24. 1 0
      app/release/output.json
  25. 26 0
      app/src/androidTest/java/com/haochuan/dudutoy/ExampleInstrumentedTest.java
  26. 79 0
      app/src/main/AndroidManifest.xml
  27. 25 0
      app/src/main/java/com/haochuan/dudutoy/BasicFactory.java
  28. 312 0
      app/src/main/java/com/haochuan/dudutoy/CrashHandler.java
  29. 493 0
      app/src/main/java/com/haochuan/dudutoy/DuduPlayer.java
  30. 66 0
      app/src/main/java/com/haochuan/dudutoy/ErrorDataViewModel.java
  31. 9 0
      app/src/main/java/com/haochuan/dudutoy/ErrorFactory.java
  32. 23 0
      app/src/main/java/com/haochuan/dudutoy/ErrorService.java
  33. 152 0
      app/src/main/java/com/haochuan/dudutoy/HuaweiPay.java
  34. 29 0
      app/src/main/java/com/haochuan/dudutoy/LocalStore.java
  35. 596 0
      app/src/main/java/com/haochuan/dudutoy/MainActivity.java
  36. 99 0
      app/src/main/java/com/haochuan/dudutoy/PayActivity.java
  37. 8 0
      app/src/main/java/com/haochuan/dudutoy/StringUtils.java
  38. 14 0
      app/src/main/java/com/haochuan/dudutoy/StyleData.java
  39. 43 0
      app/src/main/java/com/haochuan/dudutoy/TestUnsubscribe.java
  40. 25 0
      app/src/main/java/com/haochuan/dudutoy/ToyApplication.java
  41. 29 0
      app/src/main/java/com/haochuan/dudutoy/UrlManager.java
  42. 336 0
      app/src/main/java/com/haochuan/dudutoy/VideoEndDialog.java
  43. 298 0
      app/src/main/java/com/haochuan/dudutoy/VideoPlayerActivity.java
  44. BIN
      app/src/main/res/drawable-hdpi/btn_icon_add_default.png
  45. BIN
      app/src/main/res/drawable-hdpi/btn_icon_add_selected.png
  46. BIN
      app/src/main/res/drawable-hdpi/btn_icon_continue.png
  47. BIN
      app/src/main/res/drawable-hdpi/btn_icon_out.png
  48. BIN
      app/src/main/res/drawable-hdpi/btn_icon_right.png
  49. BIN
      app/src/main/res/drawable-hdpi/btn_icon_stop.png
  50. BIN
      app/src/main/res/drawable-hdpi/loading_1.png
  51. BIN
      app/src/main/res/drawable-hdpi/loading_2.png
  52. BIN
      app/src/main/res/drawable-hdpi/logo1.png
  53. BIN
      app/src/main/res/drawable-hdpi/logo2.png
  54. BIN
      app/src/main/res/drawable-hdpi/logo_icon_down.png
  55. BIN
      app/src/main/res/drawable-hdpi/logo_icon_left.png
  56. BIN
      app/src/main/res/drawable-hdpi/logo_icon_ok.png
  57. BIN
      app/src/main/res/drawable-hdpi/logo_icon_right.png
  58. BIN
      app/src/main/res/drawable-ldpi/btn_icon_add_default.png
  59. BIN
      app/src/main/res/drawable-ldpi/btn_icon_add_selected.png
  60. BIN
      app/src/main/res/drawable-ldpi/btn_icon_continue.png
  61. BIN
      app/src/main/res/drawable-ldpi/btn_icon_out.png
  62. BIN
      app/src/main/res/drawable-ldpi/btn_icon_right.png
  63. BIN
      app/src/main/res/drawable-ldpi/btn_icon_stop.png
  64. BIN
      app/src/main/res/drawable-ldpi/loading_1.png
  65. BIN
      app/src/main/res/drawable-ldpi/loading_2.png
  66. BIN
      app/src/main/res/drawable-ldpi/logo1.png
  67. BIN
      app/src/main/res/drawable-ldpi/logo2.png
  68. BIN
      app/src/main/res/drawable-ldpi/logo_icon_down.png
  69. BIN
      app/src/main/res/drawable-ldpi/logo_icon_left.png
  70. BIN
      app/src/main/res/drawable-ldpi/logo_icon_ok.png
  71. BIN
      app/src/main/res/drawable-ldpi/logo_icon_right.png
  72. BIN
      app/src/main/res/drawable-mdpi/btn_icon_add_default.png
  73. BIN
      app/src/main/res/drawable-mdpi/btn_icon_add_selected.png
  74. BIN
      app/src/main/res/drawable-mdpi/btn_icon_continue.png
  75. BIN
      app/src/main/res/drawable-mdpi/btn_icon_out.png
  76. BIN
      app/src/main/res/drawable-mdpi/btn_icon_right.png
  77. BIN
      app/src/main/res/drawable-mdpi/btn_icon_stop.png
  78. BIN
      app/src/main/res/drawable-mdpi/loading_1.png
  79. BIN
      app/src/main/res/drawable-mdpi/loading_2.png
  80. BIN
      app/src/main/res/drawable-mdpi/logo1.png
  81. BIN
      app/src/main/res/drawable-mdpi/logo2.png
  82. BIN
      app/src/main/res/drawable-mdpi/logo_icon_down.png
  83. BIN
      app/src/main/res/drawable-mdpi/logo_icon_left.png
  84. BIN
      app/src/main/res/drawable-mdpi/logo_icon_ok.png
  85. BIN
      app/src/main/res/drawable-mdpi/logo_icon_right.png
  86. BIN
      app/src/main/res/drawable-xhdpi/btn_icon_add_default.png
  87. BIN
      app/src/main/res/drawable-xhdpi/btn_icon_add_selected.png
  88. BIN
      app/src/main/res/drawable-xhdpi/btn_icon_continue.png
  89. BIN
      app/src/main/res/drawable-xhdpi/btn_icon_out.png
  90. BIN
      app/src/main/res/drawable-xhdpi/btn_icon_right.png
  91. BIN
      app/src/main/res/drawable-xhdpi/btn_icon_stop.png
  92. BIN
      app/src/main/res/drawable-xhdpi/loading_1.png
  93. BIN
      app/src/main/res/drawable-xhdpi/loading_2.png
  94. BIN
      app/src/main/res/drawable-xhdpi/logo1.png
  95. BIN
      app/src/main/res/drawable-xhdpi/logo2.png
  96. BIN
      app/src/main/res/drawable-xhdpi/logo_icon_down.png
  97. BIN
      app/src/main/res/drawable-xhdpi/logo_icon_left.png
  98. BIN
      app/src/main/res/drawable-xhdpi/logo_icon_ok.png
  99. BIN
      app/src/main/res/drawable-xhdpi/logo_icon_right.png
  100. 0 0
      app/src/main/res/drawable-xxhdpi/btn_icon_add_default.png

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild

+ 19 - 0
.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="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/TvSDK_Lib_Project" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 33 - 0
.idea/misc.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="NullableNotNullManager">
+    <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
+    <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
+    <option name="myNullables">
+      <value>
+        <list size="4">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+        </list>
+      </value>
+    </option>
+    <option name="myNotNulls">
+      <value>
+        <list size="4">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+        </list>
+      </value>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" 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>

+ 10 - 0
.idea/modules.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/DuduToy.iml" filepath="$PROJECT_DIR$/DuduToy.iml" />
+      <module fileurl="file://$PROJECT_DIR$/TvSDK_Lib_Project/TvSDK_Lib_Project.iml" filepath="$PROJECT_DIR$/TvSDK_Lib_Project/TvSDK_Lib_Project.iml" />
+      <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.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="$PROJECT_DIR$/git" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
TvSDK_Lib_Project/.gitignore

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

+ 26 - 0
TvSDK_Lib_Project/build.gradle

@@ -0,0 +1,26 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 27
+    buildToolsVersion "27.0.2"
+
+    defaultConfig {
+        minSdkVersion 15
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+
+    compile files('libs/tv_pay_static.jar')
+    compile files('libs/odin.jar')
+}

BIN
TvSDK_Lib_Project/libs/odin.jar


BIN
TvSDK_Lib_Project/libs/tv_pay_static.jar


+ 17 - 0
TvSDK_Lib_Project/proguard-rules.pro

@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in D:\sdk\android-sdk-windows/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# 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 *;
+#}

+ 16 - 0
TvSDK_Lib_Project/src/main/AndroidManifest.xml

@@ -0,0 +1,16 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.huawei.digital.tvpay"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+    </application>
+
+</manifest>

BIN
TvSDK_Lib_Project/src/main/res/drawable-hdpi/ic_launcher.png


BIN
TvSDK_Lib_Project/src/main/res/raw/odin_plugin_ability_1x0x3.apk


BIN
TvSDK_Lib_Project/src/main/res/raw/odin_plugin_tv_1x0x0.apk


+ 11 - 0
TvSDK_Lib_Project/src/main/res/values-v11/styles.xml

@@ -0,0 +1,11 @@
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>

+ 12 - 0
TvSDK_Lib_Project/src/main/res/values-v14/styles.xml

@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>

+ 5 - 0
TvSDK_Lib_Project/src/main/res/values/strings.xml

@@ -0,0 +1,5 @@
+<resources>
+
+    <string name="app_name">PaymentSDKAndroidlib</string>
+
+</resources>

+ 20 - 0
TvSDK_Lib_Project/src/main/res/values/styles.xml

@@ -0,0 +1,20 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>

+ 1 - 0
app/.gitignore

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

+ 54 - 0
app/build.gradle

@@ -0,0 +1,54 @@
+apply plugin: 'com.android.application'
+
+android {
+    signingConfigs {
+        config {
+            keyAlias 'haochuan'
+            keyPassword '123456'
+            storeFile file('D:/android project/DuduToy/key/dudutoykey.jks')
+            storePassword '123456'
+        }
+    }
+    compileSdkVersion 27
+    buildToolsVersion "27.0.2"
+    defaultConfig {
+        applicationId "com.haochuan.dudutoy"
+        minSdkVersion 15
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0.1"
+        ndk {
+            abiFilters "armeabi-v7a", "x86"
+        }
+
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.config
+        }
+        debug {
+            debuggable true
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.config
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(include: ['*.jar'], dir: 'libs')
+    implementation project(':TvSDK_Lib_Project')
+    implementation 'com.android.support:appcompat-v7:27.0.2'
+    implementation 'com.android.support:support-v4:27.0.2'
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+    implementation 'com.shuyu:gsyVideoPlayer-java:5.0.0-beta'
+    implementation 'com.shuyu:gsyVideoPlayer-ex_so:5.0.0-beta'
+    implementation 'com.android.volley:volley:1.1.0'
+    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
+    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
+    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
+    implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
+    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
+}

+ 86 - 0
app/proguard-rules.pro

@@ -0,0 +1,86 @@
+# 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
+-keep class com.huawei.tools.**{*;}
+-keep class com.huawei.ability.**{*;}
+-keep class org.kxml2.**{*;}
+-keep class org.xmlpull.**{*;}
+-keep class com.google.**{*;}
+-keep class org.tantalum.**{*;}
+-keep class android.**{*;}
+-keep class assets.**{*;}
+-keep class com.android.**{*;}
+-keep class java.**{*;}
+-keep class javax.**{*;}
+-keep class junit.**{*;}
+-keep class org.**{*;}
+-keep class res.**{*;}
+
+
+-keep public class * extends android.content.ContextWrapper
+-keep public class * extends com.odin.framework.foundation.BasePluginActivity
+-keep public class * extends com.odin.framework.foundation.BasePluginService
+
+-keep class com.odin.framework{*;}
+-keep class com.odin.framework.utils.FileUtil{*;}
+-keep class com.odin.framework.utils.StringUtil{*;}
+-keep class com.odin.framework.utils.ThreadUtil{*;}
+-keep class com.odin.framework.proxy.ProxyManager{*;}
+-keep class com.odin.framework.plugable.Logger{*;}
+-keep class com.odin.framework.foundation.Framework{*;}
+-keep class com.odin.framework.foundation.ExposedService{*;}
+-keep class com.odin.framework.foundation.PluginInfo{*;}
+
+-keep class com.odin.plugable.api.**{*;}
+-keep class com.sdk.plugable.ability.log.LogImpl{*;}
+
+-keepattributes InnerClasses
+
+#Dynamic R File
+-keep class com.huawei.digital.tv.R{*;}
+
+-keep class com.huawei.digital.tv.R$*{*;}
+
+#plugin_in R File
+-keep class com.odin_plugin.R{*;}
+
+-keep class com.haochuan.dudutoy.R{*;}
+-keep class com.haochuan.dudutoy.R$*{*;}
+
+
+
+
+-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.**
+
+-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);
+}

BIN
app/release/dudutoy.apk


+ 1 - 0
app/release/output.json

@@ -0,0 +1 @@
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1},"path":"app-release.apk","properties":{"packageId":"com.haochuan.dudutoy","split":"","minSdkVersion":"16"}}]

+ 26 - 0
app/src/androidTest/java/com/haochuan/dudutoy/ExampleInstrumentedTest.java

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

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

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.haochuan.dudutoy">
+
+    <uses-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,com.shuyu.gsyvideoplayer.ex_so,tv.danmaku.ijk.media.exo2,shuyu.com.androidvideocache" />
+
+    <!-- 计费权限 -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application
+        android:name=".ToyApplication"
+        android:allowBackup="true"
+        android:icon="@drawable/dudu_icon"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:screenOrientation="landscape"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name=".MainActivity"
+            android:hardwareAccelerated="true"
+            android:launchMode="singleTop"
+            android:process=":remote"
+            android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".VideoPlayerActivity"
+            android:hardwareAccelerated="true"
+            android:screenOrientation="landscape"></activity>
+        <activity
+            android:name=".TestUnsubscribe"
+            android:screenOrientation="landscape"></activity>
+
+        <!-- 计费开始 -->
+        <activity
+            android:name="com.odin.framework.proxy.ProxyActivity"
+            android:configChanges="orientation|navigation|screenSize|keyboardHidden|keyboard"
+            android:exported="false"
+            android:screenOrientation="landscape"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
+            android:windowSoftInputMode="adjustPan"></activity>
+
+        <activity android:name=".PayActivity"
+            android:screenOrientation="landscape"
+            >
+
+        </activity>
+        <service
+            android:name="com.odin.framework.proxy.ProxyService1"
+            android:exported="false" />
+        <service
+            android:name="com.odin.framework.proxy.ProxyService2"
+            android:exported="false" />
+        <service
+            android:name="com.odin.framework.proxy.ProxyService3"
+            android:exported="false" />
+        <service
+            android:name="com.odin.framework.proxy.ProxyService4"
+            android:exported="false" />
+        <service
+            android:name="com.odin.framework.proxy.ProxyService5"
+            android:exported="false" />
+        <!-- 计费结束 -->
+
+    </application>
+
+</manifest>

+ 25 - 0
app/src/main/java/com/haochuan/dudutoy/BasicFactory.java

@@ -0,0 +1,25 @@
+package com.haochuan.dudutoy;
+
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * Created by yunhaipiaodi on 2017/8/2.
+ */
+
+public class BasicFactory {
+    protected String baseUrl = "http://202.99.114.74:56199/";
+    protected Retrofit retrofit = new Retrofit.Builder()
+            .baseUrl(baseUrl)
+            .client(new OkHttpClient.Builder()
+                    .connectTimeout(10, TimeUnit.SECONDS)
+                    .writeTimeout(10, TimeUnit.SECONDS)
+                    .readTimeout(10, TimeUnit.SECONDS).build())
+            .addConverterFactory(GsonConverterFactory.create())
+            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+            .build();
+}

+ 312 - 0
app/src/main/java/com/haochuan/dudutoy/CrashHandler.java

@@ -0,0 +1,312 @@
+package com.haochuan.dudutoy;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Looper;
+import android.util.Log;
+
+
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by yunhaipiaodi on 2017/10/24.
+ */
+
+public class CrashHandler implements Thread.UncaughtExceptionHandler {
+    public static final String TAG = "CrashHandler";
+
+    //系统默认的UncaughtException处理类
+    private Thread.UncaughtExceptionHandler mDefaultHandler;
+    //CrashHandler实例
+    private static CrashHandler INSTANCE = new CrashHandler();
+    //程序的Context对象
+    private Context mContext;
+    //用来存储设备信息和异常信息
+    private Map<String, String> infos = new HashMap<String, String>();
+
+    //用于格式化日期,作为日志文件名的一部分
+    private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
+
+    /** 保证只有一个CrashHandler实例 */
+    private CrashHandler() {
+    }
+
+    /** 获取CrashHandler实例 ,单例模式 */
+    public static CrashHandler getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * 初始化
+     *
+     * @param context
+     */
+    public void init(Context context) {
+        mContext = context;
+        //获取系统默认的UncaughtException处理器
+        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+        //设置该CrashHandler为程序的默认处理器
+        Thread.setDefaultUncaughtExceptionHandler(this);
+    }
+
+    private String  getImei(){
+        /*TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        return mTm.getDeviceId();*/
+        return "";
+    }
+
+    private String  getModel(){
+        return Build.MODEL;
+    }
+
+    private int getAndroidVersion(){
+        return Build.VERSION.SDK_INT;
+    }
+
+
+    /**
+     * 当UncaughtException发生时会转入该函数来处理
+     */
+    @Override
+    public void uncaughtException(Thread thread, Throwable ex) {
+        if (!handleException(ex) && mDefaultHandler != null) {
+            //如果用户没有处理则让系统默认的异常处理器来处理
+            mDefaultHandler.uncaughtException(thread, ex);
+        } else {
+            try {
+                Thread.sleep(3000);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "error : ", e);
+            }
+            //退出程序
+            android.os.Process.killProcess(android.os.Process.myPid());
+            System.exit(0);
+        }
+    }
+
+    /**
+     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
+     *
+     * @param ex
+     * @return true:如果处理了该异常信息;否则返回false.
+     */
+    private boolean handleException(Throwable ex) {
+        if (ex == null) {
+            return false;
+        }
+        //使用Toast来显示异常信息
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                //Toast.makeText(mContext, "很抱歉,程序出现异常", Toast.LENGTH_LONG).show();
+                Looper.loop();
+            }
+        }.start();
+        //收集设备参数信息
+        collectDeviceInfo(mContext);
+       //保存日志文件
+        saveCrashInfo2File(ex);
+
+
+       //保存错误信息到后台云端
+        saveCrashInfoToWeb(ex);
+        return true;
+    }
+
+    /**
+     * 收集设备参数信息
+     * @param ctx
+     */
+    public void collectDeviceInfo(Context ctx) {
+        try {
+            PackageManager pm = ctx.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
+            if (pi != null) {
+                String versionName = pi.versionName == null ? "null" : pi.versionName;
+                String versionCode = pi.versionCode + "";
+                infos.put("versionName", versionName);
+                infos.put("versionCode", versionCode);
+            }
+            infos.put("apiLevel",String.valueOf(Build.VERSION.SDK_INT));
+        } catch (PackageManager.NameNotFoundException e) {
+           // Log.e(TAG, "an error occured when collect package info", e);
+        }
+        Field[] fields = Build.class.getDeclaredFields();
+        for (Field field : fields) {
+            try {
+                field.setAccessible(true);
+                infos.put(field.getName(), field.get(null).toString());
+                //Log.d(TAG, field.getName() + " : " + field.get(null));
+            } catch (Exception e) {
+                //Log.e(TAG, "an error occured when collect crash info", e);
+            }
+        }
+    }
+
+    /**
+     * 保存错误信息到后台云端
+     *
+     */
+
+    private void saveCrashInfoToWeb(Throwable ex){
+        String cpuAbi = "";
+        String cpuAbi2 = "";
+        String versionName = "";
+        String versionCode = "";
+        String apiLevel = "";
+        String errorMessage = "";
+        String ramSize = ""; //内存大小
+
+        ramSize = getTotalRam(mContext);
+        for (Map.Entry<String, String> entry : infos.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+
+            if(key.equals("CPU_ABI")){
+                cpuAbi = value;
+            }else if(key.equals("CPU_ABI2")){
+                cpuAbi2 = value;
+            }
+            else if(key.equals("versionName")){
+                versionName = value;
+            }
+            else if(key.equals("versionCode")){
+                versionCode = value;
+            }
+            else if(key.equals("apiLevel")){
+                apiLevel = value;
+            }
+        }
+
+        Writer writer = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(writer);
+        ex.printStackTrace(printWriter);
+        Throwable cause = ex.getCause();
+        while (cause != null) {
+            cause.printStackTrace(printWriter);
+            cause = cause.getCause();
+        }
+        printWriter.close();
+        String result = writer.toString();
+
+
+
+        new ErrorDataViewModel(cpuAbi,cpuAbi2,versionName,versionCode,apiLevel,result,ramSize);
+    }
+
+    public void saveCrashInfoToWeb(String msg){
+        String cpuAbi = "";
+        String cpuAbi2 = "";
+        String versionName = "";
+        String versionCode = "";
+        String apiLevel = "";
+        String errorMessage = "";
+        String ramSize = ""; //内存大小
+        collectDeviceInfo(mContext);
+        ramSize = getTotalRam(mContext);
+
+        for (Map.Entry<String, String> entry : infos.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+
+            if(key.equals("CPU_ABI")){
+                cpuAbi = value;
+            }else if(key.equals("CPU_ABI2")){
+                cpuAbi2 = value;
+            }
+            else if(key.equals("versionName")){
+                versionName = value;
+            }
+            else if(key.equals("versionCode")){
+                versionCode = value;
+            }
+            else if(key.equals("apiLevel")){
+                apiLevel = value;
+            }
+        }
+
+
+        String result = msg;
+
+
+
+        new ErrorDataViewModel(cpuAbi,cpuAbi2,versionName,versionCode,apiLevel,result,ramSize);
+    }
+
+
+    //返回内存大小 GB
+    public  String getTotalRam(Context context){
+        String path = "/proc/meminfo";
+        String firstLine = null;
+        int totalRam = 0 ;
+        try{
+            FileReader fileReader = new FileReader(path);
+            BufferedReader br = new BufferedReader(fileReader,8192);
+            firstLine = br.readLine().split("\\s+")[1];
+            br.close();
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        if(firstLine != null){
+            totalRam = (int)Math.ceil((new Float(Float.valueOf(firstLine) / (1024 * 1024)).doubleValue()));
+        }
+
+        return totalRam + "GB";//返回1GB/2GB/3GB/4GB
+    }
+
+    /**
+     * 保存错误信息到文件中
+     *
+     * @param ex
+     * @return  返回文件名称,便于将文件传送到服务器
+     */
+    private String saveCrashInfo2File(Throwable ex) {
+
+        StringBuffer sb = new StringBuffer();
+        for (Map.Entry<String, String> entry : infos.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            sb.append(key + "=" + value + "\n");
+        }
+
+        Writer writer = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(writer);
+        ex.printStackTrace(printWriter);
+        Throwable cause = ex.getCause();
+        while (cause != null) {
+            cause.printStackTrace(printWriter);
+            cause = cause.getCause();
+        }
+        printWriter.close();
+        String result = writer.toString();
+        sb.append(result);
+        try {
+            long timestamp = System.currentTimeMillis();
+            String time = formatter.format(new Date());
+            String fileName = "crash-" + time + "-" + timestamp + ".log";
+            String path = mContext.getExternalCacheDir().getAbsolutePath();
+            FileOutputStream fos = new FileOutputStream(path + fileName);
+            fos.write(sb.toString().getBytes());
+            fos.close();
+            return fileName;
+        } catch (Exception e) {
+            Log.e(TAG, "an error occured while writing file...", e);
+        }
+        return null;
+    }
+}

+ 493 - 0
app/src/main/java/com/haochuan/dudutoy/DuduPlayer.java

@@ -0,0 +1,493 @@
+package com.haochuan.dudutoy;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.AnimationDrawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.shuyu.gsyvideoplayer.GSYVideoManager;
+import com.shuyu.gsyvideoplayer.model.VideoOptionModel;
+import com.shuyu.gsyvideoplayer.utils.Debuger;
+import com.shuyu.gsyvideoplayer.utils.GSYVideoType;
+import com.shuyu.gsyvideoplayer.video.GSYADVideoPlayer;
+import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import moe.codeest.enviews.ENDownloadView;
+import tv.danmaku.ijk.media.player.IjkMediaPlayer;
+
+
+/**
+ * Created by Lyn on 2018/5/30.
+ */
+
+public class DuduPlayer extends StandardGSYVideoPlayer {
+
+    ImageView startBtn;
+    ImageView loading;
+    AnimationDrawable a;
+    OnCompleteListener onCompleteListener;
+
+    LinearLayout seekContainer;
+    SeekBar seekBar;
+    TextView durationText;
+    TextView percentText;
+
+    private long currentTime = 0;
+
+    Context context;
+    Timer timer ;
+    TimerTask timerTask;
+
+    private boolean isSeeked = false;
+
+    private boolean isNoticed = false;
+
+    String TAG = "DuduPlayer";
+
+
+
+
+    public DuduPlayer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setOnCompleteListener(OnCompleteListener onCompleteListener){
+        this.onCompleteListener = onCompleteListener;
+    }
+
+    @Override
+    protected void init(Context context) {
+        super.init(context);
+        this.context = context;
+        mDismissControlTime = 200;
+        startBtn = findViewById(R.id.dudu_start_btn);
+        loading = findViewById(R.id.loading_anim);
+        seekContainer = findViewById(R.id.seek_container);
+        durationText = findViewById(R.id.duration_text);
+        percentText = findViewById(R.id.percent_text);
+        seekBar = findViewById(R.id.seek_bar);
+        seekBar.setMax(1000);
+        seekBar.setProgress(0);
+        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                int mProgress = 0;
+                if (fromUser) {
+                    mProgress = progress;
+                }
+                percentText.setText(mProgress/10 + "%");
+
+                if(progress<=0){
+                    seekBar.setProgress(10);
+                    percentText.setText("1%");
+                }
+
+                if(progress >= 1000){
+                    seekBar.setProgress(990);
+                    percentText.setText("99%");
+                }
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+        //GSYVideoType.enableMediaCodec();
+        //GSYVideoType.enableMediaCodecTexture();
+        videoOptimize();
+        initLoadingAnimation();
+        initTimer();
+        Debuger.disable();
+    }
+
+
+
+    private void videoOptimize(){
+        List<VideoOptionModel> list = new ArrayList<>();
+        VideoOptionModel videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "allowed_media_types", "video"); //根据媒体类型来配置
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "mediacodec", 1);
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "videotoolbox", 0);
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", 20000);
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "buffer_size", 1316);
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "infbuf", 1);  // 无限读
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzemaxduration", 100);
+        list.add(videoOptionModel);
+        videoOptionModel = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1);
+        list.add(videoOptionModel);
+        GSYVideoManager.instance().setOptionModelList(list);
+    }
+
+    private void initLoadingAnimation(){
+        loading.setImageResource(R.drawable.loading_animation);
+        AnimationDrawable a = (AnimationDrawable)loading.getDrawable();
+        a.start();
+    }
+
+    @Override
+    public void clickStartIcon(){
+        super.clickStartIcon();
+    }
+
+    @Override
+    public int getLayoutId() {
+        return R.layout.du_du_player;
+    }
+
+
+
+    public void seek(int position){
+        if(mCurrentState == CURRENT_STATE_PREPAREING || getDuration() == 0 || mCurrentState!= CURRENT_STATE_PLAYING){
+            return;
+        }
+
+        seekContainer.setVisibility(VISIBLE);
+        seekBar.setProgress(position);
+
+        currentTime =Calendar.getInstance().getTimeInMillis();
+        cancelTimer();
+        initTimer();
+        isSeeked = true;
+    }
+
+
+    private void initTimer(){
+        if(timer == null){
+            timer = new Timer();
+        }
+        timerTask = new TimerTask() {
+            @Override
+            public void run() {
+                Activity activity = (Activity)context;
+                activity.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        long myCurrentTime = Calendar.getInstance().getTimeInMillis();
+                        if(myCurrentTime - currentTime > 3){
+                            int position = seekBar.getProgress();
+                            position = position* getDuration()/1000;
+                            seekTo(position);
+                            seekContainer.setVisibility(INVISIBLE);
+                        }
+                    }
+                });
+            }
+        };
+
+        timer.schedule(timerTask,3000);
+    }
+
+    public boolean canSeek(){
+        if(mCurrentState == CURRENT_STATE_PREPAREING || getDuration() == 0){
+            return false;
+        }else{
+            return true;
+        }
+    }
+
+    private void cancelTimer(){
+        if(timerTask != null){
+            timerTask.cancel();
+        }
+    }
+
+    @Override
+    public void onStopTrackingTouch(SeekBar seekBar) {
+        super.onStopTrackingTouch(seekBar);
+    }
+
+    @Override
+    protected void showWifiDialog() {
+        startPlayLogic();
+    }
+
+    @Override
+    protected void changeUiToPauseShow(){
+        Debuger.printfLog("changeUiToPauseShow");
+
+        setViewShowState(mTopContainer, VISIBLE);
+        setViewShowState(mBottomContainer, VISIBLE);
+        setViewShowState(mStartButton, INVISIBLE);
+        setViewShowState(mLoadingProgressBar, INVISIBLE);
+        setViewShowState(mThumbImageViewLayout, INVISIBLE);
+        setViewShowState(mBottomProgressBar, INVISIBLE);
+        setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
+
+        if (mLoadingProgressBar instanceof ENDownloadView) {
+            ((ENDownloadView) mLoadingProgressBar).reset();
+        }
+        updateStartImage();
+        updatePauseCover();
+
+        //Log.d(TAG,"changeUiToPauseShow");
+    }
+
+    public  String convertLongTimeToStr(long time) {
+        int ss = 1000;
+        int mi = ss * 60;
+        int hh = mi * 60;
+
+        long hour = (time) / hh;
+        long minute = (time - hour * hh) / mi;
+        long second = (time - hour * hh - minute * mi) / ss;
+
+        String strHour = hour < 10 ? "0" + hour : "" + hour;
+        String strMinute = minute < 10 ? "0" + minute : "" + minute;
+        String strSecond = second < 10 ? "0" + second : "" + second;
+        if (hour > 0) {
+            return strHour + ":" + strMinute + ":" + strSecond;
+        } else {
+            return strMinute + ":" + strSecond;
+        }
+    }
+
+    @Override
+    protected void changeUiToPlayingShow() {
+        Debuger.printfLog("changeUiToPlayingShow");
+        isBuffering = false;
+        setViewShowState(mTopContainer, INVISIBLE);
+        setViewShowState(mBottomContainer, INVISIBLE);
+        setViewShowState(mStartButton, INVISIBLE);
+        setViewShowState(mLoadingProgressBar, INVISIBLE);
+        setViewShowState(mThumbImageViewLayout, INVISIBLE);
+        setViewShowState(mBottomProgressBar, INVISIBLE);
+        setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
+        durationText.setText(convertLongTimeToStr(getDuration()));
+        if (mLoadingProgressBar instanceof ENDownloadView) {
+            ((ENDownloadView) mLoadingProgressBar).reset();
+        }
+        updateStartImage();
+        //Log.d(TAG,"changeUiToPreparingShow");
+    }
+
+    @Override
+    protected void changeUiToNormal() {
+        Debuger.printfLog("changeUiToNormal");
+
+        setViewShowState(mTopContainer, VISIBLE);
+        setViewShowState(mBottomContainer, VISIBLE);
+        setViewShowState(mStartButton, INVISIBLE);
+        setViewShowState(mLoadingProgressBar, INVISIBLE);
+        setViewShowState(mThumbImageViewLayout, VISIBLE);
+        setViewShowState(mBottomProgressBar, INVISIBLE);
+        setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
+
+        updateStartImage();
+        if (mLoadingProgressBar instanceof ENDownloadView) {
+            ((ENDownloadView) mLoadingProgressBar).reset();
+        }
+
+        //Log.d(TAG,"changeUiToNormal");
+    }
+
+
+    @Override
+    protected void changeUiToCompleteShow() {
+        Debuger.printfLog("changeUiToCompleteShow");
+
+        setViewShowState(mTopContainer, VISIBLE);
+        setViewShowState(mBottomContainer, VISIBLE);
+        setViewShowState(mStartButton, INVISIBLE);
+        setViewShowState(mLoadingProgressBar, INVISIBLE);
+        setViewShowState(mThumbImageViewLayout, VISIBLE);
+        setViewShowState(mBottomProgressBar, INVISIBLE);
+        setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
+
+        this.onCompleteListener.onComplete();
+        if (mLoadingProgressBar instanceof ENDownloadView) {
+            ((ENDownloadView) mLoadingProgressBar).reset();
+        }
+        updateStartImage();
+        //Log.d(TAG,"changeUiToCompleteShow");
+    }
+
+    private void Toast(final String msg){
+        Activity activity = (Activity)context;
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Toast.makeText(context,msg,Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    @Override
+    public void onError(int what, int extra) {
+        if(what == -10000){
+            return;
+        }
+        super.onError(what,extra);
+        Log.d(TAG,"what:" + what + "extra:" + extra);
+    }
+
+
+
+    @Override
+    protected void changeUiToError() {
+        Debuger.printfLog("changeUiToError");
+
+        setViewShowState(mTopContainer, VISIBLE);
+        setViewShowState(mBottomContainer, VISIBLE);
+        setViewShowState(mStartButton, INVISIBLE);
+        setViewShowState(mLoadingProgressBar, INVISIBLE);
+        setViewShowState(mThumbImageViewLayout, INVISIBLE);
+        setViewShowState(mBottomProgressBar, INVISIBLE);
+        setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
+
+        if (mLoadingProgressBar instanceof ENDownloadView) {
+            ((ENDownloadView) mLoadingProgressBar).reset();
+        }
+        updateStartImage();
+        //Log.d(TAG,"changeUiToError");
+        Toast("播放器发生错误,请退出播放!");
+        onCompleteListener.onComplete();
+    }
+
+    long lastBufferingTime = 0;
+
+    boolean isBuffering = false;
+    @Override
+    protected void changeUiToPlayingBufferingShow() {
+        Date date = new Date();
+        long currentBufferingTime = date.getTime();
+        Debuger.printfLog("changeUiToPlayingBufferingShow,lastBufferingTime" + currentBufferingTime);
+        if(currentBufferingTime - lastBufferingTime > 1500){
+            setViewShowState(mTopContainer, INVISIBLE);
+            setViewShowState(mBottomContainer, INVISIBLE);
+            setViewShowState(mStartButton, INVISIBLE);
+            setViewShowState(mLoadingProgressBar, VISIBLE);
+            setViewShowState(mThumbImageViewLayout, INVISIBLE);
+            setViewShowState(mBottomProgressBar, INVISIBLE);
+            setViewShowState(mLockScreen, GONE);
+
+            if (mLoadingProgressBar instanceof ENDownloadView) {
+                ENDownloadView enDownloadView = (ENDownloadView) mLoadingProgressBar;
+                if (enDownloadView.getCurrentState() == ENDownloadView.STATE_PRE) {
+                    ((ENDownloadView) mLoadingProgressBar).start();
+                }
+            }
+        }
+        isSeeked = false;
+        lastBufferingTime =currentBufferingTime;
+        isBuffering = true;
+        if(!isNoticed){
+            Toast("提示!视频在缓冲过程中,请不要做其他任何操作,以免发生异常!");
+            isNoticed = true;
+        }
+
+       // Log.d(TAG,"changeUiToPlayingBufferingShow,");
+    }
+
+    @Override
+    protected void changeUiToPreparingShow() {
+        super.changeUiToPreparingShow();
+       // Log.d(TAG,"changeUiToPreparingShow");
+    }
+
+
+    public void playOrPause(){
+        if (mCurrentState == CURRENT_STATE_PLAYING) {
+            try {
+                getGSYVideoManager().pause();
+                setStateAndUi(CURRENT_STATE_PAUSE);
+                startBtn.setImageResource(R.drawable.btn_icon_right);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }else if (mCurrentState == CURRENT_STATE_PAUSE){
+            try {
+                getGSYVideoManager().start();
+                setStateAndUi(CURRENT_STATE_PLAYING);
+                startBtn.setImageResource(R.drawable.btn_icon_stop);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void play(){
+        if (mCurrentState == CURRENT_STATE_PAUSE){
+            try {
+                getGSYVideoManager().start();
+                setStateAndUi(CURRENT_STATE_PLAYING);
+                startBtn.setImageResource(R.drawable.btn_icon_stop);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void pause(){
+        if (mCurrentState == CURRENT_STATE_PLAYING || mCurrentState == CURRENT_STATE_PLAYING_BUFFERING_START) {
+            try {
+                getGSYVideoManager().pause();
+                setStateAndUi(CURRENT_STATE_PAUSE);
+                startBtn.setImageResource(R.drawable.btn_icon_right);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void onDestroy(){
+        startBtn = null;
+        loading = null;
+        if(a != null){
+            a.stop();
+        }
+        a = null;
+        onCompleteListener = null;
+        seekContainer = null;
+        seekBar = null;
+        durationText = null;
+        percentText= null;
+        context = null;
+        if(timer !=null){
+            timer.cancel();
+        }
+        if(timerTask !=null){
+            timerTask.cancel();
+        }
+        timer = null;
+        timerTask = null;
+
+    }
+
+    public boolean isBuffering(){
+        return isBuffering;
+    }
+
+    public interface OnCompleteListener{
+        public void onComplete();
+    }
+
+
+
+}

+ 66 - 0
app/src/main/java/com/haochuan/dudutoy/ErrorDataViewModel.java

@@ -0,0 +1,66 @@
+package com.haochuan.dudutoy;
+
+
+import java.util.Observable;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.annotations.NonNull;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.functions.Consumer;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/20.
+ */
+
+public class ErrorDataViewModel extends Observable {
+    private CompositeDisposable compositeDisposable = new CompositeDisposable();
+    String cpuAbi;
+    String cpuAbi2;
+    String versionName;
+    String versionCode;
+    String apiLevel;
+    String errorMessage;
+    String ramSize;
+
+    public ErrorDataViewModel(String cpuAbi, String cpuAbi2, String versionName,
+                              String versionCode, String apiLevel, String errorMessage, String ramSize){
+        this.cpuAbi = cpuAbi;
+        this.cpuAbi2 = cpuAbi2;
+        this.versionName = versionName;
+        this.versionCode = versionCode;
+        this.apiLevel = apiLevel;
+        this.errorMessage = errorMessage;
+        this.ramSize = ramSize;
+        fetchErrorData();
+    }
+
+    private void fetchErrorData() {
+
+        compositeDisposable.add( new ErrorFactory().create()
+                .getObservable(cpuAbi,cpuAbi2,versionName,versionCode,apiLevel,errorMessage,ramSize)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Consumer<StyleData>() {
+                    @Override
+                    public void accept(@NonNull StyleData source) throws Exception {
+                    }
+                }, new Consumer<Throwable>() {
+                    @Override
+                    public void accept(@NonNull Throwable throwable) throws Exception {
+                        throwable.printStackTrace();
+                    }
+                }));
+    }
+
+
+    public void reset(){
+        unSubscribeFromObservable();
+        compositeDisposable = null;
+    }
+    private void unSubscribeFromObservable() {
+        if (compositeDisposable != null && !compositeDisposable.isDisposed()) {
+            compositeDisposable.dispose();
+        }
+    }
+}

+ 9 - 0
app/src/main/java/com/haochuan/dudutoy/ErrorFactory.java

@@ -0,0 +1,9 @@
+package com.haochuan.dudutoy;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/22.
+ */
+
+public class ErrorFactory extends BasicFactory {
+    public ErrorService create(){return super.retrofit.create(ErrorService.class);}
+}

+ 23 - 0
app/src/main/java/com/haochuan/dudutoy/ErrorService.java

@@ -0,0 +1,23 @@
+package com.haochuan.dudutoy;
+
+
+import io.reactivex.Observable;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/22.
+ */
+
+public interface ErrorService {
+    @POST("index.php?m=Home&c=Api&a=addError")
+    @FormUrlEncoded
+    public  Observable<StyleData> getObservable(@Field("cpu_abi") String cpuAbi,
+                                                @Field("cpu_abi2") String cpuAbi2,
+                                                @Field("version_name") String versionName,
+                                                @Field("version_code") String versionCode,
+                                                @Field("api_level") String apiLevel,
+                                                @Field("error_message") String errorMessage,
+                                                @Field("ram_size") String ramSize);
+}

+ 152 - 0
app/src/main/java/com/haochuan/dudutoy/HuaweiPay.java

@@ -0,0 +1,152 @@
+package com.haochuan.dudutoy;
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+import com.android.volley.toolbox.Volley;
+import com.odin.framework.plugable.Logger;
+import com.sdk.commplatform.Commplatform;
+import com.sdk.commplatform.entry.AppInfo;
+import com.sdk.commplatform.entry.AuthResult;
+import com.sdk.commplatform.entry.CyclePayment;
+import com.sdk.commplatform.entry.ErrorCode;
+import com.sdk.commplatform.entry.PayResult;
+import com.sdk.commplatform.listener.CallbackListener;
+
+import org.json.JSONObject;
+
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ * Created by Lyn on 2018/6/4.
+ */
+
+public class HuaweiPay {
+    private String appKey="hcjf";
+    private String appId="hcddwjwg";
+    private String authProductId="ddwjwgby";
+    private String authContentId="ddwjwgby";
+    private String productId="1";
+    private String thirdAppId="1";
+    private String thirdAppName="嘟嘟玩具王国";
+    private String thirdAppPkgName="com.haochuan.dudutoy";
+    private String notifyUrl="http://202.99.114.74:56199/notify.php";
+
+    private static HuaweiPay instance;
+
+    public static HuaweiPay getInstance(){
+        if(instance == null){
+            instance = new HuaweiPay();
+        }
+        return instance;
+    }
+
+    public static String getRandomCharAndNumr(Integer length) {
+        String str = "";
+        Random random = new Random();
+        for (int i = 0; i < length; i++) {
+            boolean b = random.nextBoolean();
+            if (b) { // 字符串
+                // int choice = random.nextBoolean() ? 65 : 97; 取得65大写字母还是97小写字母
+                str += (char) (65 + random.nextInt(26));// 取得大写字母
+            } else { // 数字
+                str += String.valueOf(random.nextInt(10));
+            }
+        }
+        return str;
+    }
+
+    private CyclePayment getBuyInfo(String tradeNo)
+    {//校验商品信息
+        CyclePayment buyInfo = new CyclePayment();
+        buyInfo.setTradeNo(tradeNo);
+        buyInfo.setThirdAppId(thirdAppId);
+        buyInfo.setThirdAppName(thirdAppName);
+        buyInfo.setThirdAppPkgname(thirdAppPkgName);
+        buyInfo.setNotifyURL(notifyUrl);
+        buyInfo.setNote("");
+        buyInfo.setUnsubNotifyURL("http://202.99.114.74:56199/index.php?m=Home&c=Order&a=unsubscribeNotify");
+        return buyInfo;
+    }
+
+
+    //计费sdk初始化
+    public void init(Context context,CallbackListener<Integer> listener){
+        thirdAppPkgName = context.getPackageName();
+        AppInfo appInfo = new AppInfo();
+        appInfo.setAppId(appId);// 应用ID
+        appInfo.setAppKey(appKey);// 应用Key
+        appInfo.setCtx(context);
+        appInfo.setVersionCheckStatus(0);
+        Commplatform.getInstance().Init(0,
+                appInfo,
+                listener);
+    }
+
+    //包月鉴权
+    public void authForMonth(CallbackListener<AuthResult> listener){
+            Commplatform.getInstance().authPermission(authProductId,"2",authContentId,listener);
+    }
+
+    //获取用户Id
+    public String getUserId(){
+        return Commplatform.getInstance().getLoginUin();
+    }
+
+    private void getTradeNo(Context context,String userId,final GetTradeNoListener listener){
+        String url = String.format("http://202.99.114.74:56199/index.php?m=Home&c=Api&a=CreatOrder&uid=%s",userId);
+        Volley.newRequestQueue(context).add(new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() {
+            @Override
+            public void onResponse(JSONObject response) {
+                    if(response.has("data")){
+                        try{
+                            listener.onResult(response.getString("data"));
+                        }catch (Exception e){
+                            listener.onResult("");
+                            e.printStackTrace();
+                        }
+                    }
+            }
+        }, new Response.ErrorListener() {
+            @Override
+            public void onErrorResponse(VolleyError error) {
+                listener.onResult("");
+                error.printStackTrace();
+            }
+        }));
+    }
+
+    //包月计费
+    public void payForMonth(final Context context,String userId,final String buyProductId,final CallbackListener<PayResult> listener)
+    {
+        getTradeNo(context, userId, new GetTradeNoListener() {
+            @Override
+            public void onResult(String tradeNo) {
+                CyclePayment buyInfo = getBuyInfo(tradeNo);
+                buyInfo.setProductId(buyProductId);
+                Commplatform.getInstance().subsPay(buyInfo,
+                        context,
+                        listener);
+            }
+        });
+    }
+
+    //取消订购
+    public void unSubscribe(Context context,String tradeNo,CallbackListener<PayResult> payListener){
+        Commplatform.getInstance().cancelCyclePay(tradeNo,context,payListener);
+    }
+
+    //销毁sdk
+    public void onDestroy(){
+        Commplatform.getInstance().destroy();
+    }
+
+    public interface GetTradeNoListener{
+        public void onResult(String tradeNo);
+    }
+}

+ 29 - 0
app/src/main/java/com/haochuan/dudutoy/LocalStore.java

@@ -0,0 +1,29 @@
+package com.haochuan.dudutoy;
+
+import android.content.Context;
+
+/**
+ * Created by 浩传 on 2018/6/22.
+ */
+
+public class LocalStore {
+    Context context;
+    String shareName = "duduToy";
+    String isVipTag = "isVip";
+
+    public LocalStore(Context context){
+        this.context = context;
+    }
+
+    public void saveIsVip(boolean isVip){
+        context.getSharedPreferences(shareName,Context.MODE_PRIVATE)
+                .edit()
+                .putBoolean(isVipTag,isVip)
+                .commit();
+    }
+
+    public boolean getIsVip(){
+       return context.getSharedPreferences(shareName,Context.MODE_PRIVATE)
+               .getBoolean(isVipTag,false);
+    }
+}

+ 596 - 0
app/src/main/java/com/haochuan/dudutoy/MainActivity.java

@@ -0,0 +1,596 @@
+package com.haochuan.dudutoy;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.drawable.AnimationDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.webkit.JavascriptInterface;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+import com.android.volley.toolbox.Volley;
+import com.odin.framework.plugable.Logger;
+import com.sdk.commplatform.entry.AuthResult;
+import com.sdk.commplatform.entry.ErrorCode;
+import com.sdk.commplatform.entry.PayResult;
+import com.sdk.commplatform.listener.CallbackListener;
+
+import org.json.JSONObject;
+
+public class MainActivity extends Activity {
+
+    String TAG = "HuaweiPay";
+
+    private String userId="";
+    private WebView webview;
+    private ImageView pageLoadingAnim;
+
+    private String backUrl = "";
+    private String buyProductId="";
+
+    boolean enableLogger = false;
+
+    private void Logger(String msg){
+        if(enableLogger){
+            Log.d(TAG,msg);
+        }
+    }
+
+    private boolean isPlayPay =false;
+
+    private int requestPlayCode = 1;
+    private int requestPayCode =2;
+    private int responsePlayCode =3;
+
+    private H5Result h5Result = new H5Result() {
+        @Override
+        public void videoPlay(String url,String title,String uId,String sourceId) {
+            Intent intent = new Intent(MainActivity.this,VideoPlayerActivity.class);
+            intent.putExtra("url",url);
+            intent.putExtra("title",title);
+            intent.putExtra("uId",uId);
+            intent.putExtra("sourceId",sourceId);
+            MainActivity.this.startActivityForResult(intent,requestPlayCode);
+        }
+    };
+
+    private MyPayResult myPayResult = new MyPayResult() {
+        @Override
+        public void onSuccess() {
+            Toast("计费成功" );
+            Logger("计费成功");
+            authAfterPay();
+
+        }
+
+        @Override
+        public void onFail(String msg) {
+            Logger("计费失败:" + msg);
+            authAfterPay();
+        }
+    };
+
+    private void authAfterPay(){
+        final ProgressDialog dialog = new ProgressDialog(this);
+        dialog.setMessage("获取用户支付状态中,请稍后...");
+        dialog.setCancelable(false);
+        Logger("计费返回");
+        Logger("开始鉴权");
+
+        HuaweiPay.getInstance().authForMonth(new CallbackListener<AuthResult>() {
+            @Override
+            public void callback(int i, AuthResult authResult) {
+                if(i == ErrorCode.COM_PLATFORM_SUCCESS){
+                   new LocalStore(MainActivity.this).saveIsVip(true);
+                    Logger("当前用户是会员");
+                }else{
+                    new LocalStore(MainActivity.this).saveIsVip(false);
+                    Logger("当前用户不是会员");
+                }
+                MainActivity.this.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        dialog.dismiss();
+                    }
+                });
+                if(!isPlayPay){
+                    Logger("跳转到主页");
+                    reloadUrl();
+                }else{
+                    Logger("不跳转到主页");
+                }
+
+            }
+        });
+    }
+
+    public static String replaceAccessTokenReg(String url, String name, String accessToken) {
+        url = url.replaceAll("(" + name + "=[^&]*)", name + "=" + accessToken);
+        return url;
+    }
+
+    private String transUrl(String url){
+        if(url.contains("is_vip=")){
+            url = replaceAccessTokenReg(url,"is_vip",new LocalStore(MainActivity.this).getIsVip()?"true":"false");
+        }else{
+            url = url + "&is_vip=" + (new LocalStore(MainActivity.this).getIsVip()?"true":"false");
+        }
+        if(!url.contains("uid=")){
+            url = url+ "&uid=" + userId;
+        }
+
+        return url;
+    }
+
+    private void reloadUrl(){
+        this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                String url = transUrl(MainActivity.this.backUrl);
+                webview.loadUrl(url);
+            }
+        });
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode,int resultCode,Intent data){
+        super.onActivityResult(requestCode,resultCode,data);
+        if(requestCode == requestPlayCode){
+            onJsFresh();
+            if(resultCode == responsePlayCode){
+                Log.d(TAG,"视频跳转计费");
+                isPlayPay = true;
+                gotoPayActivity(userId,buyProductId);
+            }
+        }else if(requestCode == requestPayCode){
+            onJsFresh();
+            authAfterPay();
+        }
+
+    }
+
+    private void gotoPayActivity(String userId,String buyProductId){
+        Intent intent = new Intent(this,PayActivity.class);
+        intent.putExtra("userId",userId);
+        intent.putExtra("buyProductId",buyProductId);
+        startActivityForResult(intent,requestPayCode);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        FrameLayout frameLayout = findViewById(R.id.webview_container);
+        webview = new WebView(this);
+        frameLayout.addView(webview,new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
+        webview.setVisibility(View.INVISIBLE);
+        pageLoadingAnim = findViewById(R.id.loading_anim);
+        initLoadingAnimation();
+        prepare();
+
+    }
+
+    public void saveLoginUser(String userId){
+        String requestUrl = "http://202.99.114.74:56199/index.php?m=Home&c=DuduApi&a=addUser"
+                    + "&uid=" + userId
+                    + "&UserToken=dudutoken"
+                    +"&originId" + 2;
+        RequestQueue queue = Volley.newRequestQueue(this);
+        queue.add(new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
+            @Override
+            public void onResponse(JSONObject response) {
+
+            }
+        }, new Response.ErrorListener() {
+            @Override
+            public void onErrorResponse(VolleyError error) {
+
+            }
+        }));
+    }
+
+    private void initLoadingAnimation(){
+        pageLoadingAnim.setImageResource(R.drawable.loading_page_animation);
+        AnimationDrawable loadingAnim = (AnimationDrawable)pageLoadingAnim.getDrawable();
+        loadingAnim.start();
+        pageLoadingAnim.setVisibility(View.VISIBLE);
+    }
+
+    private void stopLoadingAnimation(){
+        AnimationDrawable loadingAnim = (AnimationDrawable)pageLoadingAnim.getDrawable();
+        loadingAnim.stop();
+        pageLoadingAnim.setVisibility(View.INVISIBLE);
+    }
+
+
+    private void loadH5Url(){
+        String url = "http://202.99.114.74:56199/h5/toymallapp/index.html?is_vip=%s&uid=%s";
+        url = String.format(url,new LocalStore(MainActivity.this).getIsVip(),userId);
+        webview.getSettings().setJavaScriptEnabled(true);
+        webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
+        webview.setWebChromeClient(new WebChromeClient() {
+            @Override
+            public void onProgressChanged(WebView view, int progress) {
+                MainActivity.this.setProgress(progress * 1000);
+            }
+        });
+        webview.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url)
+            {
+                super.onPageFinished(view, url);
+                stopLoadingAnimation();
+                webview.setVisibility(View.VISIBLE);
+            }
+
+            @Override
+            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+                Toast("Oh no! ");
+            }
+        });
+        webview.addJavascriptInterface(new AndroidToJs(h5Result,myPayResult),"H5Play");
+        webview.loadUrl(url);
+
+    }
+
+    private void prepare(){
+        HuaweiPay.getInstance().init(this, new CallbackListener<Integer>()
+        {
+            @Override
+            public void callback(final int paramInt, final Integer paramT)
+            {
+                switch (paramInt){
+                    case ErrorCode.COM_PLATFORM_SUCCESS:
+                        //Toast("初始化成功");
+                        HuaweiPay.getInstance().authForMonth(new CallbackListener<AuthResult>() {
+                            @Override
+                            public void callback(int i, AuthResult authResult) {
+                                switch (i){
+                                    case ErrorCode.COM_PLATFORM_SUCCESS:
+                                        new LocalStore(MainActivity.this).saveIsVip(true);
+                                        if(authResult!=null){
+                                            Toast(authResult.description);
+                                            Log.i(TAG,authResult.description);
+                                        }
+                                        runH5();
+                                        break;
+                                    case ErrorCode.COM_PLATFORM_ERROR_PARAM:
+                                        new LocalStore(MainActivity.this).saveIsVip(false);
+                                        if(authResult!=null){
+                                            getBuyProductId(authResult);
+                                        }
+                                        runH5();
+                                        Log.i(TAG,"参数错误,errorcode:" + paramInt);
+                                        break;
+                                    case ErrorCode.COM_PLATFORM_ERROR_UNKNOWN:
+                                        new LocalStore(MainActivity.this).saveIsVip(false);
+                                        if(authResult!=null){
+                                            getBuyProductId(authResult);
+                                        }
+                                        runH5();
+                                        Log.i(TAG,"SDK未初始化及其它错误,errorcode:" + paramInt);
+                                        break;
+                                    default:
+                                        new LocalStore(MainActivity.this).saveIsVip(false);
+                                        if(authResult!=null){
+                                            getBuyProductId(authResult);
+                                        }
+                                        runH5();
+                                        Log.i(TAG,"其他错误,errorcode:" + paramInt);
+                                        break;
+                                }
+                            }
+                        });
+                        userId = HuaweiPay.getInstance().getUserId();
+                        saveLoginUser(userId);
+                        break;
+                    case ErrorCode.COM_PLATFORM_ERROR_ONLINE_CHECK_FAILURE:
+                        Log.i(TAG,"无网络");
+                        CrashHandler.getInstance().saveCrashInfoToWeb("初始化失败,无网络");
+                        onInitFail();
+                        break;
+                    case ErrorCode.COM_PLATFORM_ERROR_FORCE_CLOSE:
+                        Log.i(TAG,"初始化异常,强制退出");
+                        CrashHandler.getInstance().saveCrashInfoToWeb("初始化异常,强制退出");
+                        onInitFail();
+                        break;
+                    case ErrorCode.COM_PLATFORM_ERROR_TIME_OUT:
+                        //Toast(MainActivity.this,"网络超时:" + paramInt);
+                        Log.i(TAG,"网络超时");
+                        CrashHandler.getInstance().saveCrashInfoToWeb("初始化失败,网络超时");
+                        onInitFail();
+                        break;
+                    default:
+                        Log.i(TAG,"其他错误:" + paramInt);
+                        CrashHandler.getInstance().saveCrashInfoToWeb("初始化失败,其他错误:" + paramInt);
+                        onInitFail();
+                        break;
+                }
+            }
+        });
+    }
+
+
+    private void onInitFail(){
+        new AlertDialog.Builder(this)
+                .setMessage("初始化失败,点击'确定'退出")
+                .setPositiveButton("确定",new DialogInterface.OnClickListener(){
+
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        MainActivity.this.finish();
+                    }
+                }).show();
+    }
+
+    private void getBuyProductId(@NonNull AuthResult authResult){
+        if(authResult.productInfos.length>0){
+            buyProductId = authResult.productInfos[0].productId;
+            //Toast("计费产品ID:" + buyProductId);
+       }else{
+            CrashHandler.getInstance().saveCrashInfoToWeb("计费失败,未检测到产品列表,用户ID:" + userId);
+            Toast("没有检测到产品列表,不能发起计费!");
+        }
+
+    }
+
+    private void monthPay(){
+        Logger("开始计费");
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                HuaweiPay.getInstance().payForMonth(MainActivity.this,userId,buyProductId,new CallbackListener<PayResult>()
+                {
+                    @Override
+                    public void callback(final int arg0, PayResult arg1)
+                    {
+                        switch(arg0){
+                            case ErrorCode.COM_PLATFORM_SUCCESS:
+                       /* Log.i(TAG,"计费成功,用户ID:" + arg1.getUin()
+                                +";流水号:" + arg1.getConsumeStreamId() + ";商户收入:" + arg1.getShare());*/
+                                myPayResult.onSuccess();
+                                break;
+                            case ErrorCode.COM_PLATFORM_ERROR_PARAM:
+                                myPayResult.onFail("参数错误");
+                                break;
+                            case ErrorCode.COM_PLATFORM_ERROR_UNKNOWN:
+                                myPayResult.onFail("SDK未初始化及其它错误,tradeStatus:" + arg1.getTradeStatus());
+                                break;
+                            case ErrorCode.COM_PLATFORM_ERROR_PAY_CANCEL:
+                                myPayResult.onFail("用户取消" + arg1.getTradeStatus());
+                                break;
+                            default:
+                                myPayResult.onFail("计费未知错误:" + arg0);
+                                break;
+                        }
+                        if (null != arg1)
+                        {
+                            Logger.d(TAG, "unipayExt PayResult : "+ arg1);
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+    private void runH5(){
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                loadH5Url();
+            }
+        });
+    }
+
+
+
+    private void Toast(final String msg){
+        MainActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    public class AndroidToJs{
+        H5Result listener;
+        MyPayResult payResult;
+        public AndroidToJs(H5Result h5Result,MyPayResult payResult){
+            this.listener = h5Result;
+            this.payResult = payResult;
+        }
+
+        @JavascriptInterface
+        public void play(final String url,final String title,final String sourceId){
+            listener.videoPlay(url,title,userId,sourceId);
+        }
+
+        @JavascriptInterface
+        public void pay(String backUrl){
+            //Toast.makeText(MainActivity.this,"开始计费",Toast.LENGTH_SHORT).show();
+            Log.d(TAG,"限时订购计费");
+            MainActivity.this.backUrl = backUrl;
+            gotoPayActivity(userId,buyProductId);
+        }
+
+        @JavascriptInterface
+        public int getScreenWidth(){
+            return getWindowManager().getDefaultDisplay().getWidth();
+        }
+
+        @JavascriptInterface
+        public void exit(){
+            //todo run in ui thread
+            new AlertDialog.Builder(MainActivity.this)
+                    .setMessage("确认退出!")
+                    .setPositiveButton("继续观看", new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+
+                        }
+                    }).setNegativeButton("立即退出", new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    MainActivity.this.finish();
+                }
+            }).show();
+        }
+
+        @JavascriptInterface
+        public void jsAuth(){
+            HuaweiPay.getInstance().authForMonth(new CallbackListener<AuthResult>() {
+                @Override
+                public void callback(int i, AuthResult authResult) {
+                    if(i == ErrorCode.COM_PLATFORM_SUCCESS){
+                        onAuthResult(1);
+                    }else{
+                        onAuthResult(-1);
+                    }
+                }
+            });
+        }
+
+        @JavascriptInterface
+        public int  getVipState(){
+            boolean vipState = new LocalStore(MainActivity.this).getIsVip();
+            Logger("vipState:" + (vipState?"是":"否"));
+            return vipState?1:-1;
+        }
+    }
+
+    @Override
+    protected void onDestroy(){
+        //清空所有Cookie
+        CookieSyncManager.createInstance(this);  //Create a singleton CookieSyncManager within a context
+        CookieManager cookieManager = CookieManager.getInstance(); // the singleton CookieManager instance
+        cookieManager.removeAllCookie();// Removes all cookies.
+        CookieSyncManager.getInstance().sync(); // forces sync manager to sync now
+
+        if(webview != null){
+            webview.clearCache(true);
+            webview.clearFormData();
+            webview.clearMatches();
+            webview.clearSslPreferences();
+            webview.clearDisappearingChildren();
+            webview.clearHistory();
+            webview.clearAnimation();
+            webview.loadUrl("about:blank");
+            webview.removeAllViews();
+            webview.freeMemory();
+
+            webview.setWebChromeClient(null);
+            webview.setWebViewClient(null);
+            webview.getSettings().setJavaScriptEnabled(false);
+            webview.clearCache(true);
+            webview = null;
+        }
+
+        HuaweiPay.getInstance().onDestroy();
+        super.onDestroy();
+
+    }
+
+    @Override
+    public void onBackPressed() {
+        onJsBack();
+    }
+
+    private void onJsBack(){
+        final int version = Build.VERSION.SDK_INT;
+        if(version>18){
+            webview.evaluateJavascript("javascript:onBack()", new ValueCallback<String>() {
+                @Override
+                public void onReceiveValue(String value) {
+                    //此处为 js 返回的结果
+                }
+            });
+        }else{
+            webview.loadUrl("javascript:onBack()");
+        }
+    }
+
+    private void onJsFresh(){
+        final int version = Build.VERSION.SDK_INT;
+        if(version>18){
+            webview.evaluateJavascript("javascript:myrefresh()", new ValueCallback<String>() {
+                @Override
+                public void onReceiveValue(String value) {
+                    //此处为 js 返回的结果
+                }
+            });
+        }else{
+            webview.loadUrl("javascript:myrefresh()");
+        }
+    }
+
+    private void onPlayBackPay(){
+        final int version = Build.VERSION.SDK_INT;
+        if(version>18){
+            webview.evaluateJavascript("javascript:onPlayBackPay()", new ValueCallback<String>() {
+                @Override
+                public void onReceiveValue(String value) {
+                    //此处为 js 返回的结果
+                }
+            });
+        }else{
+            webview.loadUrl("javascript:onPlayBackPay()");
+        }
+    }
+
+
+    private void onAuthResult(final int i){
+        MainActivity.this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final int version = Build.VERSION.SDK_INT;
+                String script = "javascript:onAuthResult(" + i +")";
+                if(version>18){
+                    webview.evaluateJavascript(script, new ValueCallback<String>() {
+                        @Override
+                        public void onReceiveValue(String value) {
+                            //此处为 js 返回的结果
+                        }
+                    });
+                }else{
+                    webview.loadUrl(script);
+                }
+            }
+        });
+
+    }
+
+    public interface H5Result {
+        public void videoPlay(String url,String title,String uId,String sourceId);
+    }
+
+    public interface MyPayResult{
+        public void onSuccess();
+        public void onFail(String msg);
+    }
+}
+
+

+ 99 - 0
app/src/main/java/com/haochuan/dudutoy/PayActivity.java

@@ -0,0 +1,99 @@
+package com.haochuan.dudutoy;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.odin.framework.plugable.Logger;
+import com.sdk.commplatform.entry.AuthResult;
+import com.sdk.commplatform.entry.ErrorCode;
+import com.sdk.commplatform.entry.PayResult;
+import com.sdk.commplatform.listener.CallbackListener;
+
+public class PayActivity extends Activity {
+    String userId = "";
+    String buyProductId = "";
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_pay);
+        userId = getIntent().getStringExtra("userId");
+        buyProductId = getIntent().getStringExtra("buyProductId");
+        prepare();
+
+    }
+
+    private void prepare(){
+        HuaweiPay.getInstance().init(this, new CallbackListener<Integer>()
+        {
+            @Override
+            public void callback(final int paramInt, final Integer paramT)
+            {
+                switch (paramInt){
+                    case ErrorCode.COM_PLATFORM_SUCCESS:
+                        //Toast("初始化成功");
+                        monthPay();
+                        break;
+                    case ErrorCode.COM_PLATFORM_ERROR_ONLINE_CHECK_FAILURE:
+                        break;
+                    case ErrorCode.COM_PLATFORM_ERROR_FORCE_CLOSE:
+                        break;
+                    case ErrorCode.COM_PLATFORM_ERROR_TIME_OUT:
+
+                        break;
+                    default:
+
+                        break;
+                }
+            }
+        });
+    }
+
+    private void monthPay(){
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                HuaweiPay.getInstance().payForMonth(PayActivity.this,userId,buyProductId,new CallbackListener<PayResult>()
+                {
+                    @Override
+                    public void callback(final int arg0, PayResult arg1)
+                    {
+                        switch(arg0){
+                            case ErrorCode.COM_PLATFORM_SUCCESS:
+                       /* Log.i(TAG,"计费成功,用户ID:" + arg1.getUin()
+                                +";流水号:" + arg1.getConsumeStreamId() + ";商户收入:" + arg1.getShare());*/
+                                paySuccessResult();
+                                break;
+                            case ErrorCode.COM_PLATFORM_ERROR_PARAM:
+                                payFailResult();
+                                break;
+                            case ErrorCode.COM_PLATFORM_ERROR_UNKNOWN:
+                                payFailResult();
+                                break;
+                            case ErrorCode.COM_PLATFORM_ERROR_PAY_CANCEL:
+                                payFailResult();
+                                break;
+                            default:
+                                payFailResult();
+                                break;
+                        }
+                        if (null != arg1)
+                        {
+
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+   private void paySuccessResult(){
+       new LocalStore(this).saveIsVip(true);
+       finish();
+   }
+
+    private void payFailResult(){
+        new LocalStore(this).saveIsVip(false);
+        finish();
+    }
+}

+ 8 - 0
app/src/main/java/com/haochuan/dudutoy/StringUtils.java

@@ -0,0 +1,8 @@
+package com.haochuan.dudutoy;
+
+/**
+ * Created by 浩传 on 2018/6/7.
+ */
+
+class StringUtils {
+}

+ 14 - 0
app/src/main/java/com/haochuan/dudutoy/StyleData.java

@@ -0,0 +1,14 @@
+package com.haochuan.dudutoy;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.Serializable;
+
+/**
+ * Created by yunhaipiaodi on 2017/9/20.
+ */
+
+public class StyleData implements Serializable {
+    @SerializedName("code")     public int code = 0;
+    @SerializedName("msg")      public String msg = "";
+}

+ 43 - 0
app/src/main/java/com/haochuan/dudutoy/TestUnsubscribe.java

@@ -0,0 +1,43 @@
+package com.haochuan.dudutoy;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.sdk.commplatform.entry.ErrorCode;
+import com.sdk.commplatform.entry.PayResult;
+import com.sdk.commplatform.listener.CallbackListener;
+
+public class TestUnsubscribe extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_test_unsubscribe);
+        Button unSubscribe = findViewById(R.id.unsubscribe);
+
+        unSubscribe.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+               HuaweiPay.getInstance().unSubscribe(TestUnsubscribe.this, "B702207712043108", new CallbackListener<PayResult>() {
+                    @Override
+                    public void callback(int i, PayResult payResult) {
+                        if(i == ErrorCode.COM_PLATFORM_SUCCESS){
+                            TestUnsubscribe.this.runOnUiThread(new Runnable() {
+                                @Override
+                                public void run() {
+                                    Toast.makeText(TestUnsubscribe.this,"取消订购平台已受理",Toast.LENGTH_SHORT).show();
+                                }
+                            });
+                        }else{
+                            Log.i("TestUnsubscribe","取消订购失败:" + i);
+                        }
+                    }
+                });
+            }
+        });
+    }
+}

+ 25 - 0
app/src/main/java/com/haochuan/dudutoy/ToyApplication.java

@@ -0,0 +1,25 @@
+package com.haochuan.dudutoy;
+
+import android.app.Application;
+import android.content.Context;
+
+import java.net.Proxy;
+
+/**
+ * Created by 浩传 on 2018/7/2.
+ */
+
+public class ToyApplication extends Application {
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        initCrashHandler();
+    }
+
+    private void initCrashHandler(){
+        CrashHandler crashHandler = CrashHandler.getInstance();
+        crashHandler.init(getApplicationContext());
+    }
+}

+ 29 - 0
app/src/main/java/com/haochuan/dudutoy/UrlManager.java

@@ -0,0 +1,29 @@
+package com.haochuan.dudutoy;
+
+/**
+ * Created by Lyn on 2018/5/30.
+ */
+
+public class UrlManager {
+    private String host = "http://202.99.114.74:56199/";
+
+    public String getCollectedStateUrl(String uId,String sourceId){
+        return host + "index.php?m=Home&c=DuduApi&a=isCollect"
+                + "&uid=" + uId
+                +"&source_id=" + sourceId;
+    }
+
+    public String addCollectedStateUrl(String uId,String sourceId,int type){
+        return host + "index.php?m=Home&c=DuduApi&a=upWatchCollectLog"
+                + "&type=" + type
+                + "&uid=" + uId
+                +"&source_id=" + sourceId;
+    }
+
+    public String cancelCollectedStateUrl(String uId,String sourceId,int type){
+        return host + "index.php?m=Home&c=DuduApi&a=delWatchCollectLog"
+                + "&type=" + type
+                + "&uid=" + uId
+                +"&source_id=" + sourceId;
+    }
+}

+ 336 - 0
app/src/main/java/com/haochuan/dudutoy/VideoEndDialog.java

@@ -0,0 +1,336 @@
+package com.haochuan.dudutoy;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+import com.android.volley.toolbox.Volley;
+
+import org.json.JSONObject;
+import org.w3c.dom.Text;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+
+/**
+ * Created by yunhaipiaodi on 2017/10/13.
+ */
+
+public class VideoEndDialog extends DialogFragment{
+
+    private static String PARAM1 = "uid";
+    private static String PARAM2 = "sourceId";
+    private static String PARAM3 = "isComplete";
+
+    private String uId = "";
+    private String sourceId = "";
+    private Boolean isComplete = false;
+
+    private OnClickListener mListener;
+    private RequestQueue queue;
+
+    private LinearLayout collectContainer;
+    private ImageView collectIcon;
+    private TextView collectTitle;
+
+    private long  mLastClickTime = 0;
+
+    public static VideoEndDialog getInstance(String uId,String sourceId,Boolean isComplete){
+        VideoEndDialog videoEndDialog = new VideoEndDialog();
+        Bundle bundle = new Bundle();
+        bundle.putString(PARAM1,uId);
+        bundle.putString(PARAM2,sourceId);
+        bundle.putBoolean(PARAM3,isComplete);
+        videoEndDialog.setArguments(bundle);
+        return videoEndDialog;
+    }
+
+
+    @Override
+    public void onAttach(Activity activity){
+        super.onAttach(activity);
+        queue = Volley.newRequestQueue(activity);
+        if(activity instanceof OnClickListener){
+            mListener = (OnClickListener)activity;
+        }else{
+            throw new RuntimeException(activity.toString()
+                    + " must implement VideoEndDialog.OnClickListener");
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState){
+        super.onCreate(savedInstanceState);
+        this.setCancelable(false);
+        uId = getArguments().getString(PARAM1);
+        sourceId = getArguments().getString(PARAM2);
+        isComplete = getArguments().getBoolean(PARAM3);
+    }
+
+    @Override
+    public void onStart(){
+        super.onStart();
+        mLastClickTime = getCurrentTime();
+        //Toast.makeText(getActivity(),"mLastClickTime:" + mLastClickTime,Toast.LENGTH_LONG ).show();
+    }
+
+
+    private int getCurrentTime(){
+        int currentTime = 0;
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HHmmss");
+        currentTime = Integer.parseInt(simpleDateFormat.format(new Date()));
+        return currentTime;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState)
+    {
+        Dialog dialog = getDialog();
+        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
+            @Override
+            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                switch (keyCode){
+                    case KeyEvent.KEYCODE_BACK:
+                        if (getCurrentTime() - mLastClickTime < 2) {
+                            return false;
+                        }else{
+                            VideoEndDialog.this.dismiss();
+                            return true;
+                        }
+                }
+                return false;
+            }
+        });
+
+        View view = inflater.inflate(R.layout.dialog_video_end, container);
+        LinearLayout continueBtn = view.findViewById(R.id.continue_play);
+        collectContainer = view.findViewById(R.id.collect_video);
+        LinearLayout exitBtn = view.findViewById(R.id.exit_play);
+        collectIcon = view.findViewById(R.id.collect_icon);
+        collectTitle = view.findViewById(R.id.collect_title);
+
+        if(isComplete){
+            continueBtn.setVisibility(View.INVISIBLE);
+        }
+
+        getCollectState(new OnCollectListener(){
+
+            @Override
+            public void onCollected(boolean result) {
+                if(result){     //已经收藏
+                    collectSet();
+                    collectContainer.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            cancelCollectStateToWeb();
+                        }
+                    });
+                }else{          //未收藏
+                    noCollectSet();
+                    collectContainer.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            addCollectStateToWeb();
+                        }
+                    });
+                }
+            }
+        });
+
+        continueBtn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                VideoEndDialog.this.dismiss();
+                mListener.onContinuePlay();
+            }
+        });
+
+        exitBtn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mListener.onExit();
+            }
+        });
+
+        continueBtn.requestFocus();
+        return view;
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        super.onDismiss(dialog);
+        if(mListener!=null){
+            mListener.onDismiss();
+        }
+    }
+
+    //没收藏时的设置
+    private void noCollectSet(){
+        collectTitle.setText("加入收藏");
+        collectTitle.setTextColor(getActivity().getResources().getColor(R.color.video_end_text_color));
+        collectIcon.setImageResource(R.drawable.btn_icon_add_default);
+    }
+
+    //已收藏时的设置
+    private void collectSet(){
+        collectTitle.setText("取消收藏");
+        collectTitle.setTextColor(getActivity().getResources().getColor(R.color.video_end_text_color));
+        collectIcon.setImageResource(R.drawable.btn_icon_add_selected);
+    }
+
+    public void getCollectState(final OnCollectListener listener ){
+        final String requestUrl = new UrlManager().getCollectedStateUrl(uId,sourceId);
+        queue.add(new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
+            @Override
+            public void onResponse(JSONObject response) {
+                if(response.has("code")){
+                    try{
+                        int code = response.getInt("code");
+                        switch (code){
+                            case 1:
+                                listener.onCollected(false);
+                                break;
+                            case 2:
+                                listener.onCollected(true);
+                                break;
+                            default:
+                                listener.onCollected(false);
+                                break;
+                        }
+                    }catch (Exception e){
+                        listener.onCollected(false);
+                        e.printStackTrace();
+                    }
+
+                }
+            }
+        }, new Response.ErrorListener() {
+            @Override
+            public void onErrorResponse(VolleyError error) {
+
+            }
+        }));
+    }
+
+    private void addCollectStateToWeb(){
+        final String requestUrl = new UrlManager().addCollectedStateUrl(uId,sourceId,2);
+        queue.add(new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
+            @Override
+            public void onResponse(JSONObject response) {
+                if(response.has("code")){
+                    try{
+                        int code = response.getInt("code");
+                        if(code == 0){
+                            collectSet();
+                            collectContainer.setOnClickListener(new View.OnClickListener() {
+                                @Override
+                                public void onClick(View v) {
+                                    cancelCollectStateToWeb();
+                                }
+                            });
+                        }else{
+                            Toast.makeText(getActivity(),"收藏失败",Toast.LENGTH_SHORT).show();
+                        }
+                    }catch (Exception e){
+                        e.printStackTrace();
+                    }
+
+                }
+            }
+        }, new Response.ErrorListener() {
+            @Override
+            public void onErrorResponse(VolleyError error) {
+
+            }
+        }));
+    }
+
+    private void cancelCollectStateToWeb(){
+        final String requestUrl = new UrlManager().cancelCollectedStateUrl(uId,sourceId,2);
+        queue.add(new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
+            @Override
+            public void onResponse(JSONObject response) {
+                if(response.has("code")){
+                    try{
+                        int code = response.getInt("code");
+                        if(code == 0){
+                            noCollectSet();
+                            collectContainer.setOnClickListener(new View.OnClickListener() {
+                                @Override
+                                public void onClick(View v) {
+                                    addCollectStateToWeb();
+                                }
+                            });
+                        }else{
+                            Toast.makeText(getActivity(),"取消收藏失败",Toast.LENGTH_SHORT).show();
+                        }
+                    }catch (Exception e){
+                        e.printStackTrace();
+                    }
+
+                }
+            }
+        }, new Response.ErrorListener() {
+            @Override
+            public void onErrorResponse(VolleyError error) {
+
+            }
+        }));
+    }
+
+    @Override
+    public void show(FragmentManager manager, String tag) {
+        try {
+            //在每个add事务前增加一个remove事务,防止连续的add
+            manager.beginTransaction().remove(this).commitAllowingStateLoss();
+            super.show(manager, tag);
+        } catch (Exception e) {
+            //同一实例使用不同的tag会异常,这里捕获一下
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void onDestroy(){
+        collectContainer= null;
+        collectIcon = null;
+        collectTitle = null;
+        super.onDestroy();
+    }
+
+    public interface OnCollectListener{
+        public void onCollected(boolean result);
+    }
+
+    public interface OnClickListener{
+        public void onExit();
+        public void onDismiss();
+        public void onContinuePlay();
+    }
+
+}

+ 298 - 0
app/src/main/java/com/haochuan/dudutoy/VideoPlayerActivity.java

@@ -0,0 +1,298 @@
+package com.haochuan.dudutoy;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.JsonObjectRequest;
+import com.android.volley.toolbox.Volley;
+import com.odin.framework.plugable.Logger;
+import com.sdk.commplatform.entry.ErrorCode;
+import com.sdk.commplatform.entry.PayResult;
+import com.sdk.commplatform.listener.CallbackListener;
+import com.shuyu.gsyvideoplayer.GSYVideoADManager;
+import com.shuyu.gsyvideoplayer.GSYVideoManager;
+import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
+
+import org.json.JSONObject;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class VideoPlayerActivity extends Activity implements VideoEndDialog.OnClickListener{
+
+    String uId = "";
+    String sourceId = "";
+
+    private boolean showVideoEndDialog = false;
+    DuduPlayer duduPlayer;
+
+    private int seekPercent = 5;
+
+    private Timer timer_pay;
+    private TimerTask task_pay;
+
+    String TAG = "VideoPlayerActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_video_player);
+        String url = getIntent().getStringExtra("url");
+        String title = getIntent().getStringExtra("title");
+        uId = getIntent().getStringExtra("uId");
+        sourceId = getIntent().getStringExtra("sourceId");
+       /* url = "http://202.99.114.93/88888891/16/20171229/269788225/269788225.ts";
+        title = "小小战士";*/
+        duduPlayer = findViewById(R.id.video_player);
+        duduPlayer.setUp(url, false,title);
+        duduPlayer.clickStartIcon();
+
+        duduPlayer.setOnCompleteListener(new DuduPlayer.OnCompleteListener() {
+            @Override
+            public void onComplete() {
+                new Handler().postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        VideoPlayerActivity.this.runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                showVideoEndDialogComplete();
+                            }
+                        });
+                    }
+                },1000);
+
+            }
+        });
+        addHistoryToWeb();
+
+        if(!new LocalStore(this).getIsVip()){
+            initPayTimeTask();
+            Toast.makeText(this,"您还不是会员,您只可以试看30秒视频!并且不能快进",Toast.LENGTH_LONG).show();
+        }
+    }
+
+
+    private void addHistoryToWeb(){
+        final String requestUrl = new UrlManager().addCollectedStateUrl(uId,sourceId,1);
+        RequestQueue queue = Volley.newRequestQueue(this);
+        queue.add(new JsonObjectRequest(Request.Method.GET, requestUrl, null, new Response.Listener<JSONObject>() {
+            @Override
+            public void onResponse(JSONObject response) {
+
+            }
+        }, new Response.ErrorListener() {
+            @Override
+            public void onErrorResponse(VolleyError error) {
+
+            }
+        }));
+    }
+
+    //遥控事件
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:      //播放/暂停
+                playOrPause();
+                return true;
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if(duduPlayer.canSeek()){
+                    seekBack();
+                }else{
+                    //Toast.makeText(VideoPlayerActivity.this,"视频准备中,暂时不能拖动快进",Toast.LENGTH_SHORT).show();
+                }
+                return true;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if(duduPlayer.canSeek()){
+                    seekForward();
+                }else{
+                    //Toast.makeText(VideoPlayerActivity.this,"视频准备中,暂时不能拖动快进",Toast.LENGTH_SHORT).show();
+                }
+                return true;
+            case KeyEvent.KEYCODE_BACK:      //到顶跳到相应tab
+                duduPlayer.pause();
+                if(!showVideoEndDialog){
+                    if(Build.VERSION.SDK_INT> 15){
+                        showVideoEndDialog();
+                    }else{
+                        VideoPlayerActivity.this.finish();
+                    }
+                    //Toast.makeText(this,"显示VideoEndDialog",Toast.LENGTH_SHORT).show();
+                    return true;
+                }else{
+                    return false;
+                }
+        }
+        return false;
+    }
+
+    private void playOrPause(){
+       duduPlayer.playOrPause();
+    }
+
+    private void seekBack(){
+        if(!new LocalStore(this).getIsVip()){
+            return;
+        }
+        int seekCount = duduPlayer.getDuration()*seekPercent/100;
+        int position = 0;
+        if(duduPlayer.getCurrentPositionWhenPlaying() - seekCount > 0) {
+            position = (duduPlayer.getCurrentPositionWhenPlaying() - seekCount) * 1000/ duduPlayer.getDuration();
+        }
+        if(position<= 0){
+            return;
+        }
+        duduPlayer.seek(position);
+    }
+
+    private void seekForward(){
+        if(!new LocalStore(this).getIsVip()){
+            return;
+        }
+        int seekCount = duduPlayer.getDuration()*seekPercent/100;
+        int position = duduPlayer.getDuration();
+        if(duduPlayer.getCurrentPositionWhenPlaying() + seekCount <= duduPlayer.getDuration()) {
+            position = (duduPlayer.getCurrentPositionWhenPlaying() + seekCount) *1000/ duduPlayer.getDuration();
+        }
+        if(position>=1000){
+            return;
+        }
+        duduPlayer.seek(position);
+    }
+
+
+    private void showVideoEndDialog(){
+        try{
+            VideoEndDialog videoEndDialog =  VideoEndDialog.getInstance(uId,sourceId,false);
+            videoEndDialog.show(getFragmentManager(),"VideoEndDialog");
+            showVideoEndDialog = true;
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    private void showVideoEndDialogComplete(){
+        try{
+            VideoEndDialog videoEndDialog =  VideoEndDialog.getInstance(uId,sourceId,true);
+            videoEndDialog.show(getFragmentManager(),"VideoEndDialog");
+            showVideoEndDialog = true;
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    //非会员视频播放到30秒
+    private void initPayTimeTask(){
+        timer_pay = new Timer();
+        task_pay = new TimerTask() {
+            @Override
+            public void run() {
+                new Thread(){
+                    public void run(){
+                        Looper.prepare();
+                        new Handler().post(
+                                new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        //Toast.makeText(CntvPlayerActivity.this,"监控计费时间",Toast.LENGTH_SHORT).show();
+                                        int pos = duduPlayer.getCurrentPositionWhenPlaying();
+                                        if(pos/1000 > 30){
+                                            //跳转到计费界面
+                                            VideoPlayerActivity.this.runOnUiThread(new Runnable() {
+                                                @Override
+                                                public void run() {
+                                                    setResult(3);
+                                                    VideoPlayerActivity.this.finish();
+                                                }
+                                            });
+                                        }
+                                    }
+                                });
+                        Looper.loop();
+                    }
+                }.start();
+
+            }
+        };
+        timer_pay.schedule(task_pay,0,1000);
+    }
+
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if(duduPlayer != null){
+            duduPlayer.pause();
+        }
+    }
+
+
+
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if(duduPlayer != null){
+            duduPlayer.play();
+        }
+    }
+
+    @Override
+    protected void onStop(){
+        super.onStop();
+        this.finish();
+    }
+
+    @Override
+    protected void onDestroy() {
+        duduPlayer.setVideoAllCallBack(null);
+        GSYVideoManager.releaseAllVideos();
+        duduPlayer.onDestroy();
+
+        duduPlayer = null;
+        if(timer_pay != null){
+            timer_pay.cancel();
+        }
+        if(task_pay != null){
+            task_pay.cancel();
+        }
+        task_pay = null;
+        timer_pay = null;
+        super.onDestroy();
+    }
+
+    @Override
+    public void onExit() {
+        this.finish();
+    }
+
+    @Override
+    public void onDismiss() {
+        showVideoEndDialog = false;
+        if(duduPlayer!=null){
+            duduPlayer.play();
+        }
+    }
+
+    @Override
+    public void onContinuePlay() {
+        if(duduPlayer != null){
+            duduPlayer.play();
+        }
+    }
+}

BIN
app/src/main/res/drawable-hdpi/btn_icon_add_default.png


BIN
app/src/main/res/drawable-hdpi/btn_icon_add_selected.png


BIN
app/src/main/res/drawable-hdpi/btn_icon_continue.png


BIN
app/src/main/res/drawable-hdpi/btn_icon_out.png


BIN
app/src/main/res/drawable-hdpi/btn_icon_right.png


BIN
app/src/main/res/drawable-hdpi/btn_icon_stop.png


BIN
app/src/main/res/drawable-hdpi/loading_1.png


BIN
app/src/main/res/drawable-hdpi/loading_2.png


BIN
app/src/main/res/drawable-hdpi/logo1.png


BIN
app/src/main/res/drawable-hdpi/logo2.png


BIN
app/src/main/res/drawable-hdpi/logo_icon_down.png


BIN
app/src/main/res/drawable-hdpi/logo_icon_left.png


BIN
app/src/main/res/drawable-hdpi/logo_icon_ok.png


BIN
app/src/main/res/drawable-hdpi/logo_icon_right.png


BIN
app/src/main/res/drawable-ldpi/btn_icon_add_default.png


BIN
app/src/main/res/drawable-ldpi/btn_icon_add_selected.png


BIN
app/src/main/res/drawable-ldpi/btn_icon_continue.png


BIN
app/src/main/res/drawable-ldpi/btn_icon_out.png


BIN
app/src/main/res/drawable-ldpi/btn_icon_right.png


BIN
app/src/main/res/drawable-ldpi/btn_icon_stop.png


BIN
app/src/main/res/drawable-ldpi/loading_1.png


BIN
app/src/main/res/drawable-ldpi/loading_2.png


BIN
app/src/main/res/drawable-ldpi/logo1.png


BIN
app/src/main/res/drawable-ldpi/logo2.png


BIN
app/src/main/res/drawable-ldpi/logo_icon_down.png


BIN
app/src/main/res/drawable-ldpi/logo_icon_left.png


BIN
app/src/main/res/drawable-ldpi/logo_icon_ok.png


BIN
app/src/main/res/drawable-ldpi/logo_icon_right.png


BIN
app/src/main/res/drawable-mdpi/btn_icon_add_default.png


BIN
app/src/main/res/drawable-mdpi/btn_icon_add_selected.png


BIN
app/src/main/res/drawable-mdpi/btn_icon_continue.png


BIN
app/src/main/res/drawable-mdpi/btn_icon_out.png


BIN
app/src/main/res/drawable-mdpi/btn_icon_right.png


BIN
app/src/main/res/drawable-mdpi/btn_icon_stop.png


BIN
app/src/main/res/drawable-mdpi/loading_1.png


BIN
app/src/main/res/drawable-mdpi/loading_2.png


BIN
app/src/main/res/drawable-mdpi/logo1.png


BIN
app/src/main/res/drawable-mdpi/logo2.png


BIN
app/src/main/res/drawable-mdpi/logo_icon_down.png


BIN
app/src/main/res/drawable-mdpi/logo_icon_left.png


BIN
app/src/main/res/drawable-mdpi/logo_icon_ok.png


BIN
app/src/main/res/drawable-mdpi/logo_icon_right.png


BIN
app/src/main/res/drawable-xhdpi/btn_icon_add_default.png


BIN
app/src/main/res/drawable-xhdpi/btn_icon_add_selected.png


BIN
app/src/main/res/drawable-xhdpi/btn_icon_continue.png


BIN
app/src/main/res/drawable-xhdpi/btn_icon_out.png


BIN
app/src/main/res/drawable-xhdpi/btn_icon_right.png


BIN
app/src/main/res/drawable-xhdpi/btn_icon_stop.png


BIN
app/src/main/res/drawable-xhdpi/loading_1.png


BIN
app/src/main/res/drawable-xhdpi/loading_2.png


BIN
app/src/main/res/drawable-xhdpi/logo1.png


BIN
app/src/main/res/drawable-xhdpi/logo2.png


BIN
app/src/main/res/drawable-xhdpi/logo_icon_down.png


BIN
app/src/main/res/drawable-xhdpi/logo_icon_left.png


BIN
app/src/main/res/drawable-xhdpi/logo_icon_ok.png


BIN
app/src/main/res/drawable-xhdpi/logo_icon_right.png


+ 0 - 0
app/src/main/res/drawable-xxhdpi/btn_icon_add_default.png


Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott