├── .gitignore
├── .pullapprove.yml
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── leancloudlivekit
├── .gitignore
├── build.gradle
├── libs
│ ├── pldroid-camera-streaming-1.7.1.jar
│ └── pldroid-player-1.3.0.jar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── leancloud
│ │ └── leancloudlivekit
│ │ ├── LCLKUser.java
│ │ ├── LCLiveKit.java
│ │ ├── LCLiveKitProvider.java
│ │ ├── barrage
│ │ └── LCLKBarrageLayout.java
│ │ ├── handler
│ │ ├── LCLKClientEventHandler.java
│ │ ├── LCLKConversationHandler.java
│ │ └── LCLKMessageHandler.java
│ │ ├── im
│ │ ├── LCLKChatAdapter.java
│ │ ├── LCLKChatItemStatusHolder.java
│ │ ├── LCLKChatItemTextHolder.java
│ │ ├── LCLKCommonListAdapter.java
│ │ ├── LCLKCommonViewHolder.java
│ │ ├── LCLKGiftDialogFragment.java
│ │ ├── LCLKGiftItem.java
│ │ ├── LCLKGiftManager.java
│ │ ├── LCLKGiftMessage.java
│ │ ├── LCLKGiftPagerAdapter.java
│ │ ├── LCLKIMBarrageMessage.java
│ │ ├── LCLKIMFragment.java
│ │ ├── LCLKIMMessage.java
│ │ ├── LCLKIMMessageEvent.java
│ │ ├── LCLKIMStatusMessage.java
│ │ └── LCLKRoundCornerImageView.java
│ │ ├── play
│ │ ├── LCLKPlayActivity.java
│ │ └── LCLKPlayFragment.java
│ │ ├── record
│ │ ├── LCLKRecordActivity.java
│ │ └── LCLKRecordFragment.java
│ │ └── utils
│ │ ├── LCLKConstants.java
│ │ └── LCLKProfileCache.java
│ ├── jniLibs
│ ├── arm64-v8a
│ │ ├── libpldroid_mmprocessing.so
│ │ ├── libpldroid_streaming_aac_encoder.so
│ │ ├── libpldroid_streaming_core.so
│ │ ├── libpldroid_streaming_h264_encoder.so
│ │ └── libpldroidplayer.so
│ ├── armeabi-v7a
│ │ ├── libpldroid_mmprocessing.so
│ │ ├── libpldroid_streaming_aac_encoder.so
│ │ ├── libpldroid_streaming_core.so
│ │ ├── libpldroid_streaming_h264_encoder.so
│ │ └── libpldroidplayer.so
│ └── armeabi
│ │ ├── libpldroid_mmprocessing.so
│ │ ├── libpldroid_streaming_aac_encoder.so
│ │ ├── libpldroid_streaming_core.so
│ │ ├── libpldroid_streaming_h264_encoder.so
│ │ └── libpldroidplayer.so
│ └── res
│ ├── drawable
│ ├── lclk_barrage_item_bg.xml
│ ├── lclk_im_gift_bg.xml
│ ├── lclk_im_input_bg.xml
│ ├── lclk_im_item_content_bg.9.png
│ └── lclk_praise_bg.xml
│ ├── layout
│ ├── lclk_barrage_gift_item.xml
│ ├── lclk_barrage_item.xml
│ ├── lclk_gift_dialog.xml
│ ├── lclk_gift_item.xml
│ ├── lclk_im_barrage_layout.xml
│ ├── lclk_im_chat_item_text_layout.xml
│ ├── lclk_im_chat_status_item.xml
│ ├── lclk_im_fragment.xml
│ ├── lclk_im_gift_layout.xml
│ ├── lclk_im_im_layout.xml
│ ├── lclk_im_input_layout.xml
│ ├── lclk_im_personal_layout.xml
│ ├── lclk_play_activity.xml
│ ├── lclk_play_fragment.xml
│ ├── lclk_record_activity.xml
│ └── lclk_record_fragment.xml
│ ├── mipmap-xxhdpi
│ ├── lclk_camera_switch.png
│ ├── lclk_default_avatar_icon.png
│ ├── lclk_im_close.png
│ ├── lclk_im_gift_1.png
│ ├── lclk_im_gift_2.png
│ ├── lclk_im_gift_3.png
│ ├── lclk_im_gift_4.png
│ ├── lclk_im_gift_5.png
│ ├── lclk_im_gift_6.png
│ ├── lclk_im_gift_7.png
│ ├── lclk_im_gift_8.png
│ └── lclk_star.png
│ └── values
│ ├── lclk_colors.xml
│ ├── lclk_dimens.xml
│ ├── lclk_strings.xml
│ └── lclk_styles.xml
├── livekitapplication
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── leancloud
│ │ └── livekitapplication
│ │ ├── LCLKAppProvider.java
│ │ ├── LCLKApplication.java
│ │ ├── LCLKLiveRoomCreateActivity.java
│ │ ├── LCLKLiveRoomItemClickEvent.java
│ │ ├── LCLKLiveRoomItemHolder.java
│ │ ├── LCLKLiveRoomListActivity.java
│ │ ├── LCLKLoginActivity.java
│ │ └── LCLiveRoom.java
│ └── res
│ ├── drawable
│ ├── edittext_bg.xml
│ ├── start_channel_btn_bg.xml
│ └── start_channel_image_bg.xml
│ ├── layout
│ ├── lclk_live_room_create_activity.xml
│ ├── lclk_live_room_item.xml
│ ├── lclk_live_room_list_activity.xml
│ └── lclk_login_activity.xml
│ ├── menu
│ └── lclk_menu_live_create.xml
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── lclk_live_add_image.png
│ └── values
│ ├── lclk_colors.xml
│ ├── lclk_dimens.xml
│ ├── lclk_strings.xml
│ └── lclk_styles.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # ADT
16 | .classpath
17 | .project
18 | .settings
19 | local.properties
20 | bin
21 | gen
22 | _layouts
23 | proguard.cfg
24 |
25 | # OSX
26 | .DS_Store
27 |
28 | # Gradle files
29 | .gradle/
30 | build/
31 |
32 | # Local configuration file (sdk path, etc)
33 | local.properties
34 |
35 | # Proguard folder generated by Eclipse
36 | proguard/
37 |
38 | # IDEA
39 | *.iml
40 | *.ipr
41 | *.iws
42 | out
43 | .idea
44 |
45 | # Maven
46 | target
47 | release.properties
48 | pom.xml.*
49 |
50 | # VIM
51 | *~
52 | *.swp
53 |
--------------------------------------------------------------------------------
/.pullapprove.yml:
--------------------------------------------------------------------------------
1 | approve_by_comment: true
2 | approve_regex: '^(Reviewed|Approved|LGTM)'
3 | reject_regex: '^Rejected'
4 | reset_on_push: false
5 | reviewers:
6 | required: 1
7 | members:
8 | - daweibayu
9 | - jwfing
10 | name: default
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LiveKit 直播+聊天 UI 套件 · Android
2 |
3 | LiveKit 是由 [LeanCloud](http://leancloud.cn) 官方推出的基于 [LeanCloud 实时通信](https://leancloud.cn/docs/realtime_v2.html) 与 [七牛直播服务](http://developer.qiniu.com/article/pili/sdk/server-sdk.html) 的 UI 套件。它包含直播、文字聊天、弹幕、送礼物等界面,方便开发者为自己的项目快速植入直播与聊天功能,并灵活定制界面。直播与聊天的数据都保存在云端,支持 CDN 加速,开发者无需为数据的存储和访问速度而担忧。
4 |
5 | 具体使用方法请阅读 [官方文档](https://leancloud.cn/docs/livekit-android.html)。
6 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | google()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:3.0.1'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | jcenter()
14 | maven {
15 | url "http://mvn.leancloud.cn/nexus/content/repositories/releases"
16 | }
17 | google()
18 | }
19 | }
--------------------------------------------------------------------------------
/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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/leancloudlivekit/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/leancloudlivekit/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion '26.0.2'
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | multiDexEnabled true
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | lintOptions {
21 | abortOnError false
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 |
28 | compile 'com.android.support:support-v4:23.4.0'
29 | compile 'com.android.support:appcompat-v7:23.4.0'
30 | compile 'com.android.support:gridlayout-v7:23.4.0'
31 | compile 'com.android.support:recyclerview-v7:23.4.0'
32 |
33 | //avoscloud-sdk 为 LeanCloud基础包
34 | compile ('cn.leancloud.android:avoscloud-sdk:v4.+')
35 |
36 | //avoscloud-push 为推送与实时聊天需要的包
37 | compile ('cn.leancloud.android:avoscloud-push:v4.+@aar'){transitive = true}
38 |
39 |
40 | compile 'com.qiniu:happy-dns:0.2.7'
41 | compile 'com.squareup.okhttp:okhttp:2.5.0'
42 | compile 'com.google.code.gson:gson:2.3.1'
43 |
44 | compile 'com.squareup.picasso:picasso:2.5.2'
45 | compile 'de.greenrobot:eventbus:2.4.0'
46 | }
47 |
--------------------------------------------------------------------------------
/leancloudlivekit/libs/pldroid-camera-streaming-1.7.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/libs/pldroid-camera-streaming-1.7.1.jar
--------------------------------------------------------------------------------
/leancloudlivekit/libs/pldroid-player-1.3.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/libs/pldroid-player-1.3.0.jar
--------------------------------------------------------------------------------
/leancloudlivekit/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wli/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/LCLKUser.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit;
2 |
3 | /**
4 | * Created by wli on 16/8/4.
5 | * * LeanCloudLiveKit 中的用户类,仅包含三个变量,暂不支持继承扩展
6 | */
7 | public final class LCLKUser {
8 |
9 | /**
10 | * 用户 id
11 | */
12 | private String userId;
13 |
14 | /**
15 | * 用户头像地址
16 | */
17 | private String avatarUrl;
18 |
19 | /**
20 | * 用户别名
21 | */
22 | private String name;
23 |
24 | public LCLKUser(String userId, String userName, String avatarUrl) {
25 | this.userId = userId;
26 | this.avatarUrl = avatarUrl;
27 | this.name = userName;
28 | }
29 |
30 | public String getUserId() {
31 | return userId;
32 | }
33 |
34 | public String getAvatarUrl() {
35 | return avatarUrl;
36 | }
37 |
38 | public String getUserName() {
39 | return name;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/LCLiveKit.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit;
2 |
3 |
4 | import android.content.Context;
5 | import android.text.TextUtils;
6 |
7 | import com.avos.avoscloud.AVOSCloud;
8 | import com.avos.avoscloud.SignatureFactory;
9 | import com.avos.avoscloud.im.v2.AVIMClient;
10 | import com.avos.avoscloud.im.v2.AVIMException;
11 | import com.avos.avoscloud.im.v2.AVIMMessageManager;
12 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
13 | import com.avos.avoscloud.im.v2.callback.AVIMClientCallback;
14 | import com.pili.pldroid.streaming.StreamingEnv;
15 |
16 | import cn.leancloud.leancloudlivekit.handler.LCLKClientEventHandler;
17 | import cn.leancloud.leancloudlivekit.handler.LCLKConversationHandler;
18 | import cn.leancloud.leancloudlivekit.handler.LCLKMessageHandler;
19 | import cn.leancloud.leancloudlivekit.im.LCLKGiftMessage;
20 | import cn.leancloud.leancloudlivekit.im.LCLKIMBarrageMessage;
21 | import cn.leancloud.leancloudlivekit.im.LCLKIMMessage;
22 | import cn.leancloud.leancloudlivekit.im.LCLKIMStatusMessage;
23 |
24 | /**
25 | * Created by wli on 16/8/4.
26 | * * LeanCloudLiveKit 的管理类
27 | */
28 | public class LCLiveKit {
29 |
30 | private static LCLiveKit lcLiveKit;
31 | private LCLiveKitProvider liveKitProvider;
32 | private String currentUserId;
33 |
34 | private LCLiveKit() {
35 | }
36 |
37 | public static synchronized LCLiveKit getInstance() {
38 | if (null == lcLiveKit) {
39 | lcLiveKit = new LCLiveKit();
40 | }
41 | return lcLiveKit;
42 | }
43 |
44 | /**
45 | * 初始化 LeanCloudLiveKit,此函数要在 Application 的 onCreate 中调用
46 | *
47 | * @param context
48 | * @param appId
49 | * @param appKey
50 | */
51 | public void init(Context context, String appId, String appKey) {
52 | if (TextUtils.isEmpty(appId)) {
53 | throw new IllegalArgumentException("appId can not be empty!");
54 | }
55 | if (TextUtils.isEmpty(appKey)) {
56 | throw new IllegalArgumentException("appKey can not be empty!");
57 | }
58 |
59 | StreamingEnv.init(context);
60 |
61 | AVOSCloud.initialize(context.getApplicationContext(), appId, appKey);
62 |
63 | // 消息处理 handler
64 | AVIMMessageManager.registerMessageHandler(AVIMTypedMessage.class, new LCLKMessageHandler(context));
65 |
66 | // 与网络相关的 handler
67 | AVIMClient.setClientEventHandler(LCLKClientEventHandler.getInstance());
68 |
69 | // 和 Conversation 相关的事件的 handler
70 | AVIMMessageManager.setConversationEventHandler(LCLKConversationHandler.getInstance());
71 |
72 | // 默认设置为离线消息仅推送数量
73 | AVIMClient.setOfflineMessagePush(true);
74 |
75 | AVIMMessageManager.registerAVIMMessageType(LCLKIMMessage.class);
76 | AVIMMessageManager.registerAVIMMessageType(LCLKIMBarrageMessage.class);
77 | AVIMMessageManager.registerAVIMMessageType(LCLKGiftMessage.class);
78 | AVIMMessageManager.registerAVIMMessageType(LCLKIMStatusMessage.class);
79 | }
80 | public void setProfileProvider(LCLiveKitProvider profileProvider) {
81 | this.liveKitProvider = profileProvider;
82 | }
83 |
84 | /**
85 | * 获取当前的用户体系
86 | *
87 | * @return
88 | */
89 | public LCLiveKitProvider getProfileProvider() {
90 | return liveKitProvider;
91 | }
92 |
93 | /**
94 | * 设置签名工厂
95 | *
96 | * @param signatureFactory
97 | */
98 | public void setSignatureFactory(SignatureFactory signatureFactory) {
99 | AVIMClient.setSignatureFactory(signatureFactory);
100 | }
101 |
102 | /**
103 | * 开启实时聊天
104 | *
105 | * @param userId
106 | * @param callback
107 | */
108 | public void open(final String userId, final AVIMClientCallback callback) {
109 | if (TextUtils.isEmpty(userId)) {
110 | throw new IllegalArgumentException("userId can not be empty!");
111 | }
112 | if (null == callback) {
113 | throw new IllegalArgumentException("callback can not be null!");
114 | }
115 |
116 | AVIMClient.getInstance(userId).open(new AVIMClientCallback() {
117 | @Override
118 | public void done(final AVIMClient avimClient, AVIMException e) {
119 | if (null == e) {
120 | currentUserId = userId;
121 | }
122 | callback.internalDone(avimClient, e);
123 | }
124 | });
125 | }
126 |
127 | /**
128 | * 关闭实时聊天
129 | *
130 | * @param callback
131 | */
132 | public void close(final AVIMClientCallback callback) {
133 | AVIMClient.getInstance(currentUserId).close(new AVIMClientCallback() {
134 | @Override
135 | public void done(AVIMClient avimClient, AVIMException e) {
136 | currentUserId = null;
137 | if (null != callback) {
138 | callback.internalDone(avimClient, e);
139 | }
140 | }
141 | });
142 | }
143 |
144 | /**
145 | * 获取当前的实时聊天的用户
146 | *
147 | * @return
148 | */
149 | public String getCurrentUserId() {
150 | return currentUserId;
151 | }
152 |
153 | /**
154 | * 获取当前的 AVIMClient 实例
155 | *
156 | * @return
157 | */
158 | public AVIMClient getClient() {
159 | if (!TextUtils.isEmpty(currentUserId)) {
160 | return AVIMClient.getInstance(currentUserId);
161 | }
162 | return null;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/LCLiveKitProvider.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit;
2 |
3 | import com.avos.avoscloud.AVCallback;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Created by wli on 16/8/4.
9 | * LeanCloudLiveKit 用户体系的接口
10 | * 开发者需要实现此接口并调用 LCLiveKit.getInstance().setProfiProvider(LCLiveKitProvider)
11 | * 来接入 LeanCloudLiveKit
12 | */
13 | public interface LCLiveKitProvider {
14 |
15 | /**
16 | * 根据用户 id 获取用户的详细信息
17 | * @param userIdList
18 | * @param profilesCallBack
19 | */
20 | void fetchProfiles(List userIdList, AVCallback> profilesCallBack);
21 |
22 | /**
23 | * 根据 LiveId 拉取推流地址
24 | * @param liveId
25 | * @param streamCallback
26 | */
27 | void fetchRecordStream(String liveId, AVCallback streamCallback);
28 |
29 | /**
30 | * 根据 LiveId 拉取播放地址
31 | * @param liveId
32 | * @param streamCallback
33 | */
34 | void fetchPlayStream(String liveId, AVCallback streamCallback);
35 | }
36 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/barrage/LCLKBarrageLayout.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.barrage;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.animation.Animation;
9 | import android.view.animation.LinearInterpolator;
10 | import android.view.animation.TranslateAnimation;
11 | import android.widget.RelativeLayout;
12 | import android.widget.TextView;
13 |
14 | import java.util.Random;
15 |
16 | import cn.leancloud.leancloudlivekit.R;
17 |
18 | /**
19 | * Created by wli on 16/7/21.
20 | */
21 | public class LCLKBarrageLayout extends RelativeLayout {
22 |
23 | public LCLKBarrageLayout(Context context) {
24 | super(context);
25 | }
26 |
27 | public LCLKBarrageLayout(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 | }
30 |
31 | public LCLKBarrageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | }
34 |
35 | public void sendView(final View view) {
36 | int viewHeight = getResources().getDimensionPixelSize(R.dimen.lclk_im_barrage_item_width);
37 | int y = (getHeight() - viewHeight) * new Random().nextInt(100) / 100;
38 | Animation anim = createTranslateAnim(getWidth(), -1 * getWidth(), y);
39 | anim.setAnimationListener(new Animation.AnimationListener() {
40 | @Override
41 | public void onAnimationStart(Animation animation) {
42 |
43 | }
44 |
45 | @Override
46 | public void onAnimationEnd(Animation animation) {
47 | removeView(view);
48 | }
49 |
50 | @Override
51 | public void onAnimationRepeat(Animation animation) {
52 | }
53 | });
54 | view.startAnimation(anim);
55 |
56 | addView(view);
57 | }
58 |
59 | @Override
60 | protected void onDetachedFromWindow() {
61 | super.onDetachedFromWindow();
62 | }
63 |
64 | @Override
65 | protected void onVisibilityChanged(View changedView, int visibility) {
66 | super.onVisibilityChanged(changedView, visibility);
67 | }
68 |
69 | private static Animation createTranslateAnim(int fromX, int toX, int y) {
70 | TranslateAnimation tlAnim = new TranslateAnimation(fromX, toX, y, y);
71 | long duration = 3000;
72 | tlAnim.setDuration(duration);
73 | tlAnim.setFillEnabled(false);
74 | tlAnim.setInterpolator(new LinearInterpolator());
75 | return tlAnim;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/handler/LCLKClientEventHandler.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.handler;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMClient;
4 | import com.avos.avoscloud.im.v2.AVIMClientEventHandler;
5 |
6 | /**
7 | * Created by wli on 16/8/4.
8 | */
9 | public class LCLKClientEventHandler extends AVIMClientEventHandler {
10 |
11 | private static LCLKClientEventHandler eventHandler;
12 |
13 | public static synchronized LCLKClientEventHandler getInstance() {
14 | if (null == eventHandler) {
15 | eventHandler = new LCLKClientEventHandler();
16 | }
17 | return eventHandler;
18 | }
19 |
20 | private LCLKClientEventHandler() {
21 | }
22 |
23 |
24 | private volatile boolean connect = false;
25 |
26 | /**
27 | * 是否连上聊天服务
28 | *
29 | * @return
30 | */
31 | public boolean isConnect() {
32 | return connect;
33 | }
34 |
35 | public void setConnectAndNotify(boolean isConnect) {
36 | connect = isConnect;
37 | // EventBus.getDefault().post(new LCIMConnectionChangeEvent(connect));
38 | }
39 |
40 | @Override
41 | public void onConnectionPaused(AVIMClient avimClient) {
42 | setConnectAndNotify(false);
43 | }
44 |
45 | @Override
46 | public void onConnectionResume(AVIMClient avimClient) {
47 | setConnectAndNotify(true);
48 | }
49 |
50 | @Override
51 | public void onClientOffline(AVIMClient avimClient, int i) {
52 | // LCIMLogUtils.d("client " + avimClient.getClientId() + " is offline!");
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/handler/LCLKConversationHandler.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.handler;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMClient;
4 | import com.avos.avoscloud.im.v2.AVIMConversation;
5 | import com.avos.avoscloud.im.v2.AVIMConversationEventHandler;
6 |
7 | import java.util.List;
8 |
9 |
10 | /**
11 | * Created by wli on 16/8/4.
12 | */
13 | public class LCLKConversationHandler extends AVIMConversationEventHandler {
14 |
15 | private static LCLKConversationHandler eventHandler;
16 |
17 | public static synchronized LCLKConversationHandler getInstance() {
18 | if (null == eventHandler) {
19 | eventHandler = new LCLKConversationHandler();
20 | }
21 | return eventHandler;
22 | }
23 |
24 | private LCLKConversationHandler() {
25 | }
26 |
27 | // @Override
28 | public void onOfflineMessagesUnread(AVIMClient client, AVIMConversation conversation, int unreadCount) {
29 | }
30 |
31 | @Override
32 | public void onMemberLeft(AVIMClient client, AVIMConversation conversation, List members, String kickedBy) {
33 | // 因为不同用户需求不同,此处暂不做默认处理,如有需要,用户可以通过自定义 Handler 实现
34 | }
35 |
36 | @Override
37 | public void onMemberJoined(AVIMClient client, AVIMConversation conversation, List members, String invitedBy) {
38 | }
39 |
40 | @Override
41 | public void onKicked(AVIMClient client, AVIMConversation conversation, String kickedBy) {
42 | }
43 |
44 | @Override
45 | public void onInvited(AVIMClient client, AVIMConversation conversation, String operator) {
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/handler/LCLKMessageHandler.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.handler;
2 |
3 | import android.content.Context;
4 | import com.avos.avoscloud.im.v2.AVIMClient;
5 | import com.avos.avoscloud.im.v2.AVIMConversation;
6 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
7 | import com.avos.avoscloud.im.v2.AVIMTypedMessageHandler;
8 |
9 | import cn.leancloud.leancloudlivekit.LCLiveKit;
10 | import cn.leancloud.leancloudlivekit.im.LCLKIMMessageEvent;
11 | import de.greenrobot.event.EventBus;
12 |
13 | /**
14 | * Created by wli on 16/8/4.
15 | */
16 | public class LCLKMessageHandler extends AVIMTypedMessageHandler {
17 |
18 | private Context context;
19 |
20 | public LCLKMessageHandler(Context context) {
21 | this.context = context.getApplicationContext();
22 | }
23 |
24 | @Override
25 | public void onMessage(AVIMTypedMessage message, AVIMConversation conversation, AVIMClient client) {
26 | if (message == null || message.getMessageId() == null) {
27 | return;
28 | }
29 |
30 | if (LCLiveKit.getInstance().getCurrentUserId() == null) {
31 | client.close(null);
32 | } else {
33 | if (!client.getClientId().equals(LCLiveKit.getInstance().getCurrentUserId())) {
34 | client.close(null);
35 | } else {
36 | if (!message.getFrom().equals(client.getClientId())) {
37 | sendEvent(message, conversation);
38 | }
39 | }
40 | }
41 | }
42 |
43 | @Override
44 | public void onMessageReceipt(AVIMTypedMessage message, AVIMConversation conversation, AVIMClient client) {
45 | super.onMessageReceipt(message, conversation, client);
46 | }
47 |
48 | /**
49 | * 发送消息到来的通知事件
50 | *
51 | * @param message
52 | * @param conversation
53 | */
54 | private void sendEvent(AVIMTypedMessage message, AVIMConversation conversation) {
55 | LCLKIMMessageEvent event = new LCLKIMMessageEvent();
56 | event.message = message;
57 | event.conversation = conversation;
58 | EventBus.getDefault().post(event);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKChatAdapter.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.ViewGroup;
5 |
6 | import com.avos.avoscloud.im.v2.AVIMMessage;
7 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * Created by wli on 16/7/22.
14 | */
15 | public class LCLKChatAdapter extends RecyclerView.Adapter {
16 |
17 | private final int CHAT_ITEM_IM_TYPE = 100;
18 | private final int CHAT_ITEM_STATUS_TYPE = 200;
19 |
20 | int maxMessageCount = 120;
21 | int removeCountTime = 50;
22 |
23 | protected List messageList = new ArrayList();
24 |
25 | public LCLKChatAdapter() {
26 | super();
27 | }
28 |
29 | /**
30 | * 添加多条消息记录
31 | *
32 | * @param messages
33 | */
34 | public void addDataList(List messages) {
35 | messageList.addAll(messages);
36 | if (messageList.size() > maxMessageCount) {
37 | messageList = messageList.subList(removeCountTime, messageList.size());
38 | }
39 | }
40 |
41 | @Override
42 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
43 | switch (viewType) {
44 | case CHAT_ITEM_IM_TYPE:
45 | return new LCLKChatItemTextHolder(parent.getContext(), parent);
46 | case CHAT_ITEM_STATUS_TYPE:
47 | return new LCLKChatItemStatusHolder(parent.getContext(), parent);
48 | }
49 | return new LCLKChatItemStatusHolder(parent.getContext(), parent);
50 | }
51 |
52 | @Override
53 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
54 | ((LCLKCommonViewHolder) holder).bindData(messageList.get(position));
55 | }
56 |
57 | @Override
58 | public int getItemViewType(int position) {
59 | AVIMMessage message = messageList.get(position);
60 | if (null != message && message instanceof LCLKIMStatusMessage) {
61 | return CHAT_ITEM_STATUS_TYPE;
62 | }
63 | return CHAT_ITEM_IM_TYPE;
64 | }
65 |
66 | @Override
67 | public int getItemCount() {
68 | return messageList.size();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKChatItemStatusHolder.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.content.Context;
4 | import android.view.ViewGroup;
5 | import android.widget.TextView;
6 | import cn.leancloud.leancloudlivekit.R;
7 |
8 | /**
9 | * Created by wli on 16/8/18.
10 | */
11 | public class LCLKChatItemStatusHolder extends LCLKCommonViewHolder {
12 |
13 | private TextView contentView;
14 |
15 | public LCLKChatItemStatusHolder(Context context, ViewGroup root) {
16 | super(context, root, R.layout.lclk_im_chat_status_item);
17 | contentView = (TextView) itemView.findViewById(R.id.lclk_im_status_item_view);
18 | }
19 |
20 | public static ViewHolderCreator HOLDER_CREATOR = new ViewHolderCreator() {
21 | @Override
22 | public LCLKChatItemStatusHolder createByViewGroupAndType(ViewGroup parent, int viewType) {
23 | return new LCLKChatItemStatusHolder(parent.getContext(), parent);
24 | }
25 | };
26 |
27 | @Override
28 | public void bindData(LCLKIMStatusMessage statusMessage) {
29 | contentView.setText(statusMessage.getStatusContent());
30 | }
31 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKChatItemTextHolder.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import android.widget.TextView;
8 |
9 | import com.squareup.picasso.Picasso;
10 |
11 | import cn.leancloud.leancloudlivekit.R;
12 |
13 | /**
14 | * Created by wli on 16/8/4.
15 | */
16 | public class LCLKChatItemTextHolder extends LCLKCommonViewHolder {
17 |
18 | private ImageView avatarView;
19 | private TextView nameView;
20 | private TextView contentView;
21 |
22 | public LCLKChatItemTextHolder(Context context, ViewGroup root) {
23 | super(context, root, R.layout.lclk_im_chat_item_text_layout);
24 | initView();
25 | }
26 |
27 | public void initView() {
28 | avatarView = (ImageView) itemView.findViewById(R.id.im_chat_item_text_avatar_view);
29 | contentView = (TextView) itemView.findViewById(R.id.im_chat_item_text_content_view);
30 | nameView = (TextView) itemView.findViewById(R.id.im_chat_item_text_name_view);
31 | }
32 |
33 | public static ViewHolderCreator HOLDER_CREATOR = new ViewHolderCreator() {
34 | @Override
35 | public LCLKChatItemTextHolder createByViewGroupAndType(ViewGroup parent, int viewType) {
36 | return new LCLKChatItemTextHolder(parent.getContext(), parent);
37 | }
38 | };
39 |
40 | @Override
41 | public void bindData(LCLKIMMessage LCLKIMMessage) {
42 | if (null != LCLKIMMessage) {
43 | if (!TextUtils.isEmpty(LCLKIMMessage.getName())) {
44 | nameView.setText(LCLKIMMessage.getName());
45 | }
46 | if (!TextUtils.isEmpty(LCLKIMMessage.getAvatar())) {
47 | Picasso.with(getContext()).load(LCLKIMMessage.getAvatar()).placeholder(R.mipmap.lclk_default_avatar_icon).into(avatarView);
48 | }
49 | contentView.setText(LCLKIMMessage.getMessageContent());
50 | } else {
51 | nameView.setText("");
52 | avatarView.setImageResource(R.mipmap.lclk_default_avatar_icon);
53 | contentView.setText("");
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKCommonListAdapter.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.ViewGroup;
5 |
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.List;
9 |
10 | /**
11 | * Created by wli on 16/8/4.
12 | */
13 | public class LCLKCommonListAdapter extends RecyclerView.Adapter {
14 |
15 | private static HashMap creatorHashMap = new HashMap<>();
16 |
17 | private Class> vhClass;
18 |
19 | protected List dataList = new ArrayList();
20 |
21 | public LCLKCommonListAdapter() {
22 | super();
23 | }
24 |
25 | public LCLKCommonListAdapter(Class> vhClass) {
26 | this.vhClass = vhClass;
27 | }
28 |
29 | /**
30 | * 获取该 Adapter 中存的数据
31 | *
32 | * @return
33 | */
34 | public List getDataList() {
35 | return dataList;
36 | }
37 |
38 | /**
39 | * 设置数据,会清空以前数据
40 | *
41 | * @param datas
42 | */
43 | public void setDataList(List datas) {
44 | dataList.clear();
45 | if (null != datas) {
46 | dataList.addAll(datas);
47 | }
48 | }
49 |
50 | /**
51 | * 添加数据,默认在最后插入,以前数据保留
52 | *
53 | * @param datas
54 | */
55 | public void addDataList(List datas) {
56 | dataList.addAll(datas);
57 | }
58 |
59 | @Override
60 | public LCLKCommonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
61 | if (null == vhClass) {
62 | try {
63 | throw new IllegalArgumentException("please use CommonListAdapter(Class vhClass)");
64 | } catch (Exception e) {
65 | }
66 | }
67 |
68 | LCLKCommonViewHolder.ViewHolderCreator> creator = null;
69 | if (creatorHashMap.containsKey(vhClass.getName())) {
70 | creator = creatorHashMap.get(vhClass.getName());
71 | } else {
72 | try {
73 | creator = (LCLKCommonViewHolder.ViewHolderCreator) vhClass.getField("HOLDER_CREATOR").get(null);
74 | creatorHashMap.put(vhClass.getName(), creator);
75 | } catch (IllegalAccessException e) {
76 | } catch (NoSuchFieldException e) {
77 | }
78 | }
79 | if (null != creator) {
80 | return creator.createByViewGroupAndType(parent, viewType);
81 | } else {
82 | throw new IllegalArgumentException(vhClass.getName() + " HOLDER_CREATOR should be instantiated");
83 | }
84 | }
85 |
86 | @Override
87 | public void onBindViewHolder(LCLKCommonViewHolder holder, int position) {
88 | if (position >= 0 && position < dataList.size()) {
89 | holder.bindData(dataList.get(position));
90 | }
91 | }
92 |
93 | @Override
94 | public int getItemCount() {
95 | return dataList.size();
96 | }
97 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKCommonViewHolder.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.ViewGroup;
7 |
8 | /**
9 | * Created by wli on 16/8/4.
10 | */
11 | public abstract class LCLKCommonViewHolder extends RecyclerView.ViewHolder {
12 |
13 | public LCLKCommonViewHolder(Context context, ViewGroup root, int layoutRes) {
14 | super(LayoutInflater.from(context).inflate(layoutRes, root, false));
15 | }
16 |
17 | public Context getContext() {
18 | return itemView.getContext();
19 | }
20 |
21 | /**
22 | * 用给定的 data 对 holder 的 view 进行赋值
23 | */
24 | public abstract void bindData(T t);
25 |
26 | public void setData(T t) {
27 | bindData(t);
28 | }
29 |
30 | /**
31 | * 因为 CommonListAdapter 里边无法对于未知类型的 Class 进行实例化
32 | * 所以需要如果想用 CommonListAdapter,必须要在对应的 CommonViewHolder 实例化一个 HOLDER_CREATOR
33 | * 注意:public static ViewHolderCreator HOLDER_CREATOR,名字与修饰符都不能更改,否则有可能引发失败
34 | * 具体样例可参见 DiscoverItemHolder
35 | * 如果不使用 CommonListAdapter,则不需要实例化 ViewHolderCreator
36 | *
37 | * @param
38 | */
39 | public interface ViewHolderCreator {
40 | public VH createByViewGroupAndType(ViewGroup parent, int viewType);
41 | }
42 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKGiftDialogFragment.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.app.Dialog;
4 | import android.content.DialogInterface;
5 | import android.graphics.Color;
6 | import android.graphics.drawable.ColorDrawable;
7 | import android.os.Bundle;
8 | import android.support.v4.app.DialogFragment;
9 | import android.support.v4.view.ViewPager;
10 | import android.support.v7.widget.GridLayout;
11 | import android.view.Gravity;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.view.Window;
15 | import android.view.WindowManager;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | import cn.leancloud.leancloudlivekit.R;
21 |
22 | /**
23 | * Created by wli on 16/7/22.
24 | */
25 | public class LCLKGiftDialogFragment extends DialogFragment {
26 |
27 | GridLayout currentLayout = null;
28 |
29 | ViewPager viewPager;
30 |
31 | LCLKGiftPagerAdapter pagerAdapter;
32 |
33 | List giftViewList = new ArrayList<>();
34 |
35 | DialogInterface.OnDismissListener onDismissListener;
36 |
37 |
38 | int pageWidth = 4;
39 | int pagerHeight = 2;
40 |
41 | @Override
42 | public void onDismiss(DialogInterface dialog) {
43 | super.onDismiss(dialog);
44 | if (null != onDismissListener) {
45 | onDismissListener.onDismiss(dialog);
46 | }
47 | }
48 |
49 | @Override
50 | public Dialog onCreateDialog(Bundle savedInstanceState) {
51 | // 使用不带Theme的构造器, 获得的dialog边框距离屏幕仍有几毫米的缝隙。
52 | Dialog dialog = new Dialog(getActivity(), R.style.LCLKBottomDialog);
53 |
54 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // 设置Content前设定
55 | dialog.setContentView(R.layout.lclk_gift_dialog);
56 | dialog.setCanceledOnTouchOutside(true); // 外部点击取消
57 | dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
58 |
59 | viewPager = (ViewPager) dialog.findViewById(R.id.lift_gift_dialog_pager);
60 |
61 | pagerAdapter = new LCLKGiftPagerAdapter();
62 | viewPager.setAdapter(pagerAdapter);
63 |
64 | // 设置宽度为屏宽, 靠近屏幕底部。
65 | Window window = dialog.getWindow();
66 | window.getWindowManager().getDefaultDisplay().getWidth();
67 | WindowManager.LayoutParams lp = window.getAttributes();
68 | lp.gravity = Gravity.BOTTOM; // 紧贴底部
69 | lp.width = WindowManager.LayoutParams.MATCH_PARENT; // 宽度持平
70 | window.setAttributes(lp);
71 |
72 | initGridView();
73 | return dialog;
74 | }
75 |
76 | public void setViews(List viewList) {
77 | giftViewList.clear();
78 | if (null != viewList) {
79 | giftViewList.addAll(viewList);
80 | }
81 | initGridView();
82 | }
83 |
84 | public void setOnDismissListener(final DialogInterface.OnDismissListener listener) {
85 | onDismissListener = listener;
86 | }
87 |
88 | private void initGridView() {
89 | if (null != pagerAdapter) {
90 | final int screenWidth = getResources().getDisplayMetrics().widthPixels;
91 | final int dialogHeight = getResources().getDimensionPixelOffset(R.dimen.lclk_live_gift_dialog_height);
92 | if(currentLayout != null) {
93 | currentLayout.removeAllViews();
94 | currentLayout = null;
95 | }
96 | for (View view : giftViewList) {
97 | if (null == currentLayout || currentLayout.getChildCount() >= pageWidth * pagerHeight) {
98 | currentLayout = new GridLayout(view.getContext());
99 | currentLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
100 | currentLayout.setColumnCount(pageWidth);
101 | currentLayout.setRowCount(pagerHeight);
102 | currentLayout.setUseDefaultMargins(true);
103 | pagerAdapter.addView(currentLayout);
104 | }
105 | view.setLayoutParams(new ViewGroup.LayoutParams(screenWidth / pageWidth, dialogHeight / pagerHeight));
106 | currentLayout.addView(view);
107 | }
108 | pagerAdapter.notifyDataSetChanged();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKGiftItem.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | /**
4 | * Created by wli on 16/9/12.
5 | */
6 | class LCLKGiftItem {
7 | int giftResource;
8 | String giftName;
9 | int giftMessageIndex;
10 |
11 | public LCLKGiftItem(int giftMessageIndex, String giftName, int giftResource) {
12 | this.giftMessageIndex = giftMessageIndex;
13 | this.giftName = giftName;
14 | this.giftResource = giftResource;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKGiftManager.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.HashMap;
6 | import java.util.List;
7 |
8 | /**
9 | * Created by wli on 16/9/12.
10 | */
11 | public class LCLKGiftManager {
12 |
13 | private static LCLKGiftManager giftManager;
14 |
15 | private HashMap giftItemHashMap = new HashMap<>();
16 |
17 | public synchronized static LCLKGiftManager getInstance() {
18 | if (null == giftManager) {
19 | giftManager = new LCLKGiftManager();
20 | }
21 | return giftManager;
22 | }
23 |
24 | private LCLKGiftManager() {
25 | }
26 |
27 | public List getGiftList() {
28 | ArrayList giftItemList = new ArrayList<>();
29 | giftItemList.addAll(giftItemHashMap.values());
30 | return giftItemList;
31 | }
32 |
33 | public void addGiftItem(LCLKGiftItem giftItem) {
34 | giftItemHashMap.put(giftItem.giftMessageIndex, giftItem);
35 | }
36 |
37 | public LCLKGiftItem getGiftItem(int messageIdex) {
38 | if (giftItemHashMap.containsKey(messageIdex)) {
39 | return giftItemHashMap.get(messageIdex);
40 | }
41 | return null;
42 | }
43 |
44 | public void clearGiftList() {
45 | giftItemHashMap.clear();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKGiftMessage.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMMessageCreator;
4 | import com.avos.avoscloud.im.v2.AVIMMessageField;
5 | import com.avos.avoscloud.im.v2.AVIMMessageType;
6 |
7 | /**
8 | * Created by wli on 16/7/26.
9 | */
10 | @AVIMMessageType(type = LCLKIMMessage.LIVE_IM_GIFT_MESSAGE_TYPE)
11 | public class LCLKGiftMessage extends LCLKIMMessage {
12 |
13 | public static final String LIVE_GIFT_MESSAGE_NUMBER_KEY = "number";
14 | public static final String LIVE_GIFT_MESSAGE_INDEX_KEY = "index";
15 |
16 | @AVIMMessageField(name = LIVE_GIFT_MESSAGE_NUMBER_KEY)
17 | private int number;
18 |
19 | @AVIMMessageField(name = LIVE_GIFT_MESSAGE_INDEX_KEY)
20 | private int giftIndex;
21 |
22 | public LCLKGiftMessage() {
23 | super();
24 | }
25 |
26 | public static final Creator CREATOR = new AVIMMessageCreator(LCLKGiftMessage.class);
27 |
28 | public int getNumber() {
29 | return number;
30 | }
31 |
32 | public void setNumber(int number) {
33 | this.number = number;
34 | }
35 |
36 |
37 | public int getGiftIndex() {
38 | return giftIndex;
39 | }
40 |
41 | public void setGiftIndex(int giftIndex) {
42 | this.giftIndex = giftIndex;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKGiftPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.support.v4.view.PagerAdapter;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | import com.avos.avoscloud.im.v2.AVIMClient;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 |
13 | /**
14 | * Created by wli on 16/8/3.
15 | */
16 | public class LCLKGiftPagerAdapter extends PagerAdapter {
17 |
18 | protected List viewList = new ArrayList();
19 |
20 | public LCLKGiftPagerAdapter() {
21 | }
22 |
23 | public void setViewList(List views) {
24 | viewList.clear();
25 | if (null != views && views.size() > 0) {
26 | viewList.addAll(views);
27 | }
28 | }
29 |
30 | public void addView(View view) {
31 | if (null != view) {
32 | viewList.add(view);
33 | }
34 | }
35 |
36 | @Override
37 | public int getCount() {
38 | return viewList.size();
39 | }
40 |
41 | @Override
42 | public boolean isViewFromObject(View view, Object object) {
43 | return view == object;
44 | }
45 |
46 | @Override
47 | public Object instantiateItem(ViewGroup container, int position) {
48 | if (position >=0 && position < viewList.size()) {
49 | View view = viewList.get(position);
50 | container.addView(view);
51 | return view;
52 | }
53 | return null;
54 | }
55 |
56 | @Override
57 | public void destroyItem(ViewGroup container, int position, Object object) {
58 | container.removeView(viewList.get(position));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKIMBarrageMessage.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMMessageCreator;
4 | import com.avos.avoscloud.im.v2.AVIMMessageType;
5 |
6 | /**
7 | * Created by wli on 16/7/26.
8 | */
9 | @AVIMMessageType(type = LCLKIMMessage.LIVE_IM_BARRAGE_MESSAGE_TYPE)
10 | public class LCLKIMBarrageMessage extends LCLKIMMessage {
11 |
12 | public LCLKIMBarrageMessage() {
13 | super();
14 | }
15 |
16 | public static final Creator CREATOR = new AVIMMessageCreator(LCLKIMBarrageMessage.class);
17 | }
18 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKIMFragment.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.content.DialogInterface;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.SwitchCompat;
10 | import android.text.Editable;
11 | import android.text.TextUtils;
12 | import android.text.TextWatcher;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.view.WindowManager;
17 | import android.widget.EditText;
18 | import android.widget.ImageView;
19 | import android.widget.LinearLayout;
20 | import android.widget.TextView;
21 |
22 | import com.avos.avoscloud.AVCallback;
23 | import com.avos.avoscloud.AVException;
24 | import com.avos.avoscloud.im.v2.AVIMConversation;
25 | import com.avos.avoscloud.im.v2.AVIMException;
26 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
27 | import com.avos.avoscloud.im.v2.callback.AVIMConversationCallback;
28 | import com.squareup.picasso.Picasso;
29 |
30 | import java.util.ArrayList;
31 | import java.util.Arrays;
32 | import java.util.List;
33 |
34 | import cn.leancloud.leancloudlivekit.LCLiveKit;
35 | import cn.leancloud.leancloudlivekit.LCLKUser;
36 | import cn.leancloud.leancloudlivekit.R;
37 | import cn.leancloud.leancloudlivekit.barrage.LCLKBarrageLayout;
38 | import cn.leancloud.leancloudlivekit.utils.LCLKConstants;
39 | import de.greenrobot.event.EventBus;
40 |
41 | /**
42 | * Created by wli on 16/8/4.
43 | */
44 | public class LCLKIMFragment extends Fragment {
45 |
46 | /**
47 | * recyclerView 对应的 Adapter
48 | */
49 | protected LCLKChatAdapter itemAdapter;
50 | protected LinearLayoutManager layoutManager;
51 | protected AVIMConversation imConversation;
52 |
53 | ImageView avatarView;
54 | TextView nameView;
55 | ImageView closeView;
56 | LCLKBarrageLayout giftLayout;
57 | LCLKBarrageLayout barrageLayout;
58 | EditText inputView;
59 | TextView sendButton;
60 | TextView giftView;
61 | LinearLayout inputLayout;
62 | SwitchCompat barrageSwitch;
63 | RecyclerView recyclerView;
64 | TextView newMessageTipView;
65 | LCLKGiftDialogFragment giftDialogFragment;
66 |
67 | private boolean isBottom = true;
68 |
69 |
70 | @Nullable
71 | @Override
72 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
73 | View view = inflater.inflate(R.layout.lclk_im_fragment, container, false);
74 | initView(view);
75 | EventBus.getDefault().register(this);
76 | getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
77 | return view;
78 | }
79 |
80 | private void initView(View view) {
81 | avatarView = (ImageView) view.findViewById(R.id.lclk_live_im_personal_avatar_view);
82 | nameView = (TextView) view.findViewById(R.id.lclk_live_im_personal_name_view);
83 | closeView = (ImageView) view.findViewById(R.id.lclk_live_im_personal_close_view);
84 | giftLayout = (LCLKBarrageLayout) view.findViewById(R.id.live_im_gift_barrage_view);
85 | barrageLayout = (LCLKBarrageLayout) view.findViewById(R.id.live_im_barrage_barrage_view);
86 | inputView = (EditText) view.findViewById(R.id.live_im_input_input_view);
87 | sendButton = (TextView) view.findViewById(R.id.live_im_input_send_view);
88 | giftView = (TextView) view.findViewById(R.id.live_im_input_gift_view);
89 | inputLayout = (LinearLayout) view.findViewById(R.id.live_im_input_layout);
90 | barrageSwitch = (SwitchCompat) view.findViewById(R.id.live_im_input_barrage_switch);
91 | recyclerView = (RecyclerView) view.findViewById(R.id.fragment_chat_rv_chat);
92 | newMessageTipView = (TextView) view.findViewById(R.id.fragment_chat_new_message_tip_view);
93 |
94 | sendButton.setOnClickListener(new View.OnClickListener() {
95 | @Override
96 | public void onClick(View v) {
97 | onSendClick();
98 | }
99 | });
100 |
101 | giftView.setOnClickListener(new View.OnClickListener() {
102 | @Override
103 | public void onClick(View v) {
104 | onGiftClick();
105 | }
106 | });
107 |
108 | newMessageTipView.setOnClickListener(new View.OnClickListener() {
109 | @Override
110 | public void onClick(View v) {
111 | onNewMessageClick();
112 | }
113 | });
114 |
115 | closeView.setOnClickListener(new View.OnClickListener() {
116 | @Override
117 | public void onClick(View v) {
118 | onCloseClick();
119 | }
120 | });
121 |
122 | initGift();
123 | initGiftDialog();
124 | }
125 |
126 | @Override
127 | public void onDestroyView() {
128 | EventBus.getDefault().unregister(this);
129 | super.onDestroyView();
130 | }
131 |
132 | @Override
133 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
134 | super.onViewCreated(view, savedInstanceState);
135 |
136 | initAnchorInfo();
137 | initIMView();
138 |
139 | inputView.addTextChangedListener(new TextWatcher() {
140 | @Override
141 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
142 | }
143 |
144 | @Override
145 | public void onTextChanged(CharSequence s, int start, int before, int count) {
146 | if (TextUtils.isEmpty(s)) {
147 | barrageSwitch.setVisibility(View.INVISIBLE);
148 | giftView.setVisibility(View.VISIBLE);
149 | } else {
150 | barrageSwitch.setVisibility(View.VISIBLE);
151 | giftView.setVisibility(View.INVISIBLE);
152 | }
153 | }
154 |
155 | @Override
156 | public void afterTextChanged(Editable s) {
157 | }
158 | });
159 | }
160 |
161 | private void initGift() {
162 | LCLKGiftManager giftManager = LCLKGiftManager.getInstance();
163 | giftManager.clearGiftList();
164 | giftManager.addGiftItem(new LCLKGiftItem(1, "", R.mipmap.lclk_im_gift_1));
165 | giftManager.addGiftItem(new LCLKGiftItem(2, "", R.mipmap.lclk_im_gift_2));
166 | giftManager.addGiftItem(new LCLKGiftItem(3, "", R.mipmap.lclk_im_gift_3));
167 | giftManager.addGiftItem(new LCLKGiftItem(4, "", R.mipmap.lclk_im_gift_4));
168 | giftManager.addGiftItem(new LCLKGiftItem(5, "", R.mipmap.lclk_im_gift_5));
169 | giftManager.addGiftItem(new LCLKGiftItem(6, "", R.mipmap.lclk_im_gift_6));
170 | giftManager.addGiftItem(new LCLKGiftItem(7, "", R.mipmap.lclk_im_gift_7));
171 | giftManager.addGiftItem(new LCLKGiftItem(8, "", R.mipmap.lclk_im_gift_8));
172 | }
173 |
174 | private void initGiftDialog() {
175 | giftDialogFragment = new LCLKGiftDialogFragment();
176 | giftDialogFragment.setOnDismissListener(new DialogInterface.OnDismissListener() {
177 | @Override
178 | public void onDismiss(DialogInterface dialog) {
179 | inputLayout.setVisibility(View.VISIBLE);
180 | }
181 | });
182 |
183 | LCLKGiftManager giftManager = LCLKGiftManager.getInstance();
184 | List giftItemList = giftManager.getGiftList();
185 | List viewList = new ArrayList<>();
186 | for (LCLKGiftItem giftItem : giftItemList) {
187 | viewList.add(getGiftItem(giftItem));
188 | }
189 | giftDialogFragment.setViews(viewList);
190 | }
191 |
192 | public void setConversation(final AVIMConversation conversation) {
193 | imConversation = conversation;
194 | imConversation.join(new AVIMConversationCallback() {
195 | @Override
196 | public void done(AVIMException e) {
197 | if (null == e) {
198 | sendJoinMessage();
199 | }
200 | }
201 | });
202 | }
203 |
204 | private void sendJoinMessage() {
205 | String clientId = LCLiveKit.getInstance().getCurrentUserId();
206 |
207 | LCLiveKit.getInstance().getProfileProvider().fetchProfiles(Arrays.asList(clientId), new AVCallback>() {
208 | @Override
209 | protected void internalDone0(List lclkUsers, AVException e) {
210 | String userName = "";
211 | if (null != lclkUsers && lclkUsers.size() > 0) {
212 | userName = lclkUsers.get(0).getUserName();
213 | }
214 | if (TextUtils.isEmpty(userName)) {
215 | userName = "游客";
216 | }
217 | LCLKIMStatusMessage message = new LCLKIMStatusMessage();
218 | message.setStatusContent(userName + "来了");
219 | imConversation.sendMessage(message, null);
220 | }
221 | });
222 | }
223 |
224 | private void initAnchorInfo() {
225 | String anchorId = getActivity().getIntent().getStringExtra(LCLKConstants.ANCHOR_ID);
226 | LCLiveKit.getInstance().getProfileProvider().fetchProfiles(Arrays.asList(anchorId), new AVCallback>() {
227 | @Override
228 | public void internalDone0(List userList, AVException exception) {
229 | if (null == exception && null != userList && userList.size() > 0) {
230 | final String avatar = userList.get(0).getAvatarUrl();
231 | if (!TextUtils.isEmpty(avatar)) {
232 | Picasso.with(getContext()).load(avatar).into(avatarView);
233 | }
234 | nameView.setText(userList.get(0).getUserName());
235 | }
236 | }
237 | });
238 | }
239 |
240 | private void initIMView() {
241 | layoutManager = new LinearLayoutManager(getContext());
242 | recyclerView.setLayoutManager(layoutManager);
243 |
244 | itemAdapter = new LCLKChatAdapter();
245 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
246 | @Override
247 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
248 | super.onScrollStateChanged(recyclerView, newState);
249 | }
250 |
251 | @Override
252 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
253 | super.onScrolled(recyclerView, dx, dy);
254 | if (null != layoutManager && layoutManager.getItemCount() > 0) {
255 | isBottom = (layoutManager.getItemCount() == layoutManager.findLastVisibleItemPosition() + 1);
256 | if (isBottom) {
257 | newMessageTipView.setVisibility(View.GONE);
258 | }
259 | }
260 | }
261 | });
262 | recyclerView.setAdapter(itemAdapter);
263 | }
264 |
265 | private void onSendClick() {
266 | if (barrageSwitch.isChecked()) {
267 | sendBarrage(inputView.getText().toString());
268 | } else {
269 | sendText(inputView.getText().toString());
270 | }
271 | }
272 |
273 | private void onGiftClick() {
274 | inputLayout.setVisibility(View.INVISIBLE);
275 | giftDialogFragment.show(getFragmentManager(), "dialog");
276 | }
277 |
278 | private View getGiftItem(final LCLKGiftItem giftItem) {
279 | View giftItemView = getActivity().getLayoutInflater().inflate(R.layout.lclk_gift_item, null);
280 | ImageView iconView = (ImageView) giftItemView.findViewById(R.id.live_gift_item_icon_view);
281 | TextView nameView = (TextView) giftItemView.findViewById(R.id.live_gift_item_name_view);
282 | iconView.setImageResource(giftItem.giftResource);
283 | nameView.setText(giftItem.giftName);
284 | giftItemView.setOnClickListener(new View.OnClickListener() {
285 | @Override
286 | public void onClick(View v) {
287 | sendGift(giftItem);
288 | }
289 | });
290 | return giftItemView;
291 | }
292 |
293 | private void onNewMessageClick() {
294 | scrollToBottom();
295 | }
296 |
297 | /**
298 | * 处理推送过来的消息
299 | * 同理,避免无效消息,此处加了 conversation id 判断
300 | */
301 | public void onEvent(LCLKIMMessageEvent messageEvent) {
302 | if (null != imConversation && null != messageEvent &&
303 | imConversation.getConversationId().equals(messageEvent.conversation.getConversationId())) {
304 | if (messageEvent.message instanceof LCLKIMBarrageMessage) {
305 | addBarrage((LCLKIMBarrageMessage) messageEvent.message);
306 | } else if (messageEvent.message instanceof LCLKGiftMessage) {
307 | addGiftBarrage((LCLKGiftMessage) messageEvent.message);
308 | } else if (messageEvent.message instanceof LCLKIMMessage
309 | || messageEvent.message instanceof LCLKIMStatusMessage) {
310 | itemAdapter.addDataList(Arrays.asList(messageEvent.message));
311 | itemAdapter.notifyDataSetChanged();
312 | if (isBottom) {
313 | scrollToBottom();
314 | } else {
315 | newMessageTipView.setVisibility(View.VISIBLE);
316 | }
317 | }
318 | }
319 | }
320 |
321 | /**
322 | * 滚动 recyclerView 到底部
323 | */
324 | private void scrollToBottom() {
325 | layoutManager.scrollToPositionWithOffset(itemAdapter.getItemCount() - 1, 0);
326 | }
327 |
328 | private void sendGift(final LCLKGiftItem giftItem) {
329 | LCLiveKit.getInstance().getProfileProvider().fetchProfiles(
330 | Arrays.asList(LCLiveKit.getInstance().getCurrentUserId()), new AVCallback>() {
331 | @Override
332 | protected void internalDone0(List lclkUsers, AVException e) {
333 | if (null == e && null != lclkUsers && lclkUsers.size() > 0) {
334 | final LCLKGiftMessage message = new LCLKGiftMessage();
335 | message.setMessageContent(giftItem.giftName);
336 | message.setName(lclkUsers.get(0).getUserName());
337 | message.setAvatar(lclkUsers.get(0).getAvatarUrl());
338 | message.setGiftIndex(giftItem.giftMessageIndex);
339 |
340 | imConversation.sendMessage(message, new AVIMConversationCallback() {
341 | @Override
342 | public void done(AVIMException e) {
343 | addGiftBarrage(message);
344 | }
345 | });
346 | }
347 | }
348 | });
349 | }
350 |
351 | private void sendBarrage(final String content) {
352 | LCLiveKit.getInstance().getProfileProvider().fetchProfiles(
353 | Arrays.asList(LCLiveKit.getInstance().getCurrentUserId()), new AVCallback>() {
354 | @Override
355 | protected void internalDone0(List lclkUsers, AVException e) {
356 | if (null == e && null != lclkUsers && lclkUsers.size() > 0) {
357 | final LCLKIMBarrageMessage message = new LCLKIMBarrageMessage();
358 | message.setMessageContent(content);
359 | message.setName(lclkUsers.get(0).getUserName());
360 | message.setAvatar(lclkUsers.get(0).getAvatarUrl());
361 | imConversation.sendMessage(message, new AVIMConversationCallback() {
362 | @Override
363 | public void done(AVIMException e) {
364 | addBarrage(message);
365 | }
366 | });
367 | }
368 | }
369 | });
370 | }
371 |
372 | private void addBarrage(LCLKIMBarrageMessage message) {
373 | View view = getActivity().getLayoutInflater().inflate(R.layout.lclk_barrage_item, null);
374 | ImageView avatarView = (ImageView) view.findViewById(R.id.live_barrage_item_avatar_view);
375 | TextView nameView = (TextView) view.findViewById(R.id.live_barrage_item_name_view);
376 | TextView contentView = (TextView) view.findViewById(R.id.live_barrage_item_content_view);
377 |
378 | Picasso.with(getContext()).load(message.getAvatar()).into(avatarView);
379 | nameView.setText(message.getName());
380 | contentView.setText(message.getMessageContent());
381 | barrageLayout.sendView(view);
382 | }
383 |
384 | private void addGiftBarrage(LCLKGiftMessage message) {
385 | View view = getActivity().getLayoutInflater().inflate(R.layout.lclk_barrage_gift_item, null);
386 | ImageView avatarView = (ImageView) view.findViewById(R.id.live_barrage_gift_icon_view);
387 | TextView nameView = (TextView) view.findViewById(R.id.live_barrage_gift_name_view);
388 | TextView numberView = (TextView) view.findViewById(R.id.live_barrage_gift_number_view);
389 |
390 | avatarView.setImageResource(LCLKGiftManager.getInstance().getGiftItem(message.getGiftIndex()).giftResource);
391 | nameView.setText(message.getName());
392 | if (message.getNumber() > 0) {
393 | numberView.setText(message.getNumber() + "");
394 | numberView.setVisibility(View.VISIBLE);
395 | }
396 | giftLayout.sendView(view);
397 | }
398 |
399 | /**
400 | * 发送文本消息
401 | *
402 | * @param content
403 | */
404 | protected void sendText(final String content) {
405 | LCLiveKit.getInstance().getProfileProvider().fetchProfiles(
406 | Arrays.asList(LCLiveKit.getInstance().getCurrentUserId()), new AVCallback>() {
407 | @Override
408 | protected void internalDone0(List lclkUsers, AVException e) {
409 | if (null == e && null != lclkUsers && lclkUsers.size() > 0) {
410 | LCLKIMMessage message = new LCLKIMMessage();
411 | message.setMessageContent(content);
412 | message.setName(lclkUsers.get(0).getUserName());
413 | message.setAvatar(lclkUsers.get(0).getAvatarUrl());
414 | itemAdapter.addDataList(Arrays.asList((AVIMTypedMessage) message));
415 | itemAdapter.notifyDataSetChanged();
416 | scrollToBottom();
417 | imConversation.sendMessage(message, new AVIMConversationCallback() {
418 | @Override
419 | public void done(AVIMException e) {
420 | itemAdapter.notifyDataSetChanged();
421 | }
422 | });
423 | }
424 | }
425 | });
426 | }
427 |
428 | private void onCloseClick() {
429 | getActivity().finish();
430 | }
431 | }
432 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKIMMessage.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMMessageCreator;
4 | import com.avos.avoscloud.im.v2.AVIMMessageField;
5 | import com.avos.avoscloud.im.v2.AVIMMessageType;
6 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
7 |
8 | /**
9 | * Created by wli on 16/7/22.
10 | */
11 | @AVIMMessageType(type = LCLKIMMessage.LIVE_IM_TEXT_MESSAGE_TYPE)
12 | public class LCLKIMMessage extends AVIMTypedMessage {
13 |
14 | public static final int LIVE_IM_TEXT_MESSAGE_TYPE = 5001;
15 | public static final int LIVE_IM_STATUS_MESSAGE_TYPE = 5002;
16 | public static final int LIVE_IM_GIFT_MESSAGE_TYPE = 5003;
17 | public static final int LIVE_IM_BARRAGE_MESSAGE_TYPE = 5004;
18 |
19 | public static final String LIVE_MESSAGE_AVATAR_KEY = "avatar";
20 | public static final String LIVE_MESSAGE_NAME_KEY = "name";
21 | public static final String LIVE_MESSAGE_CONTENT_KEY = "message_content";
22 |
23 | @AVIMMessageField(name = LIVE_MESSAGE_AVATAR_KEY)
24 | private String avatar;
25 |
26 | @AVIMMessageField(name = LIVE_MESSAGE_NAME_KEY)
27 | private String name;
28 |
29 | @AVIMMessageField(name = LIVE_MESSAGE_CONTENT_KEY)
30 | private String messageContent;
31 |
32 | public static final Creator CREATOR = new AVIMMessageCreator(LCLKIMMessage.class);
33 |
34 | public String getAvatar() {
35 | return avatar;
36 | }
37 |
38 | public void setAvatar(String avatar) {
39 | this.avatar = avatar;
40 | }
41 |
42 | public String getName() {
43 | return name;
44 | }
45 |
46 | public void setName(String name) {
47 | this.name = name;
48 | }
49 |
50 | public String getMessageContent() {
51 | return messageContent;
52 | }
53 |
54 | public void setMessageContent(String messageContent) {
55 | this.messageContent = messageContent;
56 | }
57 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKIMMessageEvent.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMConversation;
4 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
5 |
6 | /**
7 | * Created by wli on 16/8/4.
8 | */
9 | public class LCLKIMMessageEvent {
10 | public AVIMTypedMessage message;
11 | public AVIMConversation conversation;
12 | }
13 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKIMStatusMessage.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import com.avos.avoscloud.im.v2.AVIMMessageCreator;
4 | import com.avos.avoscloud.im.v2.AVIMMessageField;
5 | import com.avos.avoscloud.im.v2.AVIMMessageType;
6 | import com.avos.avoscloud.im.v2.AVIMTypedMessage;
7 |
8 | /**
9 | * Created by wli on 16/8/18.
10 | */
11 | @AVIMMessageType(type = LCLKIMMessage.LIVE_IM_STATUS_MESSAGE_TYPE)
12 | public class LCLKIMStatusMessage extends AVIMTypedMessage {
13 |
14 | public static final String LIVE_IM_STASUT_MESSAGE_KEY = "status_content";
15 |
16 | @AVIMMessageField(name = LIVE_IM_STASUT_MESSAGE_KEY)
17 | private String statusContent;
18 |
19 | public static final Creator CREATOR = new AVIMMessageCreator(LCLKIMMessage.class);
20 |
21 | public String getStatusContent() {
22 | return statusContent;
23 | }
24 |
25 | public void setStatusContent(String statusContent) {
26 | this.statusContent = statusContent;
27 | }
28 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/im/LCLKRoundCornerImageView.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.im;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Path;
6 | import android.graphics.RectF;
7 | import android.util.AttributeSet;
8 | import android.widget.ImageView;
9 |
10 | /**
11 | * Created by wli on 16/7/26.
12 | */
13 | public class LCLKRoundCornerImageView extends ImageView {
14 | public LCLKRoundCornerImageView(Context context) {
15 | super(context);
16 | }
17 | public LCLKRoundCornerImageView(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 | public LCLKRoundCornerImageView(Context context, AttributeSet attrs, int defStyle) {
21 | super(context, attrs, defStyle);
22 | }
23 | @Override
24 | protected void onDraw(Canvas canvas) {
25 | Path clipPath = new Path();
26 | int w = this.getWidth();
27 | int h = this.getHeight();
28 | clipPath.addRoundRect(new RectF(0, 0, w, h), w/2, h/2, Path.Direction.CW);
29 | canvas.clipPath(clipPath);
30 | super.onDraw(canvas);
31 | }
32 | }
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/play/LCLKPlayActivity.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.play;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 |
8 | import com.avos.avoscloud.AVCallback;
9 | import com.avos.avoscloud.AVException;
10 | import com.avos.avoscloud.im.v2.AVIMClient;
11 | import com.avos.avoscloud.im.v2.AVIMConversation;
12 | import com.avos.avoscloud.im.v2.AVIMConversationQuery;
13 | import com.avos.avoscloud.im.v2.AVIMException;
14 | import com.avos.avoscloud.im.v2.callback.AVIMConversationQueryCallback;
15 |
16 | import java.util.List;
17 |
18 | import cn.leancloud.leancloudlivekit.LCLiveKit;
19 | import cn.leancloud.leancloudlivekit.LCLiveKitProvider;
20 | import cn.leancloud.leancloudlivekit.R;
21 | import cn.leancloud.leancloudlivekit.im.LCLKIMFragment;
22 | import cn.leancloud.leancloudlivekit.utils.LCLKConstants;
23 |
24 | /**
25 | * Created by wli on 16/8/5.
26 | */
27 | public class LCLKPlayActivity extends AppCompatActivity {
28 |
29 | LCLKIMFragment lclkimFragment;
30 | LCLKPlayFragment lclkPlayFragment;
31 |
32 | @Override
33 | protected void onCreate(@Nullable Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.lclk_play_activity);
36 |
37 | lclkimFragment = (LCLKIMFragment) getSupportFragmentManager().findFragmentById(R.id.lclk_im_fragment);
38 | lclkPlayFragment = (LCLKPlayFragment) getSupportFragmentManager().findFragmentById(R.id.lclk_play_fragment);
39 |
40 | final String liveId = getIntent().getStringExtra(LCLKConstants.LIVE_ID);
41 | initConversation(liveId);
42 | initPlayFragment(liveId);
43 | }
44 |
45 | public void initPlayFragment(final String liveId) {
46 | LCLiveKitProvider provider = LCLiveKit.getInstance().getProfileProvider();
47 | if (null != provider) {
48 | provider.fetchPlayStream(liveId, new AVCallback() {
49 | @Override
50 | protected void internalDone0(String s, AVException e) {
51 | if (null == e && !TextUtils.isEmpty(s)) {
52 | lclkPlayFragment.startLive(s);
53 | }
54 | }
55 | });
56 | }
57 | }
58 |
59 | private void initConversation(String liveId) {
60 | AVIMClient client = LCLiveKit.getInstance().getClient();
61 | AVIMConversationQuery conversationQuery = client.getQuery();
62 | conversationQuery.whereEqualTo("name", liveId);
63 | conversationQuery.findInBackground(new AVIMConversationQueryCallback() {
64 | @Override
65 | public void done(List list, AVIMException e) {
66 | if (null != list && list.size() > 0) {
67 | lclkimFragment.setConversation(list.get(0));
68 | }
69 | }
70 | });
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/play/LCLKPlayFragment.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.play;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.text.TextUtils;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.view.WindowManager;
11 | import android.widget.LinearLayout;
12 | import android.widget.Toast;
13 |
14 | import com.avos.avoscloud.AVCallback;
15 | import com.avos.avoscloud.AVException;
16 | import com.pili.pldroid.player.AVOptions;
17 | import com.pili.pldroid.player.PLMediaPlayer;
18 | import com.pili.pldroid.player.widget.PLVideoTextureView;
19 | import com.pili.pldroid.player.widget.PLVideoView;
20 |
21 | import cn.leancloud.leancloudlivekit.LCLiveKit;
22 | import cn.leancloud.leancloudlivekit.LCLiveKitProvider;
23 | import cn.leancloud.leancloudlivekit.R;
24 |
25 | /**
26 | * Created by wli on 16/7/26.
27 | */
28 | public class LCLKPlayFragment extends Fragment {
29 |
30 | PLVideoTextureView videoTextureView;
31 |
32 | LinearLayout loadingLayout;
33 |
34 | private String livePath;
35 |
36 | @Nullable
37 | @Override
38 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
39 | return inflater.inflate(R.layout.lclk_play_fragment, container, false);
40 | }
41 |
42 |
43 | @Override
44 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
45 | super.onViewCreated(view, savedInstanceState);
46 | videoTextureView = (PLVideoTextureView) view.findViewById(R.id.live_play_video_textrue_view);
47 | loadingLayout = (LinearLayout) view.findViewById(R.id.live_play_loading_layout);
48 |
49 | getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
50 | videoTextureView.setBufferingIndicator(loadingLayout);
51 | startLive(livePath);
52 | }
53 |
54 | public void startLive(String livePath) {
55 | this.livePath = livePath;
56 | if (!TextUtils.isEmpty(livePath) && null != videoTextureView) {
57 | AVOptions options = new AVOptions();
58 |
59 | // the unit of timeout is ms
60 | options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
61 | options.setInteger(AVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
62 | options.setInteger(AVOptions.KEY_LIVE_STREAMING, 1);
63 | options.setInteger(AVOptions.KEY_DELAY_OPTIMIZATION, 1);
64 | options.setInteger(AVOptions.KEY_MEDIACODEC, 0);
65 | options.setInteger(AVOptions.KEY_START_ON_PREPARED, 0);
66 | videoTextureView.setAVOptions(options);
67 | videoTextureView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_PAVED_PARENT);
68 | videoTextureView.setKeepScreenOn(true);
69 | videoTextureView.setOnCompletionListener(mOnCompletionListener);
70 | videoTextureView.setOnErrorListener(mOnErrorListener);
71 | videoTextureView.setVideoPath(livePath);
72 | videoTextureView.start();
73 | }
74 | }
75 |
76 | private PLMediaPlayer.OnErrorListener mOnErrorListener = new PLMediaPlayer.OnErrorListener() {
77 | @Override
78 | public boolean onError(PLMediaPlayer mp, int errorCode) {
79 | switch (errorCode) {
80 | case PLMediaPlayer.ERROR_CODE_INVALID_URI:
81 | showToastTips("Invalid URL !");
82 | break;
83 | case PLMediaPlayer.ERROR_CODE_404_NOT_FOUND:
84 | showToastTips("404 resource not found !");
85 | break;
86 | case PLMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
87 | showToastTips("Connection refused !");
88 | break;
89 | case PLMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
90 | showToastTips("Connection timeout !");
91 | break;
92 | case PLMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
93 | showToastTips("Empty playlist !");
94 | break;
95 | case PLMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
96 | showToastTips("Stream disconnected !");
97 | break;
98 | case PLMediaPlayer.ERROR_CODE_IO_ERROR:
99 | showToastTips("Network IO Error !");
100 | break;
101 | case PLMediaPlayer.ERROR_CODE_UNAUTHORIZED:
102 | showToastTips("Unauthorized Error !");
103 | break;
104 | case PLMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
105 | showToastTips("Prepare timeout !");
106 | break;
107 | case PLMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
108 | showToastTips("Read frame timeout !");
109 | break;
110 | case PLMediaPlayer.MEDIA_ERROR_UNKNOWN:
111 | default:
112 | showToastTips("unknown error !");
113 | break;
114 | }
115 | // getActivity().finish();
116 | return true;
117 | }
118 | };
119 |
120 | private PLMediaPlayer.OnCompletionListener mOnCompletionListener = new PLMediaPlayer.OnCompletionListener() {
121 | @Override
122 | public void onCompletion(PLMediaPlayer plMediaPlayer) {
123 | showToastTips("Play Completed !");
124 | // getActivity().finish();
125 | }
126 | };
127 |
128 | private void showToastTips(final String tips) {
129 | getActivity().runOnUiThread(new Runnable() {
130 | @Override
131 | public void run() {
132 | Toast.makeText(getActivity(), tips, Toast.LENGTH_SHORT).show();
133 | }
134 | });
135 | }
136 |
137 | @Override
138 | public void onResume() {
139 | super.onResume();
140 | videoTextureView.start();
141 | }
142 |
143 | @Override
144 | public void onPause() {
145 | super.onPause();
146 | videoTextureView.pause();
147 | }
148 |
149 | @Override
150 | public void onDestroyView() {
151 | super.onDestroyView();
152 | videoTextureView.stopPlayback();
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/record/LCLKRecordActivity.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.record;
2 |
3 |
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.text.TextUtils;
8 |
9 | import com.avos.avoscloud.AVCallback;
10 | import com.avos.avoscloud.AVException;
11 | import com.avos.avoscloud.im.v2.AVIMClient;
12 | import com.avos.avoscloud.im.v2.AVIMConversation;
13 | import com.avos.avoscloud.im.v2.AVIMConversationQuery;
14 | import com.avos.avoscloud.im.v2.AVIMException;
15 | import com.avos.avoscloud.im.v2.callback.AVIMConversationCreatedCallback;
16 | import com.avos.avoscloud.im.v2.callback.AVIMConversationQueryCallback;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | import cn.leancloud.leancloudlivekit.LCLiveKit;
22 | import cn.leancloud.leancloudlivekit.LCLiveKitProvider;
23 | import cn.leancloud.leancloudlivekit.R;
24 | import cn.leancloud.leancloudlivekit.im.LCLKIMFragment;
25 | import cn.leancloud.leancloudlivekit.utils.LCLKConstants;
26 |
27 | /**
28 | * Created by wli on 16/8/2.
29 | * 负责录制直播的页面
30 | * 只需要开发者传入 LCLKConstants.LIVE_ID 就可以
31 | */
32 | public class LCLKRecordActivity extends AppCompatActivity {
33 |
34 | LCLKIMFragment lclkimFragment;
35 | LCLKRecordFragment lclkRecordFragment;
36 |
37 | @Override
38 | protected void onCreate(@Nullable Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.lclk_record_activity);
41 | lclkimFragment = (LCLKIMFragment) getSupportFragmentManager().findFragmentById(R.id.lclk_im_fragment);
42 | lclkRecordFragment = (LCLKRecordFragment) getSupportFragmentManager().findFragmentById(R.id.lclk_record_fragment);
43 |
44 | final String liveId = getIntent().getStringExtra(LCLKConstants.LIVE_ID);
45 |
46 | initConversation(liveId);
47 | initRecordFragment(liveId);
48 | }
49 |
50 | /**
51 | * 初始化录制直播的 Fragment
52 | * @param liveId
53 | */
54 | private void initRecordFragment(String liveId) {
55 | LCLiveKitProvider provider = LCLiveKit.getInstance().getProfileProvider();
56 | if (null != provider) {
57 | provider.fetchRecordStream(liveId, new AVCallback() {
58 | @Override
59 | protected void internalDone0(String s, AVException e) {
60 | if (null == e && !TextUtils.isEmpty(s)) {
61 | lclkRecordFragment.setStream(s);
62 | }
63 | }
64 | });
65 | }
66 | }
67 |
68 | /**
69 | * 初始化实时通讯的 Fragment
70 | * @param liveId
71 | */
72 | private void initConversation(final String liveId) {
73 | final AVIMClient client = LCLiveKit.getInstance().getClient();
74 | AVIMConversationQuery conversationQuery = client.getQuery();
75 | conversationQuery.whereEqualTo("name", liveId);
76 | conversationQuery.findInBackground(new AVIMConversationQueryCallback() {
77 | @Override
78 | public void done(List list, AVIMException e) {
79 | if (null != list && list.size() > 0) {
80 | lclkimFragment.setConversation(list.get(0));
81 | } else {
82 | client.createConversation(new ArrayList(), liveId, null, false, true, new AVIMConversationCreatedCallback() {
83 | @Override
84 | public void done(AVIMConversation avimConversation, AVIMException e) {
85 | lclkimFragment.setConversation(avimConversation);
86 | }
87 | });
88 | }
89 | }
90 | });
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/record/LCLKRecordFragment.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.record;
2 |
3 | import android.opengl.GLSurfaceView;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.text.TextUtils;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 |
12 | import com.pili.pldroid.streaming.CameraStreamingManager;
13 | import com.pili.pldroid.streaming.CameraStreamingSetting;
14 | import com.pili.pldroid.streaming.StreamingProfile;
15 | import com.pili.pldroid.streaming.widget.AspectFrameLayout;
16 |
17 | import org.json.JSONException;
18 | import org.json.JSONObject;
19 |
20 | import cn.leancloud.leancloudlivekit.R;
21 |
22 | /**
23 | * Created by wli on 16/8/4.
24 | * 负责录制直播的 Fragment
25 | */
26 | public class LCLKRecordFragment extends Fragment implements CameraStreamingManager.StreamingStateListener {
27 |
28 | private CameraStreamingManager mediaStreamingManager;
29 | private CameraStreamingSetting cameraStreamingSetting;
30 | private View mView;
31 |
32 | private String recordStream;
33 |
34 | @Override
35 | public void onResume() {
36 | super.onResume();
37 | if (null != mediaStreamingManager) {
38 | mediaStreamingManager.resume();
39 | }
40 | }
41 |
42 | @Override
43 | public void onPause() {
44 | super.onPause();
45 | if (null != mediaStreamingManager) {
46 | mediaStreamingManager.pause();
47 | }
48 | }
49 |
50 | @Override
51 | public void onDestroy() {
52 | super.onDestroy();
53 | if (null != mediaStreamingManager) {
54 | mediaStreamingManager.destroy();
55 | }
56 | }
57 |
58 | @Override
59 | public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
60 | mView = inflater.inflate(R.layout.lclk_record_fragment, parent, false);
61 | return mView;
62 | }
63 |
64 | @Override
65 | public void onActivityCreated(Bundle savedInstanceState) {
66 | super.onActivityCreated(savedInstanceState);
67 |
68 | AspectFrameLayout aspectFrameLayout = (AspectFrameLayout) mView.findViewById(R.id.live_recore_aspect_layout);
69 | GLSurfaceView glSurfaceView = (GLSurfaceView) mView.findViewById(R.id.live_recore_camera_preview_view);
70 | aspectFrameLayout.setShowMode(AspectFrameLayout.SHOW_MODE.REAL);
71 |
72 | mediaStreamingManager = new CameraStreamingManager(getActivity(), aspectFrameLayout, glSurfaceView,
73 | CameraStreamingManager.EncodingType.SW_VIDEO_WITH_SW_AUDIO_CODEC);
74 | mediaStreamingManager.setStreamingStateListener(this);
75 | cameraStreamingSetting = getCameraSetting();
76 | setStream(recordStream);
77 | }
78 |
79 | @Override
80 | public void onStateChanged(int state, Object info) {
81 | switch (state) {
82 | case CameraStreamingManager.STATE.PREPARING:
83 | break;
84 | case CameraStreamingManager.STATE.READY:
85 | new Thread(new Runnable() {
86 | @Override
87 | public void run() {
88 | if (mediaStreamingManager != null) {
89 | mediaStreamingManager.startStreaming();
90 | }
91 | }
92 | }).start();
93 | break;
94 | case CameraStreamingManager.STATE.CONNECTING:
95 | break;
96 | case CameraStreamingManager.STATE.STREAMING:
97 | // The av packet had been sent.
98 | break;
99 | case CameraStreamingManager.STATE.SHUTDOWN:
100 | // The streaming had been finished.
101 | break;
102 | case CameraStreamingManager.STATE.IOERROR:
103 | // Network connect error.
104 | break;
105 | case CameraStreamingManager.STATE.SENDING_BUFFER_EMPTY:
106 | break;
107 | case CameraStreamingManager.STATE.SENDING_BUFFER_FULL:
108 | break;
109 | case CameraStreamingManager.STATE.AUDIO_RECORDING_FAIL:
110 | // Failed to record audio.
111 | break;
112 | case CameraStreamingManager.STATE.OPEN_CAMERA_FAIL:
113 | // Failed to open camera.
114 | break;
115 | case CameraStreamingManager.STATE.DISCONNECTED:
116 | // The socket is broken while streaming
117 | break;
118 | case CameraStreamingManager.STATE.INVALID_STREAMING_URL:
119 | // invalid streaming url
120 | break;
121 | }
122 | }
123 |
124 | public void setStream(String recordStream) {
125 | this.recordStream = recordStream;
126 | /**
127 | * add by zzhong
128 | * 必须先调用MediaStreamingManager.prepare 函数,不然调用MediaStreamingManager.resume()
129 | * 函数会报错,所以无论recordStream值是什么都应该调用initStream,注意空字符串即可。如果recordStream
130 | * 不符合规范,会在onStateChanged发送INVALID_STREAMING_URL消息。
131 | */
132 | //if (!TextUtils.isEmpty(recordStream) && null != mediaStreamingManager) {
133 | initStream(recordStream == null ? "" : recordStream);
134 | startRecord();
135 | //}
136 | }
137 |
138 | private void initStream(String recordStream) {
139 | StreamingProfile streamingProfile = getSreamingProfile(recordStream);
140 | mediaStreamingManager.prepare(cameraStreamingSetting, null, null, streamingProfile);
141 | }
142 |
143 | private CameraStreamingSetting getCameraSetting() {
144 | CameraStreamingSetting cameraStreamingSetting = new CameraStreamingSetting();
145 | cameraStreamingSetting.setContinuousFocusModeEnabled(true)
146 | .setCameraFacingId(CameraStreamingSetting.CAMERA_FACING_ID.CAMERA_FACING_BACK)
147 | .setBuiltInFaceBeautyEnabled(true)
148 | .setResetTouchFocusDelayInMs(3000)
149 | .setCameraPrvSizeLevel(CameraStreamingSetting.PREVIEW_SIZE_LEVEL.SMALL)
150 | .setCameraPrvSizeRatio(CameraStreamingSetting.PREVIEW_SIZE_RATIO.RATIO_16_9)
151 | .setFaceBeautySetting(new CameraStreamingSetting.FaceBeautySetting(1.0f, 1.0f, 0.8f))
152 | .setVideoFilter(CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_BEAUTY);
153 | return cameraStreamingSetting;
154 | }
155 |
156 | private StreamingProfile getSreamingProfile(String recordStream) {
157 | StreamingProfile streamingProfile = new StreamingProfile();
158 | try {
159 | streamingProfile.setVideoQuality(StreamingProfile.VIDEO_QUALITY_HIGH3);
160 | streamingProfile.setAudioQuality(StreamingProfile.AUDIO_QUALITY_MEDIUM2);
161 | streamingProfile.setEncodingSizeLevel(StreamingProfile.VIDEO_ENCODING_HEIGHT_480);
162 | streamingProfile.setEncoderRCMode(StreamingProfile.EncoderRCModes.QUALITY_PRIORITY);
163 | streamingProfile.setStreamStatusConfig(new StreamingProfile.StreamStatusConfig(3));
164 | streamingProfile.setSendingBufferProfile(new StreamingProfile.SendingBufferProfile(0.2f, 0.8f, 3.0f, 20 * 1000));
165 | streamingProfile.setStream(new StreamingProfile.Stream(new JSONObject(recordStream)));
166 | return streamingProfile;
167 | } catch (JSONException e) {
168 | e.printStackTrace();
169 | }
170 | return null;
171 | }
172 |
173 | public void startRecord() {
174 | mediaStreamingManager.startStreaming();
175 | }
176 |
177 | public void stopRecord() {
178 | mediaStreamingManager.stopStreaming();
179 | }
180 |
181 | @Override
182 | public boolean onStateHandled(int i, Object o) {
183 | return false;
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/utils/LCLKConstants.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.utils;
2 |
3 | /**
4 | * Created by wli on 16/8/4.
5 | * LeanCloudLiveKit 常量类
6 | */
7 | public class LCLKConstants {
8 |
9 | /**
10 | * LeanCloudLiveKit 常量前缀,避免与用户其他常量混淆
11 | */
12 | private static final String LEANMESSAGE_CONSTANTS_PREFIX = "cn.leancloud.livekit.";
13 |
14 | private static String getPrefixConstant(String str) {
15 | return LEANMESSAGE_CONSTANTS_PREFIX + str;
16 | }
17 |
18 | public static final String LIVE_RECORD_STREAM_KEY = getPrefixConstant("live_record_stream_key");
19 |
20 |
21 | public static final String LIVE_CONVERSATION_KEY = getPrefixConstant("live_conversation_key");
22 |
23 | public static final String LIVE_ID = getPrefixConstant("live_id");
24 | public static final String ANCHOR_ID = getPrefixConstant("anchor_id");
25 | }
26 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/java/cn/leancloud/leancloudlivekit/utils/LCLKProfileCache.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.leancloudlivekit.utils;
2 |
3 | import com.avos.avoscloud.AVCallback;
4 | import com.avos.avoscloud.AVException;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.HashMap;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | import cn.leancloud.leancloudlivekit.LCLKUser;
13 | import cn.leancloud.leancloudlivekit.LCLiveKit;
14 | import cn.leancloud.leancloudlivekit.LCLiveKitProvider;
15 |
16 | /**
17 | * Created by wli on 16/8/10.
18 | * 用户信息的缓存,仅仅缓存与内存中
19 | */
20 | public class LCLKProfileCache {
21 |
22 | /**
23 | * userMap 最大的数量,避免数据过多导致 oom
24 | */
25 | private final int PROFILE_CACHE_MAX_SIZE = 1000;
26 |
27 | private Map userMap;
28 |
29 | private LCLKProfileCache() {
30 | userMap = new HashMap<>();
31 | }
32 |
33 | private static LCLKProfileCache profileCache;
34 |
35 | public static synchronized LCLKProfileCache getInstance() {
36 | if (null == profileCache) {
37 | profileCache = new LCLKProfileCache();
38 | }
39 | return profileCache;
40 | }
41 |
42 | /**
43 | * 根据 id 获取用户信息
44 | * 先从缓存中获取,若没有再调用用户回调获取
45 | *
46 | * @param id
47 | * @param callback
48 | */
49 | public synchronized void getCachedUser(final String id, final AVCallback callback) {
50 | getCachedUsers(Arrays.asList(id), new AVCallback>() {
51 | @Override
52 | protected void internalDone0(List lclkUsers, AVException e) {
53 | LCLKUser lclkUser = (null != lclkUsers && !lclkUsers.isEmpty() ? lclkUsers.get(0) : null);
54 | callback.internalDone(lclkUser, e);
55 | }
56 | });
57 | }
58 |
59 | /**
60 | * 获取多个用户的信息
61 | * 先从缓存中获取,若没有再调用用户回调获取
62 | *
63 | * @param idList
64 | * @param callback
65 | */
66 | public synchronized void getCachedUsers(List idList, final AVCallback> callback) {
67 | if (null != callback) {
68 | if (null == idList || idList.isEmpty()) {
69 | callback.internalDone(null, new AVException(new Throwable("idList is empty!")));
70 | } else {
71 | final List profileList = new ArrayList();
72 | final List unCachedIdList = new ArrayList();
73 |
74 | for (String id : idList) {
75 | if (userMap.containsKey(id)) {
76 | profileList.add(userMap.get(id));
77 | } else {
78 | unCachedIdList.add(id);
79 | }
80 | }
81 |
82 | if (unCachedIdList.isEmpty()) {
83 | callback.internalDone(profileList, null);
84 | } else {
85 | getProfilesFromProvider(unCachedIdList, profileList, callback);
86 | }
87 | }
88 | }
89 | }
90 |
91 | /**
92 | * 根据 id 通过开发者设置的回调获取用户信息
93 | *
94 | * @param idList
95 | * @param callback
96 | */
97 | private void getProfilesFromProvider(List idList, final List profileList,
98 | final AVCallback> callback) {
99 | LCLiveKitProvider profileProvider = LCLiveKit.getInstance().getProfileProvider();
100 | if (null != profileProvider) {
101 | profileProvider.fetchProfiles(idList, new AVCallback>() {
102 | @Override
103 | protected void internalDone0(List lclkUsers, AVException e) {
104 | if (null != lclkUsers) {
105 | for (LCLKUser userProfile : lclkUsers) {
106 | cacheUser(userProfile);
107 | }
108 | }
109 | profileList.addAll(lclkUsers);
110 | callback.internalDone(profileList, null != e ? new AVException(e) : null);
111 | }
112 | });
113 | } else {
114 | callback.internalDone(null, new AVException(new Throwable("please setProfileProvider first!")));
115 | }
116 | }
117 |
118 | /**
119 | * 内存中是否包相关 LCLKUser 的信息
120 | * @param id
121 | * @return
122 | */
123 | public synchronized boolean hasCachedUser(String id) {
124 | return userMap.containsKey(id);
125 | }
126 |
127 | public synchronized void cacheUser(LCLKUser userProfile) {
128 | if (userMap.size() > PROFILE_CACHE_MAX_SIZE) {
129 | userMap.clear();
130 | }
131 | userMap.put(userProfile.getUserId(), userProfile);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_mmprocessing.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_mmprocessing.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_streaming_aac_encoder.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_streaming_aac_encoder.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_streaming_core.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_streaming_core.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_streaming_h264_encoder.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroid_streaming_h264_encoder.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroidplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/arm64-v8a/libpldroidplayer.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_mmprocessing.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_mmprocessing.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_aac_encoder.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_aac_encoder.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_core.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_core.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_h264_encoder.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_h264_encoder.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroidplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi-v7a/libpldroidplayer.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_mmprocessing.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_mmprocessing.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_streaming_aac_encoder.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_streaming_aac_encoder.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_streaming_core.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_streaming_core.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_streaming_h264_encoder.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi/libpldroid_streaming_h264_encoder.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/jniLibs/armeabi/libpldroidplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/jniLibs/armeabi/libpldroidplayer.so
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/drawable/lclk_barrage_item_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/drawable/lclk_im_gift_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/drawable/lclk_im_input_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/drawable/lclk_im_item_content_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/drawable/lclk_im_item_content_bg.9.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/drawable/lclk_praise_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_barrage_gift_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
26 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_barrage_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
18 |
27 |
28 |
38 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_gift_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_gift_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
21 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_barrage_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_chat_item_text_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
23 |
24 |
31 |
32 |
40 |
41 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_chat_status_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_gift_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_im_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
25 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_input_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
27 |
28 |
36 |
37 |
38 |
48 |
49 |
59 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_im_personal_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
24 |
25 |
33 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_play_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_play_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
20 |
21 |
25 |
26 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_record_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
19 |
24 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/layout/lclk_record_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_camera_switch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_camera_switch.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_default_avatar_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_default_avatar_icon.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_close.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_1.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_2.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_3.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_4.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_5.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_6.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_7.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_im_gift_8.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/leancloudlivekit/src/main/res/mipmap-xxhdpi/lclk_star.png
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/values/lclk_colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #121E34
5 | #121E34
6 | @color/lclk_common_blue
7 |
8 | #2c97e8
9 | #898989
10 | #ff0000
11 |
12 | #664AE2
13 |
14 | #D1D1D1
15 | @android:color/white
16 | #a8FFFFFF
17 | @color/lclk_color_primary
18 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/values/lclk_dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10dp
4 | 175dp
5 | 24dp
6 | 45dp
7 | 40dp
8 | 40dp
9 |
10 |
11 |
12 | 14sp
13 | 16sp
14 | 18sp
15 | 20sp
16 | 22sp
17 | 24sp
18 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/values/lclk_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 礼物
4 | 弹幕
5 |
--------------------------------------------------------------------------------
/leancloudlivekit/src/main/res/values/lclk_styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
17 |
18 |
22 |
23 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
45 |
46 |
49 |
50 |
53 |
54 |
57 |
58 |
59 |
60 |
66 |
67 |
71 |
72 |
76 |
--------------------------------------------------------------------------------
/livekitapplication/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/livekitapplication/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "26.0.2"
6 |
7 | defaultConfig {
8 | applicationId "cn.leancloud.livekitapplication"
9 | minSdkVersion 14
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | multiDexEnabled true
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 |
22 | lintOptions {
23 | abortOnError false
24 | }
25 | }
26 |
27 | dependencies {
28 | compile project(':leancloudlivekit')
29 | implementation 'com.jakewharton:butterknife:8.8.1'
30 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
31 | }
32 |
--------------------------------------------------------------------------------
/livekitapplication/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wli/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKAppProvider.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import com.avos.avoscloud.AVCallback;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import cn.leancloud.leancloudlivekit.LCLiveKitProvider;
9 | import cn.leancloud.leancloudlivekit.LCLKUser;
10 |
11 | /**
12 | * Created by wli on 16/8/5.
13 | */
14 | public class LCLKAppProvider implements LCLiveKitProvider {
15 |
16 | private static LCLKAppProvider customUserProvider;
17 |
18 | public synchronized static LCLKAppProvider getInstance() {
19 | if (null == customUserProvider) {
20 | customUserProvider = new LCLKAppProvider();
21 | }
22 | return customUserProvider;
23 | }
24 |
25 | private LCLKAppProvider() {
26 | }
27 |
28 | private static List partUsers = new ArrayList();
29 |
30 | // 此数据均为 fake,仅供参考
31 | static {
32 | partUsers.add(new LCLKUser("Tom", "Tom", "http://www.avatarsdb.com/avatars/tom_and_jerry2.jpg"));
33 | partUsers.add(new LCLKUser("Jerry", "Jerry", "http://www.avatarsdb.com/avatars/jerry.jpg"));
34 | partUsers.add(new LCLKUser("Harry", "Harry", "http://www.avatarsdb.com/avatars/young_harry.jpg"));
35 | partUsers.add(new LCLKUser("William", "William", "http://www.avatarsdb.com/avatars/william_shakespeare.jpg"));
36 | partUsers.add(new LCLKUser("Bob", "Bob", "http://www.avatarsdb.com/avatars/bath_bob.jpg"));
37 | }
38 |
39 | @Override
40 | public void fetchProfiles(List userIdList, AVCallback> profilesCallBack) {
41 | List userList = new ArrayList();
42 | for (String userId : userIdList) {
43 | for (LCLKUser user : partUsers) {
44 | if (user.getUserId().equals(userId)) {
45 | userList.add(user);
46 | break;
47 | }
48 | }
49 | }
50 | profilesCallBack.internalDone(userList, null);
51 | }
52 |
53 | @Override
54 | public void fetchRecordStream(String liveId, AVCallback streamCallback) {
55 | //TODO:根据liveId获取对应的推流地址
56 | streamCallback.internalDone(null, null);
57 | }
58 |
59 | @Override
60 | public void fetchPlayStream(String liveId, AVCallback streamCallback) {
61 | //TODO:根据liveId获取对应的直播地址
62 | streamCallback.internalDone("rtmp://live.hkstv.hk.lxdns.com/live/hks" , null);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKApplication.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import android.app.Application;
4 |
5 | import com.avos.avoscloud.AVOSCloud;
6 | import com.avos.avoscloud.AVObject;
7 | import com.pili.pldroid.streaming.StreamingEnv;
8 |
9 | import cn.leancloud.leancloudlivekit.LCLiveKit;
10 |
11 | /**
12 | * Created by wli on 16/8/5.
13 | */
14 | public class LCLKApplication extends Application {
15 |
16 | // 此 id 与 key 仅供测试使用
17 | private final String APP_ID = "683jigxkqb10jrirelvd9vcn9ywbq2o436lfz1kngsvigm27";
18 | private final String APP_KEY = "ualzl8f8pxmryous77m3gf2z0dyhrhk6xdb7zkiu6flc0jxy";
19 |
20 | @Override
21 | public void onCreate() {
22 | super.onCreate();
23 | LCLiveKit.getInstance().setProfileProvider(LCLKAppProvider.getInstance());
24 | LCLiveKit.getInstance().init(getApplicationContext(), APP_ID, APP_KEY);
25 | AVOSCloud.setDebugLogEnabled(true);
26 | AVObject.registerSubclass(LCLiveRoom.class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKLiveRoomCreateActivity.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.database.Cursor;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.os.Environment;
10 | import android.provider.MediaStore;
11 | import android.support.annotation.Nullable;
12 | import android.support.v7.app.AlertDialog;
13 | import android.support.v7.app.AppCompatActivity;
14 | import android.text.TextUtils;
15 | import android.view.View;
16 | import android.widget.EditText;
17 | import android.widget.ImageView;
18 | import android.widget.TextView;
19 | import android.widget.Toast;
20 |
21 | import com.avos.avoscloud.AVException;
22 | import com.avos.avoscloud.AVFile;
23 | import com.avos.avoscloud.SaveCallback;
24 | import com.pili.pldroid.streaming.widget.AspectFrameLayout;
25 | import com.squareup.picasso.Picasso;
26 |
27 | import java.io.File;
28 | import java.io.FileNotFoundException;
29 | import java.util.UUID;
30 |
31 | import butterknife.BindView;
32 | import butterknife.ButterKnife;
33 | import butterknife.OnClick;
34 | import cn.leancloud.leancloudlivekit.LCLiveKit;
35 | import cn.leancloud.leancloudlivekit.record.LCLKRecordActivity;
36 | import cn.leancloud.leancloudlivekit.utils.LCLKConstants;
37 |
38 | /**
39 | * Created by wli on 16/8/8.
40 | * 创建直播间页面
41 | */
42 | public class LCLKLiveRoomCreateActivity extends AppCompatActivity {
43 |
44 | @BindView(R.id.live_channle_start_et_title)
45 | EditText titleView;
46 |
47 | @BindView(R.id.live_channle_start_et_topic)
48 | EditText topicView;
49 |
50 | @BindView(R.id.live_channle_start_iv_conver)
51 | ImageView converView;
52 |
53 | @BindView(R.id.live_channle_start_tv_start)
54 | TextView startView;
55 |
56 | private String localCameraPath;
57 |
58 | @Override
59 | protected void onCreate(@Nullable Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.lclk_live_room_create_activity);
62 | ButterKnife.bind(this);
63 | if (TextUtils.isEmpty(LCLiveKit.getInstance().getCurrentUserId())) {
64 | Toast.makeText(this, "请先执行登陆操作!", Toast.LENGTH_SHORT).show();
65 | finish();
66 | }
67 | }
68 |
69 | @OnClick(R.id.live_channle_start_iv_conver)
70 | public void onConverClick(View view) {
71 | final String[] Items = {"手机相册", "拍照"};
72 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
73 | builder.setItems(Items, new DialogInterface.OnClickListener() {
74 | @Override
75 | public void onClick(DialogInterface dialogInterface, int i) {
76 | switch (i) {
77 | case 0:
78 | dispatchPickPictureIntent();
79 | break;
80 | case 1:
81 | dispatchTakePictureIntent();
82 | break;
83 | }
84 | }
85 | });
86 | builder.setCancelable(true);
87 | AlertDialog dialog = builder.create();
88 | dialog.show();
89 | }
90 |
91 | @OnClick(R.id.live_channle_start_tv_start)
92 | public void onStartClick(View view) {
93 | final String title = titleView.getText().toString();
94 | final String topic = topicView.getText().toString();
95 | final String clientId = LCLiveKit.getInstance().getCurrentUserId();
96 | //TODO:自己定义直播间ID,保证每个直播间ID唯一即可
97 | final String liveId = UUID.randomUUID().toString();
98 | final String anchorId = clientId;
99 |
100 | if (TextUtils.isEmpty(title.trim())) {
101 | Toast.makeText(this, "标题不能为空", Toast.LENGTH_SHORT).show();
102 | return;
103 | }
104 |
105 | if (TextUtils.isEmpty(topic.trim())) {
106 | Toast.makeText(this, "话题不能为空", Toast.LENGTH_SHORT).show();
107 | return;
108 | }
109 |
110 | if (TextUtils.isEmpty(localCameraPath)) {
111 | Toast.makeText(this, "封面不能为空", Toast.LENGTH_SHORT).show();
112 | return;
113 | }
114 |
115 | if (TextUtils.isEmpty(clientId.trim())) {
116 | Toast.makeText(this, "请重新登陆!", Toast.LENGTH_SHORT).show();
117 | }
118 |
119 | LCLiveRoom liveRoom = new LCLiveRoom();
120 |
121 | try {
122 | liveRoom.setConver(AVFile.withAbsoluteLocalPath("cover", localCameraPath));
123 | } catch (FileNotFoundException e) {
124 | e.printStackTrace();
125 | }
126 | liveRoom.setTopic(topic);
127 | liveRoom.setTitle(title);
128 | liveRoom.setLiveId(liveId);
129 | liveRoom.setAnchorId(anchorId);
130 | liveRoom.saveInBackground(new SaveCallback() {
131 | @Override
132 | public void done(AVException e) {
133 | finish();
134 | Intent intent = new Intent(LCLKLiveRoomCreateActivity.this, LCLKRecordActivity.class);
135 | intent.putExtra(LCLKConstants.LIVE_ID, liveId);
136 | intent.putExtra(LCLKConstants.ANCHOR_ID, anchorId);
137 | startActivity(intent);
138 | }
139 | });
140 | }
141 |
142 | private void dispatchTakePictureIntent() {
143 | localCameraPath = getPicturePathByCurrentTime(this);
144 | Intent takePictureIntent = new Intent("android.media.action.IMAGE_CAPTURE");
145 | Uri imageUri = Uri.fromFile(new File(localCameraPath));
146 | takePictureIntent.putExtra("return-data", false);
147 | takePictureIntent.putExtra("output", imageUri);
148 | if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
149 | this.startActivityForResult(takePictureIntent, 1);
150 | }
151 | }
152 |
153 | private void dispatchPickPictureIntent() {
154 | Intent photoPickerIntent = new Intent("android.intent.action.PICK", (Uri) null);
155 | photoPickerIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
156 | this.startActivityForResult(photoPickerIntent, 2);
157 | }
158 |
159 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
160 | super.onActivityResult(requestCode, resultCode, data);
161 | if (-1 == resultCode) {
162 | switch (requestCode) {
163 | case 1:
164 | Picasso.with(this).load(new File(localCameraPath)).into(converView);
165 | break;
166 | case 2:
167 | localCameraPath = getRealPathFromURI(this, data.getData());
168 | Picasso.with(this).load(new File(localCameraPath)).into(converView);
169 | }
170 | }
171 | }
172 |
173 | private String getRealPathFromURI(Context context, Uri contentUri) {
174 | Cursor cursor = null;
175 | String var6;
176 | try {
177 | String[] proj = new String[]{"_data"};
178 | cursor = context.getContentResolver().query(contentUri, proj, (String) null, (String[]) null, (String) null);
179 | int column_index = cursor.getColumnIndexOrThrow("_data");
180 | cursor.moveToFirst();
181 | var6 = cursor.getString(column_index);
182 | } finally {
183 | if (cursor != null) {
184 | cursor.close();
185 | }
186 | }
187 | return var6;
188 | }
189 |
190 | private static String getPicturePathByCurrentTime(Context context) {
191 | String state = Environment.getExternalStorageState();
192 | boolean isExternalStorageWritable = "mounted".equals(state);
193 | File fille = isExternalStorageWritable ? context.getExternalCacheDir() : context.getCacheDir();
194 | return (new File(fille, "picture_" + System.currentTimeMillis())).getAbsolutePath();
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKLiveRoomItemClickEvent.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | /**
4 | * Created by wli on 16/8/10.
5 | * 直播间 item 的点击事件
6 | */
7 | public class LCLKLiveRoomItemClickEvent {
8 | public LCLiveRoom liveRoom;
9 |
10 | LCLKLiveRoomItemClickEvent(LCLiveRoom liveRoom) {
11 | this.liveRoom = liveRoom;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKLiveRoomItemHolder.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import android.widget.TextView;
8 |
9 | import com.avos.avoscloud.AVCallback;
10 | import com.avos.avoscloud.AVException;
11 | import com.squareup.picasso.Picasso;
12 |
13 | import cn.leancloud.leancloudlivekit.LCLKUser;
14 | import cn.leancloud.leancloudlivekit.im.LCLKCommonViewHolder;
15 | import cn.leancloud.leancloudlivekit.im.LCLKRoundCornerImageView;
16 | import cn.leancloud.leancloudlivekit.utils.LCLKProfileCache;
17 | import de.greenrobot.event.EventBus;
18 |
19 | /**
20 | * Created by wli on 16/8/5.
21 | */
22 | public class LCLKLiveRoomItemHolder extends LCLKCommonViewHolder {
23 |
24 | private ImageView backgroudView;
25 | private TextView nameView;
26 | private LCLKRoundCornerImageView avatarView;
27 | private TextView statusView;
28 | private TextView descriptionView;
29 |
30 | private LCLiveRoom liveRoom;
31 |
32 | public LCLKLiveRoomItemHolder(Context context, ViewGroup root) {
33 | super(context, root, R.layout.lclk_live_room_item);
34 | backgroudView = (ImageView) itemView.findViewById(R.id.live_room_item_bg_view);
35 | nameView = (TextView) itemView.findViewById(R.id.live_room_item_name_view);
36 | avatarView = (LCLKRoundCornerImageView) itemView.findViewById(R.id.live_room_item_avatar_view);
37 | statusView = (TextView) itemView.findViewById(R.id.live_room_item_status_view);
38 | descriptionView = (TextView) itemView.findViewById(R.id.live_room_item_description_view);
39 |
40 | itemView.setOnClickListener(new View.OnClickListener() {
41 | @Override
42 | public void onClick(View v) {
43 | EventBus.getDefault().post(new LCLKLiveRoomItemClickEvent(liveRoom));
44 | }
45 | });
46 | }
47 |
48 | @Override
49 | public void bindData(LCLiveRoom liveRoom) {
50 | this.liveRoom = liveRoom;
51 | if(liveRoom.getConver() != null) {
52 | Picasso.with(getContext()).load(liveRoom.getConver().getUrl()).into(backgroudView);
53 | }else {
54 | Picasso.with(getContext()).load(R.mipmap.lclk_live_add_image).into(backgroudView);
55 | }
56 | LCLKProfileCache.getInstance().getCachedUser(liveRoom.getAnchorId(), new AVCallback() {
57 | @Override
58 | protected void internalDone0(LCLKUser lclkUser, AVException e) {
59 | if(lclkUser != null) {
60 | nameView.setText(lclkUser.getUserName());
61 | Picasso.with(getContext()).load(lclkUser.getAvatarUrl()).into(avatarView);
62 | }else {
63 | nameView.setText(R.string.lclk_live_room_unknow_name);
64 | Picasso.with(getContext()).load(R.mipmap.ic_launcher).into(avatarView);
65 | }
66 | }
67 | });
68 | descriptionView.setText(liveRoom.getTitle() + " #" + liveRoom.getTopic());
69 | }
70 |
71 | public static ViewHolderCreator HOLDER_CREATOR = new ViewHolderCreator() {
72 | @Override
73 | public LCLKLiveRoomItemHolder createByViewGroupAndType(ViewGroup parent, int viewType) {
74 | return new LCLKLiveRoomItemHolder(parent.getContext(), parent);
75 | }
76 | };
77 | }
78 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKLiveRoomListActivity.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.widget.SwipeRefreshLayout;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 |
13 | import com.avos.avoscloud.AVException;
14 | import com.avos.avoscloud.AVQuery;
15 | import com.avos.avoscloud.FindCallback;
16 |
17 | import java.util.List;
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import cn.leancloud.leancloudlivekit.im.LCLKCommonListAdapter;
22 | import cn.leancloud.leancloudlivekit.play.LCLKPlayActivity;
23 | import cn.leancloud.leancloudlivekit.utils.LCLKConstants;
24 | import de.greenrobot.event.EventBus;
25 |
26 | /**
27 | * Created by wli on 16/8/5.
28 | * 直播间页面
29 | */
30 | public class LCLKLiveRoomListActivity extends AppCompatActivity {
31 |
32 | @BindView(R.id.refreshable_list_srl)
33 | SwipeRefreshLayout refreshLayout;
34 |
35 | @BindView(R.id.refreshable_list_recycler)
36 | RecyclerView recyclerView;
37 |
38 | GridLayoutManager layoutManager;
39 | LCLKCommonListAdapter itemAdapter;
40 |
41 | @Override
42 | protected void onCreate(@Nullable Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.lclk_live_room_list_activity);
45 | EventBus.getDefault().register(this);
46 | ButterKnife.bind(this);
47 |
48 | layoutManager = new GridLayoutManager(this, 2);
49 | recyclerView.setLayoutManager(layoutManager);
50 |
51 | refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
52 | @Override
53 | public void onRefresh() {
54 | fetchChannels();
55 | }
56 | });
57 |
58 | itemAdapter = new LCLKCommonListAdapter<>(LCLKLiveRoomItemHolder.class);
59 | recyclerView.setAdapter(itemAdapter);
60 |
61 | fetchChannels();
62 | }
63 |
64 |
65 | @Override
66 | public boolean onCreateOptionsMenu(Menu menu) {
67 | getMenuInflater().inflate(R.menu.lclk_menu_live_create, menu);
68 | return true;
69 | }
70 |
71 | @Override
72 | public boolean onOptionsItemSelected(MenuItem item) {
73 | int menuId = item.getItemId();
74 | if (menuId == R.id.menu_channel_start) {
75 | gotoStartChannelAcitivty();
76 | }
77 | return super.onOptionsItemSelected(item);
78 | }
79 |
80 | /**
81 | * 跳转到创建直播间的页面
82 | */
83 | private void gotoStartChannelAcitivty() {
84 | Intent intent = new Intent(this, LCLKLiveRoomCreateActivity.class);
85 | startActivity(intent);
86 | }
87 |
88 | /**
89 | * 拉取直播间信息
90 | */
91 | private void fetchChannels() {
92 | AVQuery avQuery = AVQuery.getQuery(LCLiveRoom.class);
93 | avQuery.findInBackground(new FindCallback() {
94 | @Override
95 | public void done(List list, AVException e) {
96 | refreshLayout.setRefreshing(false);
97 | itemAdapter.setDataList(list);
98 | itemAdapter.notifyDataSetChanged();
99 | }
100 | });
101 | }
102 |
103 | public void onEvent(LCLKLiveRoomItemClickEvent event) {
104 | Intent intent = new Intent(LCLKLiveRoomListActivity.this, LCLKPlayActivity.class);
105 | intent.putExtra(LCLKConstants.LIVE_ID, event.liveRoom.getLiveId());
106 | intent.putExtra(LCLKConstants.ANCHOR_ID, event.liveRoom.getAnchorId());
107 | startActivity(intent);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLKLoginActivity.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.text.TextUtils;
7 | import android.view.View;
8 | import android.widget.EditText;
9 | import android.widget.Toast;
10 |
11 | import com.avos.avoscloud.im.v2.AVIMClient;
12 | import com.avos.avoscloud.im.v2.AVIMException;
13 | import com.avos.avoscloud.im.v2.callback.AVIMClientCallback;
14 |
15 | import butterknife.BindView;
16 | import butterknife.ButterKnife;
17 | import butterknife.OnClick;
18 | import cn.leancloud.leancloudlivekit.LCLiveKit;
19 |
20 | /**
21 | * Created by wli on 16/8/5.
22 | * 登陆页面
23 | */
24 | public class LCLKLoginActivity extends AppCompatActivity {
25 |
26 | @BindView(R.id.activity_login_et_username)
27 | EditText nameView;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.lclk_login_activity);
33 | ButterKnife.bind(this);
34 | }
35 |
36 | @OnClick(R.id.activity_login_btn_login)
37 | public void onLoginClick(View view) {
38 | String clientId = nameView.getText().toString();
39 | if (TextUtils.isEmpty(clientId.trim())) {
40 | Toast.makeText(this, "不能为空", Toast.LENGTH_SHORT).show();
41 | return;
42 | }
43 |
44 | // 打开 LeanCloud 实时通讯
45 | LCLiveKit.getInstance().open(clientId, new AVIMClientCallback() {
46 | @Override
47 | public void done(AVIMClient avimClient, AVIMException e) {
48 | if (null == e) {
49 | finish();
50 | Intent intent = new Intent(LCLKLoginActivity.this, LCLKLiveRoomListActivity.class);
51 | startActivity(intent);
52 | } else {
53 | Toast.makeText(LCLKLoginActivity.this, e.toString(), Toast.LENGTH_SHORT).show();
54 | }
55 | }
56 | });
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/java/cn/leancloud/livekitapplication/LCLiveRoom.java:
--------------------------------------------------------------------------------
1 | package cn.leancloud.livekitapplication;
2 |
3 | import android.os.Parcel;
4 |
5 | import com.avos.avoscloud.AVClassName;
6 | import com.avos.avoscloud.AVFile;
7 | import com.avos.avoscloud.AVObject;
8 |
9 | /**
10 | * Created by wli on 16/8/10.
11 | * 直播间
12 | */
13 | @AVClassName("live")
14 | public class LCLiveRoom extends AVObject {
15 |
16 | private final String LC_LIVEROOM_TOPIC = "topic";
17 | private final String LC_LIVEROOM_TITLE = "title";
18 | private final String LC_LIVEROOM_LIVEID = "liveId";
19 | private final String LC_LIVEROOM_ANCHORID = "AnchorId";
20 | private final String LC_LIVEROOM_COVER = "conver";
21 |
22 | public LCLiveRoom(){
23 | super();
24 | }
25 |
26 | public LCLiveRoom(Parcel in){
27 | super(in);
28 | }
29 |
30 | public void setTopic(String topic) {
31 | this.put(LC_LIVEROOM_TOPIC, topic);
32 | }
33 |
34 | public String getTopic() {
35 | return this.getString(LC_LIVEROOM_TOPIC);
36 | }
37 |
38 | public void setTitle(String title) {
39 | this.put(LC_LIVEROOM_TITLE, title);
40 | }
41 |
42 | public String getTitle() {
43 | return this.getString(LC_LIVEROOM_TITLE);
44 | }
45 |
46 | public void setLiveId(String liveId) {
47 | this.put(LC_LIVEROOM_LIVEID, liveId);
48 | }
49 |
50 | public String getLiveId() {
51 | return this.getString(LC_LIVEROOM_LIVEID);
52 | }
53 |
54 | public void setAnchorId(String anchorId) {
55 | this.put(LC_LIVEROOM_ANCHORID, anchorId);
56 | }
57 |
58 | public String getAnchorId() {
59 | return this.getString(LC_LIVEROOM_ANCHORID);
60 | }
61 |
62 | public void setConver(AVFile file) {
63 | this.put(LC_LIVEROOM_COVER, file);
64 | }
65 |
66 | public AVFile getConver() {
67 | return this.getAVFile(LC_LIVEROOM_COVER);
68 | }
69 |
70 | public static final Creator CREATOR = AVObjectCreator.instance;
71 | }
72 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/drawable/edittext_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
8 |
9 |
10 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/drawable/start_channel_btn_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/drawable/start_channel_image_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/layout/lclk_live_room_create_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
27 |
28 |
39 |
40 |
51 |
52 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/layout/lclk_live_room_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
22 |
23 |
30 |
31 |
39 |
40 |
49 |
50 |
51 |
59 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/layout/lclk_live_room_list_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/layout/lclk_login_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
25 |
26 |
37 |
38 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/menu/lclk_menu_live_create.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/livekitapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/mipmap-xxhdpi/lclk_live_add_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/LeanCloudLiveKit-Android/87f221305384f4e895f22949186b245532ee76b1/livekitapplication/src/main/res/mipmap-xxhdpi/lclk_live_add_image.png
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/values/lclk_colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #979797
4 |
5 | #979797
6 | #42ffffff
7 | #00F0F8
8 | #4A4A4A
9 | #2C2F30
10 | #78ffffff
11 |
12 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/values/lclk_dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 | 16dp
4 |
5 | 10dp
6 |
7 | 30dp
8 |
9 | 220dp
10 | 1px
11 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/values/lclk_strings.xml:
--------------------------------------------------------------------------------
1 |
2 | livekitapplication
3 |
4 | 直播间
5 | 开始直播
6 | 登陆
7 |
8 | 输入标题吸引更多粉丝
9 | # 添加话题
10 |
11 | 未知用户
12 |
13 |
14 |
--------------------------------------------------------------------------------
/livekitapplication/src/main/res/values/lclk_styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':leancloudlivekit', ':livekitapplication'
2 |
--------------------------------------------------------------------------------