├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── xigua
│ │ └── test
│ │ └── MainActivity.java
│ └── res
│ ├── drawable
│ └── ic_launcher_web.png
│ ├── layout
│ └── activity_main.xml
│ └── values
│ └── strings.xml
├── build.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── xigua
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── xigua
│ └── p2p
│ ├── InfoThread.java
│ ├── NetWorkChangeReceiver.java
│ ├── P2PClass.java
│ ├── P2PManager.java
│ ├── P2PMessageWhat.java
│ ├── P2PService.java
│ ├── StorageUtils.java
│ ├── TaskVideoInfo.java
│ ├── TaskVideoList.java
│ └── XiguaProvider.java
└── jniLibs
└── armeabi
└── libp2p.so
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /gradle
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # XiguaP2p
2 | 【次元番】使用的西瓜视频P2P库,用来缓存 xg:// xgadd:// xgplay:// 开头的ftp视频文件连接。并提供本地播放链接代理,实现边下边播的功能
3 |
4 | 基本使用
5 | ========
6 | XiguaProvider已经完成过库的初始化,所以无需重复调用P2PManager.getInstance().init(getContext());
7 | P2PManager.getInstance().play("");//开始下载/播放西瓜ftp视频文件
8 | P2PManager.getInstance().stop("");//停止
9 | P2PManager.getInstance().remove("");删除
10 |
11 | 注意
12 | ======
13 | 因为[P2PService](https://github.com/fanchen001/XiguaP2p/blob/master/xigua/src/main/java/com/xigua/p2p/P2PService.java)运行于单独的进程,
14 | 所以所有对[P2PManager](https://github.com/fanchen001/XiguaP2p/blob/master/xigua/src/main/java/com/xigua/p2p/P2PManager.java)的操作结果,
15 | 均以广播的形式反馈给调用者。具体广播参数,请看[P2PMessageWhat](https://github.com/fanchen001/XiguaP2p/blob/master/xigua/src/main/java/com/xigua/p2p/P2PMessageWhat.java),
16 | 其他使用方法,请查看[次元番](https://github.com/fanchen001/Bangumi)
17 |
18 | 添加依赖
19 | ========
20 |
21 |
22 | Add it in your root build.gradle at the end of repositories:
23 |
24 | allprojects {
25 | repositories {
26 | ...
27 | maven { url 'https://www.jitpack.io' }
28 | }
29 | }
30 | Step 2. Add the dependency
31 |
32 | dependencies {
33 | implementation 'com.github.fanchen001:XiguaP2p:1.10.25'
34 | }
35 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /test
3 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.xigua.test"
7 | minSdkVersion 19
8 | targetSdkVersion 26
9 | versionCode 20181022
10 | versionName "0.10.22"
11 | }
12 | buildTypes {
13 | release {
14 | minifyEnabled false
15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
16 | }
17 | }
18 | }
19 |
20 | dependencies {
21 | compile project(path: ':xigua')
22 | }
23 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xigua/test/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xigua.test;
2 |
3 | import android.app.Activity;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.os.Bundle;
9 | import android.os.SystemClock;
10 | import android.widget.TextView;
11 |
12 | import com.xigua.p2p.P2PManager;
13 | import com.xigua.p2p.P2PMessageWhat;
14 |
15 | public class MainActivity extends Activity {
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_main);
21 | //SDK 的初始化需要时间
22 | new Thread(){
23 |
24 | @Override
25 | public void run() {
26 | SystemClock.sleep(3000);
27 | String url = "xg://a.gbl.114s.com:20320/9847/魔法禁书目录第三季03.mp4";
28 | P2PManager.getInstance().play(url.replace("xg://","ftp://"));
29 | }
30 | }.start();
31 | registerReceiver(receiver,new IntentFilter(P2PMessageWhat.P2P_CALLBACK));
32 | }
33 |
34 | @Override
35 | protected void onDestroy() {
36 | super.onDestroy();
37 | unregisterReceiver(receiver);
38 | }
39 |
40 | private BroadcastReceiver receiver = new BroadcastReceiver() {
41 |
42 | @Override
43 | public void onReceive(Context context, Intent intent) {
44 | int intExtra = intent.getIntExtra(P2PMessageWhat.WHAT, 0);
45 | if(P2PMessageWhat.MESSAGE_TASK_LIST == intExtra){
46 | ((TextView)findViewById(R.id.text1)).setText("MESSAGE_TASK_LIST : " + intent.getParcelableArrayListExtra(P2PMessageWhat.DATA).toString());
47 | }else if(P2PMessageWhat.MESSAGE_PLAY_URL == intExtra){
48 | ((TextView)findViewById(R.id.text1)).setText("MESSAGE_PLAY_URL : " + intent.getStringExtra(P2PMessageWhat.PLAY_URL));
49 | }else if(P2PMessageWhat.MESSAGE_SPEED == intExtra){
50 | ((TextView)findViewById(R.id.text1)).setText( "MESSAGE_SPEED : " + intent.getParcelableExtra(P2PMessageWhat.DATA).toString());
51 | }
52 | }
53 |
54 | };
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanchen001/XiguaP2p/71cc4aacf4a9abc2f66ab089ec8ad0a27ceccf84/app/src/main/res/drawable/ic_launcher_web.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | maven { url 'https://www.jitpack.io' }
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.0'
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | maven { url 'https://www.jitpack.io' }
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':xigua'
2 |
--------------------------------------------------------------------------------
/xigua/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /src/androidTest
3 | /src/test
4 |
--------------------------------------------------------------------------------
/xigua/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | group = 'com.github.fanchen001'
4 |
5 | android {
6 | compileSdkVersion 26
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.10.24"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | }
29 |
--------------------------------------------------------------------------------
/xigua/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/xigua/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/InfoThread.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Handler;
6 | import android.os.Message;
7 | import android.os.SystemClock;
8 |
9 | import java.util.concurrent.atomic.AtomicBoolean;
10 |
11 | /**
12 | * InfoThread
13 | * Created by fanchen on 2018/10/19.
14 | */
15 | public class InfoThread {
16 | private MainThreadHandler handler = new MainThreadHandler();
17 | private AtomicBoolean isRun = new AtomicBoolean(true);
18 | private Context mContext;
19 |
20 | public InfoThread(Context context) {
21 | mContext = context.getApplicationContext();
22 | }
23 |
24 | /**
25 | *发送下载速度广播
26 | */
27 | private void sendBroadcastSpeed() {
28 | if (mContext == null) return;
29 | P2PClass p2PClass = P2PClass.getInstance();
30 | long speed = p2PClass.P2Pgetspeed(-1);
31 | long percent = p2PClass.P2Pgetpercent();
32 | TaskVideoInfo localTaskVideoInfo = new TaskVideoInfo();
33 | localTaskVideoInfo.setSpeed(speed);
34 | localTaskVideoInfo.setPercent(percent);
35 | Intent intent = new Intent();
36 | intent.setAction(P2PMessageWhat.P2P_CALLBACK);
37 | intent.putExtra(P2PMessageWhat.WHAT, P2PMessageWhat.MESSAGE_SPEED);
38 | intent.putExtra(P2PMessageWhat.DATA, localTaskVideoInfo);
39 | mContext.sendBroadcast(intent);
40 | }
41 |
42 | public void start() {
43 | new Thread(new MainRunnable()).start();
44 | }
45 |
46 | public void stop() {
47 | isRun.set(false);
48 | }
49 |
50 | private class MainRunnable implements Runnable {
51 |
52 | @Override
53 | public void run() {
54 | try {
55 | int position = 0;
56 | while (isRun.get()) {
57 | SystemClock.sleep(2000L);//每2秒发送一次下载速度
58 | handler.sendEmptyMessage(P2PMessageWhat.MESSAGE_SPEED);
59 | if (position % 2 == 0) {//每4秒发送一次下载列表
60 | handler.sendEmptyMessage(P2PMessageWhat.MESSAGE_TASK_LIST);
61 | } else if (position % 5 == 0) {
62 | position = 0;//每10秒发送一次
63 | handler.sendEmptyMessage(P2PMessageWhat.MESSAGE_TASK_MSG);
64 | }
65 | position++;
66 | }
67 | } catch (Throwable e) {
68 | e.printStackTrace();
69 | }
70 | }
71 |
72 | }
73 |
74 | private class MainThreadHandler extends Handler {
75 |
76 | @Override
77 | public void handleMessage(Message message) {
78 | if (message.what == P2PMessageWhat.MESSAGE_TASK_LIST) {
79 | TaskVideoList.getInstance().sendBroadcastTaskList();
80 | } else if (message.what == P2PMessageWhat.MESSAGE_SPEED) {
81 | InfoThread.this.sendBroadcastSpeed();
82 | } else if (message.what == P2PMessageWhat.MESSAGE_TASK_MSG) {
83 | TaskVideoList.getInstance().checkFreeSize();
84 | }
85 | }
86 |
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/NetWorkChangeReceiver.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | /**
8 | * NetWorkChangeReceiver
9 | * Created by fanchen on 2018/10/19.
10 | */
11 | public class NetWorkChangeReceiver extends BroadcastReceiver {
12 |
13 | @Override
14 | public void onReceive(Context context, Intent intent) {
15 | Intent broadcast = new Intent();
16 | broadcast.setAction(P2PMessageWhat.P2P_CALLBACK);
17 | broadcast.putExtra(P2PMessageWhat.WHAT, P2PMessageWhat.MESSAGE_NETWORK_CHANGE);
18 | context.sendBroadcast(broadcast);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/P2PClass.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.os.StatFs;
4 |
5 | import java.io.File;
6 |
7 | /**
8 | * P2PClass
9 | * Created by fanchen on 2018/10/19.
10 | */
11 | public class P2PClass {
12 |
13 | private static P2PClass instance;
14 |
15 | static {
16 | try {
17 | System.loadLibrary("p2p");
18 | } catch (Throwable e) {
19 | e.printStackTrace();
20 | }
21 | }
22 |
23 | private P2PClass() {
24 | }
25 |
26 | public static P2PClass getInstance() {
27 | if (instance == null) {
28 | synchronized (P2PClass.class) {
29 | if (instance == null) {
30 | instance = new P2PClass();
31 | }
32 | }
33 | }
34 | return instance;
35 | }
36 |
37 | private final native int dosetupload(int var1);
38 |
39 | private final native int doxadd(byte[] var1);
40 |
41 | private final native int doxcheck(byte[] var1);
42 |
43 | private final native int doxdel(byte[] var1);
44 |
45 | private final native int doxdownload(byte[] var1);
46 |
47 | private final native int doxendhttpd();
48 |
49 | private final native int doxpause(byte[] var1);
50 |
51 | private final native int doxsave();
52 |
53 | private final native int doxsetduration(int var1);
54 |
55 | private final native int doxstart(byte[] var1);
56 |
57 | private final native int doxstarthttpd(byte[] var1);
58 |
59 | private final native int doxterminate();
60 |
61 | private final native long getdownsize(int var1);
62 |
63 | private final native long getfilesize(int var1);
64 |
65 | private final native long getlocalfilesize(byte[] var1);
66 |
67 | private final native int getpercent();
68 |
69 | private final native long getspeed(int var1);
70 |
71 | public long P2PGetFree() {
72 | StatFs var1 = new StatFs(StorageUtils.getCachePath());
73 | return var1.getAvailableBlocks() * var1.getBlockSize();
74 | }
75 |
76 | public long P2Pdosetduration(int var1) {
77 | return (long) this.doxsetduration(var1);
78 | }
79 |
80 | public int P2Pdosetupload(int var1) {
81 | return this.dosetupload(var1);
82 | }
83 |
84 | public int P2Pdoxadd(byte[] var1) {
85 | return this.doxadd(var1);
86 | }
87 |
88 | public int P2Pdoxcheck(byte[] var1) {
89 | return this.doxcheck(var1);
90 | }
91 |
92 | public int P2Pdoxdel(byte[] var1) {
93 | return this.doxdel(var1);
94 | }
95 |
96 | public int P2Pdoxdownload(byte[] var1) {
97 | return this.doxdownload(var1);
98 | }
99 |
100 | public int P2Pdoxpause(byte[] var1) {
101 | return this.doxpause(var1);
102 | }
103 |
104 | public int P2Pdoxstart(byte[] var1) {
105 | return this.doxstart(var1);
106 | }
107 |
108 | public int P2Pdoxstarthttpd(byte[] var1) {
109 | return this.doxstarthttpd(var1);
110 | }
111 |
112 | public int P2Pdoxterminate() {
113 | return doxterminate();
114 | }
115 |
116 | public long P2Pgetdownsize(int var1) {
117 | return getdownsize(var1);
118 | }
119 |
120 | public long P2Pgetfilesize(int var1) {
121 | return getfilesize(var1);
122 | }
123 |
124 | public long P2Pgetlocalfilesize(byte[] var1) {
125 | return getlocalfilesize(var1);
126 | }
127 |
128 | public int P2Pgetpercent() {
129 | return getpercent();
130 | }
131 |
132 | public long P2Pgetspeed(int var1) {
133 | return getspeed(var1);
134 | }
135 |
136 | public int getVersion() {
137 | return 18;
138 | }
139 |
140 | public void init() {
141 | try {
142 | String path = StorageUtils.getCachePath();
143 | File file = new File(path + "/xigua");
144 | if(!file.exists())file.mkdirs();
145 | P2Pdoxstarthttpd(path.getBytes());
146 | } catch (Exception e) {
147 | e.printStackTrace();
148 | }
149 | }
150 |
151 | public void reinit() {
152 | try {
153 | String exec = StorageUtils.getCachePath();
154 | exec = "rm -r " + exec + "/xigua";
155 | Runtime.getRuntime().exec(exec).waitFor();
156 | } catch (Exception e) {
157 | e.printStackTrace();
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/P2PManager.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.ServiceConnection;
7 | import android.os.Bundle;
8 | import android.os.IBinder;
9 | import android.os.Message;
10 | import android.os.Messenger;
11 |
12 | /**
13 | * P2PManager
14 | * Created by fanchen on 2018/10/19.
15 | */
16 | public class P2PManager {
17 | public static final String PREFERENCES = "xigua_preferences";
18 | public static final String TASK_3G = "task_3g";
19 | public static final String TASK_LIST = "task_list";
20 | public static final String TASK_LAST = "task_last";
21 | public static final String TASK_PATH = "task_path";
22 | public static final String SO_VERSION = "so_version";
23 |
24 | private static P2PManager instance;
25 |
26 | private ConnectionCallback connectionCallback;
27 | private Context mContext;
28 | private boolean mIsConnect = false;
29 | private Messenger messenger;
30 |
31 | private ServiceConnection connection = new ServiceConnection() {
32 |
33 | @Override
34 | public void onServiceConnected(ComponentName name, IBinder binder) {
35 | messenger = new Messenger(binder);
36 | mIsConnect = true;
37 | if (connectionCallback != null) {
38 | connectionCallback.onServiceConnected();
39 | }
40 | }
41 |
42 | @Override
43 | public void onServiceDisconnected(ComponentName var1) {
44 | mIsConnect = false;
45 | bindP2PService();
46 | }
47 | };
48 |
49 | /**
50 | * getInstance
51 | *
52 | * @return
53 | */
54 | public static P2PManager getInstance() {
55 | if (instance == null) {
56 | synchronized (P2PManager.class) {
57 | if (instance == null) {
58 | instance = new P2PManager();
59 | }
60 | }
61 | }
62 | return instance;
63 | }
64 |
65 | /**
66 | *
67 | * @param uri
68 | * @return
69 | */
70 | public static boolean isXiguaUrl(Uri uri){
71 | String scheme = uri.getScheme();
72 | return scheme != null && (scheme.equalsIgnoreCase("xg") || scheme.equalsIgnoreCase("xgadd") || scheme.equalsIgnoreCase("xgplay"));
73 | }
74 |
75 | /**
76 | *
77 | * @param url
78 | * @return
79 | */
80 | public static boolean isXiguaUrl(String url){
81 | if(TextUtils.isEmpty(url))return false;
82 | return isXiguaUrl(Uri.parse(url));
83 | }
84 |
85 | /**
86 | * 解绑服务
87 | */
88 | private void unbindP2PService() {
89 | if (mContext == null) return;
90 | mContext.unbindService(connection);
91 | Intent var1 = new Intent(mContext, P2PService.class);
92 | mContext.stopService(var1);
93 | }
94 |
95 | /**
96 | * 绑定服务
97 | */
98 | private void bindP2PService() {
99 | if (mContext == null) return;
100 | Intent var1 = new Intent(mContext, P2PService.class);
101 | mContext.startService(var1);
102 | mContext.bindService(var1, connection, Context.BIND_AUTO_CREATE);
103 | }
104 |
105 | /**
106 | * 清空缓存
107 | *
108 | * @return
109 | */
110 | public boolean cleanCache() {
111 | if (!isConnect()) {
112 | return false;
113 | } else {
114 | try {
115 | messenger.send(Message.obtain(null, P2PMessageWhat.CLEAN_CACHE));
116 | } catch (Exception e) {
117 | e.printStackTrace();
118 | }
119 | }
120 | return true;
121 | }
122 |
123 | /**
124 | * 获取是否使用流量下载
125 | *
126 | * @return
127 | */
128 | public boolean getAllow3G() {
129 | if (mContext == null) return true;
130 | return mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).getBoolean(P2PManager.TASK_3G, true);
131 | }
132 |
133 | /**
134 | * 初始化
135 | *
136 | * @param context
137 | */
138 | public void init(Context context) {
139 | mContext = context.getApplicationContext();
140 | StorageUtils.init(context.getApplicationContext());
141 | bindP2PService();
142 | }
143 |
144 | /**
145 | * 是否连接服务
146 | *
147 | * @return
148 | */
149 | public boolean isConnect() {
150 | if (!mIsConnect) {
151 | bindP2PService();
152 | }
153 | return this.mIsConnect;
154 | }
155 |
156 | /**
157 | * 暂停一个任务
158 | *
159 | * @param var1
160 | * @return
161 | */
162 | public boolean pause(String var1) {
163 | if (!isConnect()) {
164 | return false;
165 | } else {
166 | try {
167 | Bundle bundle = new Bundle();
168 | bundle.putString("url", var1);
169 | messenger.send(Message.obtain(null, P2PMessageWhat.PAUSE, bundle));
170 | } catch (Exception e) {
171 | e.printStackTrace();
172 | }
173 | }
174 | return true;
175 | }
176 |
177 | /**
178 | * 开始一个任务
179 | *
180 | * @param var1
181 | * @return
182 | */
183 | public boolean play(String var1) {
184 | if (!isConnect()) {
185 | return false;
186 | } else {
187 | try {
188 | Bundle bundle = new Bundle();
189 | bundle.putString("url", var1);
190 | messenger.send(Message.obtain(null, P2PMessageWhat.START, bundle));
191 | } catch (Exception e) {
192 | e.printStackTrace();
193 | }
194 | }
195 | return true;
196 | }
197 |
198 | /**
199 | * 释放资源
200 | */
201 | public void release() {
202 | unbindP2PService();
203 | }
204 |
205 | /**
206 | * 移除一个任务
207 | *
208 | * @param url
209 | * @return
210 | */
211 | public boolean remove(String url) {
212 | if (!isConnect()) {
213 | return false;
214 | } else {
215 | try {
216 | Bundle bundle = new Bundle();
217 | bundle.putString("url", url);
218 | messenger.send(Message.obtain(null, P2PMessageWhat.REMOVE, bundle));
219 | } catch (Exception e) {
220 | e.printStackTrace();
221 | }
222 | }
223 | return true;
224 | }
225 |
226 | /**
227 | * 重启服务
228 | *
229 | * @return
230 | */
231 | public boolean restartService() {
232 | if (!isConnect()) {
233 | return false;
234 | } else {
235 | try {
236 | messenger.send(Message.obtain(null, P2PMessageWhat.RESTART_SERVICE));
237 | } catch (Exception e) {
238 | e.printStackTrace();
239 | }
240 | }
241 | return true;
242 | }
243 |
244 | /**
245 | * 设置是否允许流量下载
246 | *
247 | * @param allow3G
248 | */
249 | public void setAllow3G(boolean allow3G) {
250 | if (mContext == null) return;
251 | mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).edit().putBoolean(P2PManager.TASK_3G, allow3G).apply();
252 | }
253 |
254 | /**
255 | * @param connectionCallback
256 | */
257 | public void setConnectionCallback(ConnectionCallback connectionCallback) {
258 | this.connectionCallback = connectionCallback;
259 | }
260 |
261 | /**
262 | * ConnectionCallback
263 | */
264 | public interface ConnectionCallback {
265 | void onServiceConnected();
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/P2PMessageWhat.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | /**
4 | * P2PMessageWhat
5 | * Created by fanchen on 2018/10/19.
6 | */
7 | public class P2PMessageWhat {
8 | public static final int CLEAN_CACHE = 257;
9 | public static final int DOWNLOAD = 2;
10 | public static final int PAUSE = 3;
11 | public static final int REMOVE = 4;
12 | public static final int RESTART_SERVICE = 256;
13 | public static final int START = 1;
14 | public static final int MESSAGE_FREE_SIZE_NOT = 4;
15 | public static final int MESSAGE_INIT_FINISHED = 257;
16 | public static final int MESSAGE_NETWORK_CHANGE = 5;
17 | public static final int MESSAGE_PLAY_URL = 258;
18 | public static final int MESSAGE_SPEED = 1;
19 | public static final int MESSAGE_TASK_LIST = 2;
20 | public static final int MESSAGE_TASK_MSG = 3;
21 | public static final String WHAT = "what";
22 | public static final String DATA = "data";
23 | public static final String PLAY_URL = "url";
24 | public static final String LOCAL_FILE = "local";
25 | public static final String P2P_CALLBACK = "com.broadcast.message.p2p";
26 |
27 | private P2PMessageWhat(){
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/P2PService.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.app.Service;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 | import android.os.IBinder;
9 | import android.os.Message;
10 | import android.os.Messenger;
11 | import android.util.Log;
12 |
13 | /**
14 | * P2PService
15 | * Created by fanchen on 2018/10/19.
16 | */
17 | public class P2PService extends Service {
18 | public static final String TAG = "xigua_sdk";
19 | private Messenger messenger;
20 |
21 | public IBinder onBind(Intent var1) {
22 | return messenger.getBinder();
23 | }
24 |
25 | public void onCreate() {
26 | super.onCreate();
27 | TaskVideoList.getInstance().init(this);
28 | messenger = new Messenger(new IncomingHandler(this));
29 | }
30 |
31 | public void onDestroy() {
32 | super.onDestroy();
33 | TaskVideoList.getInstance().terminate();
34 | }
35 |
36 | private static class IncomingHandler extends Handler implements Runnable {
37 |
38 | private String lastUrl = "";
39 | private Context mContext;
40 |
41 | public IncomingHandler(Context context) {
42 | mContext = context;
43 | lastUrl = loadLastUrl();
44 | if (lastUrl.length() > 0) TaskVideoList.getInstance().start(lastUrl);
45 | }
46 |
47 | private String loadLastUrl() {
48 | if (mContext == null) return "";
49 | return mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).getString(P2PManager.TASK_LAST, "");
50 | }
51 |
52 | private void saveLastUrl() {
53 | if (mContext == null) return;
54 | mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).edit().putString(P2PManager.TASK_LAST, lastUrl).apply();
55 | }
56 |
57 | @Override
58 | public void handleMessage(Message msg) {
59 | if (msg.obj == null || !(msg.obj instanceof Bundle)) return;
60 | Bundle bundle = (Bundle) msg.obj;
61 | String url = bundle.getString("url", "");
62 | if (msg.what == P2PMessageWhat.START) {
63 | TaskVideoList.getInstance().start(lastUrl = url);
64 | saveLastUrl();
65 | Log.e(TAG, "PLAY " + url);
66 | } else if (msg.what == P2PMessageWhat.PAUSE) {
67 | TaskVideoList.getInstance().pause(url);
68 | if (lastUrl.equalsIgnoreCase(url)) {
69 | lastUrl = "";
70 | saveLastUrl();
71 | }
72 | Log.e(TAG, "PAUSE " + url);
73 | } else if (msg.what == P2PMessageWhat.MESSAGE_INIT_FINISHED) {
74 | lastUrl = "";
75 | saveLastUrl();
76 | new Thread(this).start();
77 | Log.e(TAG, "CLEAN_CACHE");
78 | } else if (msg.what == P2PMessageWhat.REMOVE) {
79 | TaskVideoList.getInstance().remove(url);
80 | if (lastUrl.equalsIgnoreCase(url)) {
81 | lastUrl = "";
82 | saveLastUrl();
83 | }
84 | Log.e(TAG, "REMOVE " + url);
85 | } else if (msg.what == P2PMessageWhat.RESTART_SERVICE) {
86 | Log.e(TAG, "RESTART_SERVICE");
87 | System.exit(0);
88 | }
89 | }
90 |
91 | @Override
92 | public void run() {
93 | synchronized (IncomingHandler.class) {
94 | TaskVideoList.getInstance().cleanCache();
95 | }
96 | }
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/StorageUtils.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.os.Build;
6 | import android.os.Environment;
7 | import android.os.StatFs;
8 | import android.os.storage.StorageManager;
9 |
10 | import java.io.File;
11 | import java.lang.reflect.Method;
12 | import java.util.ArrayList;
13 | import java.util.Iterator;
14 | import java.util.List;
15 |
16 | /**
17 | * StorageUtils
18 | * Created by fanchen on 2018/10/19.
19 | */
20 | public class StorageUtils {
21 | private static Context appContext = null;
22 | private static String defMaxPath = "";
23 |
24 | /**
25 | * 初始化
26 | * @param paramContext
27 | */
28 | public static void init(Context paramContext) {
29 | appContext = paramContext.getApplicationContext();
30 | defMaxPath = autoSelectMaxCache();
31 | }
32 |
33 | private static String autoSelectMaxCache() {
34 | String cachePath = Environment.getExternalStorageDirectory().getPath();
35 | try {
36 | cachePath = cachePath + File.separator + "Android" + File.separator + "data" + File.separator + appContext.getPackageName() + File.separator + "video";
37 | Iterator localIterator = getStorageList().iterator();
38 | while (localIterator.hasNext()) {
39 | String str = localIterator.next();
40 | if (getFreeSize(cachePath) >= getFreeSize(str)) continue;
41 | cachePath = str;
42 | }
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | return cachePath;
47 | }
48 |
49 | /**
50 | * 清除缓存
51 | */
52 | public static void clearCache() {
53 | try {
54 | List storageList = getStorageList();
55 | storageList.add(defMaxPath);
56 | Iterator localIterator = storageList.iterator();
57 | while (localIterator.hasNext()) {
58 | File dir = new File(localIterator.next());
59 | if (!dir.exists())continue;
60 | File[] files = dir.listFiles();
61 | int i = 0;
62 | if (files != null && files.length > 0)
63 | while (i < files.length) {
64 | if (files[i].isFile())
65 | files[i].delete();
66 | i++;
67 | }
68 | }
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | }
73 |
74 | /**
75 | * 获取下载缓存目录
76 | * @return
77 | */
78 | public static String getCachePath() {
79 | String cachePath = Environment.getExternalStorageDirectory().getPath();
80 | try {
81 | cachePath = cachePath + File.separator + "Android" + File.separator + "data" + File.separator + appContext.getPackageName() + File.separator + "video";
82 | if (defMaxPath.length() > 0)cachePath = defMaxPath;
83 | cachePath = appContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).getString(P2PManager.TASK_PATH, cachePath);
84 | } catch (Exception e) {
85 | e.printStackTrace();
86 | }
87 | return cachePath;
88 | }
89 |
90 | /**
91 | * 设置缓存目录
92 | * @param path
93 | * @return
94 | */
95 | public static boolean setCachePath(String path) {
96 | try {
97 | SharedPreferences preferences = appContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE);
98 | SharedPreferences.Editor editor = preferences.edit();
99 | editor.putString(P2PManager.TASK_PATH, path);
100 | return editor.commit();
101 | } catch (Exception e) {
102 | e.printStackTrace();
103 | }
104 | return false;
105 | }
106 |
107 | @SuppressWarnings("deprecation")
108 | public static long getFreeSize(String path) {
109 | long l2 = 10240L;
110 | long l1 = 10240L;
111 | try {
112 | StatFs statFs = new StatFs(path);
113 | if (Build.VERSION.SDK_INT >= 18) {
114 | l2 = statFs.getBlockSizeLong();
115 | l1 = statFs.getAvailableBlocksLong();
116 | } else {
117 | l2 = statFs.getBlockSize();
118 | l1 = statFs.getAvailableBlocks();
119 | }
120 | } catch (Throwable e) {
121 | e.printStackTrace();
122 | }
123 | return l2 * l1;
124 | }
125 |
126 | public static List getStorageList() {
127 | List storageList = new ArrayList();
128 | try {
129 | String str = "Android" + File.separator + "data" + File.separator + appContext.getPackageName() + File.separator + "video";
130 | StorageManager storageManager = (StorageManager) appContext.getSystemService(Context.STORAGE_SERVICE);
131 | Class> clazz = storageManager.getClass();
132 | Method getVolumePaths = clazz.getMethod("getVolumePaths",new Class[0]);
133 | String[] volumePaths = (String[]) getVolumePaths.invoke(storageManager, new Object[0]);
134 | for (String s : volumePaths) {
135 | Method getVolumeState = clazz.getMethod("getVolumeState",new Class[] { String.class });
136 | String state = (String) getVolumeState.invoke(storageManager,new Object[] { s });
137 | if ("mounted".equals(state)) {
138 | String path = s + File.separator + str;
139 | getExternalFilesDirs(appContext, null);
140 | File localFile = new File(path);
141 | if(!localFile.exists())localFile.mkdirs();
142 | if (localFile.exists())storageList.add(path);
143 | }
144 | }
145 | } catch (Exception e) {
146 | e.printStackTrace();
147 | }
148 | return storageList;
149 | }
150 |
151 | public static File[] getExternalFilesDirs(Context context, String type) {
152 | if (Build.VERSION.SDK_INT >= 19) {
153 | return context.getExternalFilesDirs(type);
154 | } else {
155 | return new File[] { context.getExternalFilesDir(type) };
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/TaskVideoInfo.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | /**
7 | * TaskVideoInfo
8 | * Created by fanchen on 2018/10/19.
9 | */
10 | public class TaskVideoInfo implements Parcelable {
11 | public static final int PAUSE = 1;
12 | public static final int START = 2;
13 | private long downSize;//已下载大小
14 | private long localSize;//本地文件大小
15 | private long percent;
16 | private long speed;//下载速度
17 | private int state;//状态
18 | private long totalSize;//总大小
19 | private String url;//url地址
20 |
21 | public TaskVideoInfo() {
22 | }
23 |
24 | protected TaskVideoInfo(Parcel in) {
25 | downSize = in.readLong();
26 | localSize = in.readLong();
27 | percent = in.readLong();
28 | speed = in.readLong();
29 | state = in.readInt();
30 | totalSize = in.readLong();
31 | url = in.readString();
32 | }
33 |
34 | public long getDownSize() {
35 | return downSize;
36 | }
37 |
38 | public void setDownSize(long downSize) {
39 | this.downSize = downSize;
40 | }
41 |
42 | public long getLocalSize() {
43 | return localSize;
44 | }
45 |
46 | public void setLocalSize(long localSize) {
47 | this.localSize = localSize;
48 | }
49 |
50 | public long getPercent() {
51 | return percent;
52 | }
53 |
54 | public void setPercent(long percent) {
55 | this.percent = percent;
56 | }
57 |
58 | public long getSpeed() {
59 | return speed;
60 | }
61 |
62 | public void setSpeed(long speed) {
63 | this.speed = speed;
64 | }
65 |
66 | public int getState() {
67 | return state;
68 | }
69 |
70 | public void setState(int state) {
71 | this.state = state;
72 | }
73 |
74 | public long getTotalSize() {
75 | return totalSize;
76 | }
77 |
78 | public void setTotalSize(long totalSize) {
79 | this.totalSize = totalSize;
80 | }
81 |
82 | public String getUrl() {
83 | return url;
84 | }
85 |
86 | public void setUrl(String url) {
87 | this.url = url;
88 | }
89 |
90 | @Override
91 | public void writeToParcel(Parcel dest, int flags) {
92 | dest.writeLong(downSize);
93 | dest.writeLong(localSize);
94 | dest.writeLong(percent);
95 | dest.writeLong(speed);
96 | dest.writeInt(state);
97 | dest.writeLong(totalSize);
98 | dest.writeString(url);
99 | }
100 |
101 | @Override
102 | public int describeContents() {
103 | return 0;
104 | }
105 |
106 | public static final Creator CREATOR = new Creator() {
107 | @Override
108 | public TaskVideoInfo createFromParcel(Parcel in) {
109 | return new TaskVideoInfo(in);
110 | }
111 |
112 | @Override
113 | public TaskVideoInfo[] newArray(int size) {
114 | return new TaskVideoInfo[size];
115 | }
116 | };
117 |
118 | @Override
119 | public String toString() {
120 | return "[url -> " + url + ", state -> " + state +",speed -> " + speed + "]";
121 | }
122 |
123 | @Override
124 | public boolean equals(Object object) {
125 | if (this == object) return true;
126 | if (object != null && object instanceof TaskVideoInfo) {
127 | return url.equals(((TaskVideoInfo) object).url);
128 | }
129 | return false;
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/TaskVideoList.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.net.ConnectivityManager;
8 | import android.net.NetworkInfo;
9 | import android.net.Uri;
10 | import android.os.Parcelable;
11 | import android.util.Log;
12 |
13 | import org.json.JSONArray;
14 |
15 | import java.io.File;
16 | import java.net.URLEncoder;
17 | import java.util.ArrayList;
18 | import java.util.Collections;
19 | import java.util.Comparator;
20 | import java.util.Set;
21 | import java.util.concurrent.CopyOnWriteArraySet;
22 |
23 | /**
24 | * TaskVideoList
25 | * Created by fanchen on 2018/10/19.
26 | */
27 | public class TaskVideoList {
28 | public static final String TAG = "xigua_sdk";
29 | private static TaskVideoList instance;
30 | private InfoThread infoThread;
31 | private Context mContext;
32 | private Set tastList = new CopyOnWriteArraySet<>();
33 |
34 | /**
35 | * getInstance
36 | * @return
37 | */
38 | public static TaskVideoList getInstance() {
39 | if (instance == null) {
40 | synchronized (TaskVideoList.class) {
41 | if (instance == null) {
42 | instance = new TaskVideoList();
43 | }
44 | }
45 | }
46 | return instance;
47 | }
48 |
49 | /**
50 | * 构建下载信息
51 | * @param url
52 | * @return
53 | */
54 | private TaskVideoInfo buildTaskInfo(String url) {
55 | try {
56 | P2PClass p2PClass = P2PClass.getInstance();
57 | byte[] gbks = url.getBytes("GBK");
58 | int doxadd = p2PClass.P2Pdoxadd(gbks);
59 | TaskVideoInfo task = new TaskVideoInfo();
60 | task.setUrl(url);
61 | task.setState(1);
62 | task.setDownSize(p2PClass.P2Pgetdownsize(doxadd));
63 | task.setTotalSize(p2PClass.P2Pgetfilesize(doxadd));
64 | task.setLocalSize(p2PClass.P2Pgetlocalfilesize(gbks));
65 | task.setSpeed(p2PClass.P2Pgetspeed(-1));
66 | task.setPercent(p2PClass.P2Pgetpercent());
67 | return task;
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 | return null;
72 | }
73 |
74 | /**
75 | * 流量情况下,是否允许下载
76 | * @return
77 | */
78 | private boolean is3G() {
79 | if (mContext == null) return false;
80 | return mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).getBoolean(P2PManager.TASK_3G, true);
81 | }
82 |
83 | /**
84 | * 暂停任务,不保存
85 | *
86 | * @param url
87 | */
88 | private void pauseNoSave(String url) {
89 | try {
90 | byte[] gbks = url.getBytes("GBK");
91 | P2PClass.getInstance().P2Pdoxpause(gbks);
92 | if (tastList == null) return;
93 | for (TaskVideoInfo info : tastList) {
94 | if (url.equals(info.getUrl())) {
95 | info.setState(1);
96 | }
97 | }
98 | } catch (Exception e) {
99 | e.printStackTrace();
100 | }
101 | }
102 |
103 | /**
104 | * 移除任务,但不保存到本地
105 | * @param url
106 | */
107 | private void removeNoSave(String url) {
108 | try {
109 | byte[] gbks = url.getBytes("GBK");
110 | P2PClass p2PClass = P2PClass.getInstance();
111 | p2PClass.P2Pdoxpause(gbks);
112 | p2PClass.P2Pdoxdel(gbks);
113 | TaskVideoInfo task = new TaskVideoInfo();
114 | task.setUrl(url);
115 | if (tastList == null) return;
116 | tastList.remove(task);
117 | String segment = Uri.parse(url).getLastPathSegment();
118 | String path = StorageUtils.getCachePath() + "/xigua/Downloads/" + segment;
119 | File file = new File(path);
120 | if (file.exists()) file.delete();
121 | } catch (Exception e) {
122 | e.printStackTrace();
123 | }
124 | }
125 |
126 | /**
127 | * 发送本地代理播放地址
128 | * @param info
129 | */
130 | private void sendPlayUrl(TaskVideoInfo info) {
131 | try {
132 | String localFileName = Uri.parse(info.getUrl()).getLastPathSegment();
133 | String localFile = StorageUtils.getCachePath() + "/xigua/Downloads/" + localFileName;
134 | File file = new File(localFile);
135 | boolean isLocal = info.getLocalSize() > 0 && file.exists();
136 | String play_url = isLocal ? "file://" + localFile : "http://127.0.0.1:8083/" + URLEncoder.encode(localFileName, "GBK");
137 | sendMessage(P2PMessageWhat.MESSAGE_PLAY_URL,new Object[]{play_url,isLocal});
138 | Log.i(TAG, "sendPlayUrl:" + play_url);
139 | } catch(Exception e) {
140 | e.printStackTrace();
141 | }
142 | }
143 |
144 | public void checkFreeSize() {
145 | try {
146 | if (mContext == null) return;
147 | if (StorageUtils.getFreeSize(StorageUtils.getCachePath()) >= 524288000L) return;
148 | getInstance().stopAll();
149 | sendMessage(P2PMessageWhat.MESSAGE_FREE_SIZE_NOT);
150 | sendBroadcastTaskList();
151 | } catch (Exception e) {
152 | e.printStackTrace();
153 | }
154 | }
155 |
156 | /**
157 | * 清空缓存
158 | */
159 | public void cleanCache() {
160 | StorageUtils.clearCache();
161 | P2PClass.getInstance().reinit();
162 | if (tastList == null) return;
163 | for (TaskVideoInfo info : tastList) {
164 | removeNoSave(info.getUrl());
165 | }
166 | saveTaskList();
167 | }
168 |
169 | /**
170 | * 初始化
171 | * @param context
172 | */
173 | public void init(Context context) {
174 | mContext = context.getApplicationContext();
175 | upgradeLibrary();
176 | StorageUtils.init(mContext);
177 | P2PClass.getInstance().init();
178 | sendBroadcastInitFinished();
179 | infoThread = new InfoThread(mContext);
180 | infoThread.start();
181 | loadTaskList();
182 | }
183 |
184 | /**
185 | * 是否是wifi环境,是否可以下载
186 | * @return
187 | */
188 | @SuppressLint("MissingPermission")
189 | public boolean isWifi() {
190 | try {
191 | ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
192 | NetworkInfo networkInfo = cm.getActiveNetworkInfo();
193 | if (networkInfo != null && networkInfo.getType() == 1) {
194 | return true;
195 | } else {
196 | return is3G();
197 | }
198 | } catch (Exception e) {
199 | e.printStackTrace();
200 | }
201 | return true;
202 | }
203 |
204 | /**
205 | * 加载下载列表
206 | */
207 | public void loadTaskList() {
208 | try{
209 | String json = mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).getString(P2PManager.TASK_LIST, "[]");
210 | JSONArray array = new JSONArray(json);
211 | for (int i = 0 ; i < array.length() ; i ++){
212 | String url = array.optString(i);
213 | TaskVideoInfo info = buildTaskInfo(url);
214 | tastList.add(info);
215 | }
216 | sendBroadcastTaskList();
217 | Log.i(TAG, "load task = :" + json);
218 | }catch (Exception e){
219 | e.printStackTrace();
220 | }
221 | }
222 |
223 | /**
224 | * 暂停任务
225 | *
226 | * @param paramString
227 | */
228 | public void pause(String paramString) {
229 | pauseNoSave(paramString);
230 | saveTaskList();
231 | }
232 |
233 | /**
234 | * 删除任务
235 | *
236 | * @param paramString
237 | */
238 | public void remove(String paramString) {
239 | removeNoSave(paramString);
240 | saveTaskList();
241 | }
242 |
243 | /**
244 | * 保存任务信息到本地
245 | */
246 | public void saveTaskList() {
247 | if (tastList == null || mContext == null) return;
248 | try {
249 | JSONArray jsonArray = new JSONArray();
250 | for (TaskVideoInfo info : tastList) {
251 | jsonArray.put(info.getUrl());
252 | }
253 | String s = jsonArray.toString();
254 | mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE).edit().putString(P2PManager.TASK_LIST, s).apply();
255 | Log.i(TAG, "save task = " + s);
256 | sendBroadcastTaskList();
257 | } catch (Exception e) {
258 | e.printStackTrace();
259 | }
260 | }
261 |
262 | /**
263 | * 发送下载完成消息
264 | */
265 | public void sendBroadcastInitFinished() {
266 | try {
267 | sendMessage(P2PMessageWhat.MESSAGE_INIT_FINISHED);
268 | } catch (Exception e) {
269 | e.printStackTrace();
270 | }
271 | }
272 |
273 | /**
274 | * 发送下载失败消息
275 | * @param data
276 | */
277 | public void sendBroadcastTaskError(String data) {
278 | try {
279 | sendMessage(P2PMessageWhat.MESSAGE_TASK_MSG, data);
280 | Log.e(TAG, "sendBroadcastTaskError -> " + data);
281 | } catch (Exception e) {
282 | e.printStackTrace();
283 | }
284 | }
285 |
286 | /**
287 | * 发送下载列表消息
288 | */
289 | public void sendBroadcastTaskList() {
290 | try {
291 | if (tastList == null) return;
292 | ArrayList list = new ArrayList<>();
293 | for (TaskVideoInfo info : tastList) {
294 | TaskVideoInfo task = buildTaskInfo(info.getUrl());
295 | if (task != null) {
296 | task.setState(info.getState());
297 | list.add(task);
298 | }
299 | }
300 | Collections.sort(list, comparator);
301 | sendMessage(P2PMessageWhat.MESSAGE_TASK_LIST, list);
302 | } catch (Exception e) {
303 | e.printStackTrace();
304 | }
305 | }
306 |
307 | /**
308 | * 开始任务
309 | * @param url
310 | * @return
311 | */
312 | public boolean start(String url) {
313 | try {
314 | byte[] bytes = url.getBytes("GBK");
315 | P2PClass p2p = P2PClass.getInstance();
316 | TaskVideoInfo info = buildTaskInfo(url);
317 | sendPlayUrl(info);
318 | if(info != null && info.getLocalSize() > 0) {
319 | return false;
320 | }else if(!isWifi()) {
321 | sendBroadcastTaskError("当前非wifi环境,不能下载");
322 | return false;
323 | }else if(info != null) {
324 | stopAll();
325 | p2p.P2Pdoxstart(bytes);
326 | info.setState(2);
327 | tastList.remove(info);
328 | tastList.add(info);
329 | } else {
330 | Log.i(TAG, "添加任务出错");
331 | return false;
332 | }
333 | } catch(Exception e) {
334 | e.printStackTrace();
335 | }
336 | saveTaskList();
337 | checkFreeSize();
338 | return true;
339 | }
340 |
341 | /**
342 | * 停止所有任务
343 | */
344 | public void stopAll() {
345 | if (tastList == null) return;
346 | for (TaskVideoInfo info : tastList) {
347 | pauseNoSave(info.getUrl());
348 | }
349 | saveTaskList();
350 | }
351 |
352 | /**
353 | * 释放资源
354 | */
355 | public void terminate() {
356 | stopAll();
357 | infoThread.stop();
358 | P2PClass.getInstance().P2Pdoxterminate();
359 | saveTaskList();
360 | }
361 |
362 | /**
363 | * 更新Library version
364 | */
365 | public void upgradeLibrary() {
366 | if (mContext == null) return;
367 | SharedPreferences preferences = mContext.getSharedPreferences(P2PManager.PREFERENCES, Context.MODE_PRIVATE);
368 | int version = preferences.getInt(P2PManager.SO_VERSION, 0);
369 | int pVersion = P2PClass.getInstance().getVersion();
370 | if (version != pVersion) {
371 | P2PClass.getInstance().reinit();
372 | preferences.edit().putInt(P2PManager.SO_VERSION, pVersion).apply();
373 | }
374 | Log.e(TAG, String.format("oldVersion = %d newVersion = %d", version, pVersion));
375 | }
376 |
377 | /**
378 | * 发送消息
379 | * @param what
380 | */
381 | private void sendMessage(int what) {
382 | sendMessage(P2PMessageWhat.P2P_CALLBACK, what, null);
383 | }
384 |
385 | /**
386 | * 发送消息
387 | * @param what
388 | * @param data
389 | */
390 | private void sendMessage(int what, Object data) {
391 | sendMessage(P2PMessageWhat.P2P_CALLBACK, what, data);
392 | }
393 |
394 | /**
395 | * 发送消息
396 | * @param action
397 | * @param what
398 | * @param data
399 | */
400 | private void sendMessage(String action, int what, Object data) {
401 | if (mContext == null) return;
402 | Intent intent = new Intent(action);
403 | intent.putExtra(P2PMessageWhat.WHAT, what);
404 | if (data != null && data instanceof String) {
405 | intent.putExtra(P2PMessageWhat.DATA, data.toString());
406 | } else if (data != null && data instanceof ArrayList) {
407 | intent.putParcelableArrayListExtra(P2PMessageWhat.DATA, (ArrayList) data);
408 | } else if (data != null && data instanceof Object[]) {
409 | Object[] objects = (Object[]) data;
410 | intent.putExtra(P2PMessageWhat.PLAY_URL, objects[0].toString());
411 | intent.putExtra(P2PMessageWhat.LOCAL_FILE, (boolean) objects[1]);
412 | }
413 | mContext.sendBroadcast(intent);
414 | }
415 |
416 | private Comparator comparator = new Comparator() {
417 |
418 | @Override
419 | public int compare(TaskVideoInfo o1, TaskVideoInfo o2) {
420 | return o1.getUrl().compareToIgnoreCase(o2.getUrl());
421 | }
422 |
423 | };
424 | }
425 |
--------------------------------------------------------------------------------
/xigua/src/main/java/com/xigua/p2p/XiguaProvider.java:
--------------------------------------------------------------------------------
1 | package com.xigua.p2p;
2 |
3 | import android.content.ContentProvider;
4 | import android.content.ContentValues;
5 | import android.database.Cursor;
6 | import android.net.Uri;
7 |
8 | /**
9 | * XiguaProvider
10 | * 通过声明 {@link ContentProvider} 自动完成初始化
11 | * Created by fanchen on 2018/10/24.
12 | */
13 | public class XiguaProvider extends ContentProvider {
14 |
15 | @Override
16 | public boolean onCreate() {
17 | P2PManager.getInstance().init(getContext());
18 | P2PManager.getInstance().setAllow3G(true);
19 | P2PManager.getInstance().isConnect();
20 | return true;
21 | }
22 |
23 | @Override
24 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
25 | return null;
26 | }
27 |
28 | @Override
29 | public String getType(Uri uri) {
30 | return null;
31 | }
32 |
33 | @Override
34 | public Uri insert(Uri uri, ContentValues values) {
35 | return null;
36 | }
37 |
38 | @Override
39 | public int delete(Uri uri, String selection, String[] selectionArgs) {
40 | return 0;
41 | }
42 |
43 | @Override
44 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
45 | return 0;
46 | }
47 | }
--------------------------------------------------------------------------------
/xigua/src/main/jniLibs/armeabi/libp2p.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanchen001/XiguaP2p/71cc4aacf4a9abc2f66ab089ec8ad0a27ceccf84/xigua/src/main/jniLibs/armeabi/libp2p.so
--------------------------------------------------------------------------------