├── .gitignore
├── .idea
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ ├── LiteAVSDK_Professional_4.6.4218.aar
│ ├── gson-2.3.1.jar
│ └── liteimsdk-release.aar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── zjp
│ │ └── tencentvideo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── zjp
│ │ │ └── tencentvideo
│ │ │ ├── BiliDanmukuParser.java
│ │ │ ├── DanmakuController.java
│ │ │ ├── TecentVideoTestApplication.java
│ │ │ ├── beautysettings
│ │ │ ├── BeautyDialogFragment.java
│ │ │ └── TCHorizontalScrollView.java
│ │ │ ├── ui
│ │ │ ├── LiveActivity.java
│ │ │ ├── MainActivity.java
│ │ │ └── RTMPActivity.java
│ │ │ ├── utils
│ │ │ ├── BitmapUtils.java
│ │ │ ├── TCFrequeControl.java
│ │ │ └── TCUtils.java
│ │ │ └── view
│ │ │ ├── TCInputTextMsgDialog.java
│ │ │ └── like
│ │ │ ├── TCAbstractPathAnimator.java
│ │ │ ├── TCHeartLayout.java
│ │ │ ├── TCHeartView.java
│ │ │ └── TCPathAnimator.java
│ └── res
│ │ ├── anim
│ │ └── load_progress_animation.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ ├── again.png
│ │ ├── barrage_slider_off.png
│ │ ├── barrage_slider_on.png
│ │ ├── beautiful.png
│ │ ├── beautiful_press.png
│ │ ├── beauty.png
│ │ ├── btn_back_gray.png
│ │ ├── camera_change.png
│ │ ├── close.png
│ │ ├── face.png
│ │ ├── icon_beauty_png.png
│ │ ├── icon_like_png.png
│ │ ├── icon_log_off.png
│ │ ├── icon_message_png.png
│ │ ├── icon_share_png.png
│ │ ├── icon_switch_camera_on.png
│ │ ├── linkmic_on_normal.png
│ │ ├── loading_circle_progress.png
│ │ ├── play_seekbar_icon.png
│ │ ├── text_accent_gray_color.xml
│ │ └── video.png
│ │ ├── drawable-xxhdpi
│ │ ├── drawable_face_beauty.xml
│ │ ├── drawable_face_filter.xml
│ │ ├── drawable_face_green.xml
│ │ ├── drawable_face_move.xml
│ │ ├── fennen.png
│ │ ├── filter.png
│ │ ├── filter_fennen.png
│ │ ├── filter_huaijiu.png
│ │ ├── filter_landiao.png
│ │ ├── filter_langman.png
│ │ ├── filter_press.png
│ │ ├── filter_qingliang.png
│ │ ├── filter_qingxin.png
│ │ ├── filter_rixi.png
│ │ ├── filter_selected.png
│ │ ├── filter_weimei.png
│ │ ├── filter_white.png
│ │ ├── greens.png
│ │ ├── greens_1.png
│ │ ├── greens_2.png
│ │ ├── greens_no.png
│ │ ├── greens_press.png
│ │ ├── greens_selected.png
│ │ ├── heart0.png
│ │ ├── heart1.png
│ │ ├── heart10.png
│ │ ├── heart11.png
│ │ ├── heart2.png
│ │ ├── heart3.png
│ │ ├── heart4.png
│ │ ├── heart5.png
│ │ ├── heart6.png
│ │ ├── heart7.png
│ │ ├── heart8.png
│ │ ├── heart9.png
│ │ ├── huaijiu.png
│ │ ├── landiao.png
│ │ ├── landscape.png
│ │ ├── langman.png
│ │ ├── linkmic_start.png
│ │ ├── liveshow_item_dot.xml
│ │ ├── move.png
│ │ ├── move_press.png
│ │ ├── orginal.png
│ │ ├── play_pause.png
│ │ ├── play_start.png
│ │ ├── portrait.png
│ │ ├── progress_bg.png
│ │ ├── progress_front.png
│ │ ├── progress_primary.png
│ │ ├── qingliang.png
│ │ ├── qingxin.png
│ │ ├── rixi.png
│ │ ├── start_record.png
│ │ └── weimei.png
│ │ ├── drawable
│ │ ├── btn_send_message.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── play_seekbar_progress.xml
│ │ ├── progress_bg.9.png
│ │ ├── pusher_info_background.xml
│ │ ├── record_progress.xml
│ │ └── seekbar_progress_drawable.xml
│ │ ├── layout
│ │ ├── activity_live.xml
│ │ ├── activity_rtmp.xml
│ │ ├── beauty_pannel.xml
│ │ ├── dialog_input_text.xml
│ │ ├── filter_layout.xml
│ │ ├── fragment_beauty_area.xml
│ │ ├── green_layout.xml
│ │ ├── layout_live_pusher_info.xml
│ │ ├── layout_loading_progress.xml
│ │ ├── layout_periscope.xml
│ │ └── layout_progress_bar.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── pause_publish.jpg
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── raw
│ │ └── comments.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── integers.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── zjp
│ └── tencentvideo
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 腾讯视频直播--推流
3 |
具体介绍参考博客
4 | 腾讯视频直播01-直播常见协议和集成sdk:https://www.jianshu.com/p/50d6cdb83018
5 | 腾讯视频直播02-推流:https://www.jianshu.com/p/914bdd9afdb0
6 | 腾讯视频直播03-直播:https://www.jianshu.com/p/608ebdfb238b
7 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "com.zjp.tencentvideo"
7 | minSdkVersion 15
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 |
13 | ndk {
14 | abiFilters "armeabi", "armeabi-v7a"
15 | // 如果您使用的是商业版,只能使用 armeabi 架构,即:
16 | // abiFilters "armeabi",
17 | }
18 |
19 | }
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 |
27 | }
28 |
29 | dependencies {
30 | implementation fileTree(include: ['*.jar'], dir: 'libs')
31 | implementation 'com.android.support:appcompat-v7:27.1.1'
32 | implementation 'com.android.support.constraint:constraint-layout:1.1.0'
33 | testImplementation 'junit:junit:4.12'
34 | androidTestImplementation 'com.android. support.test:runner:1.0.2'
35 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
36 | compile(name: 'LiteAVSDK_Professional_4.6.4218', ext: 'aar')
37 | compile(name: 'liteimsdk-release', ext: 'aar')
38 | compile 'com.android.support:multidex:1.0.1'
39 | implementation 'com.android.support:design:27.1.1'
40 | implementation 'com.github.ctiao:DanmakuFlameMaster:0.9.25'
41 | implementation 'com.github.yyued:SVGAPlayer-Android:2.0.3'
42 | compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
43 | implementation files('libs/gson-2.3.1.jar')
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/libs/LiteAVSDK_Professional_4.6.4218.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/libs/LiteAVSDK_Professional_4.6.4218.aar
--------------------------------------------------------------------------------
/app/libs/gson-2.3.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/libs/gson-2.3.1.jar
--------------------------------------------------------------------------------
/app/libs/liteimsdk-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/libs/liteimsdk-release.aar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/zjp/tencentvideo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.zjp.tencentvideo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/BiliDanmukuParser.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo;
2 |
3 | import android.graphics.Color;
4 | import android.text.TextUtils;
5 |
6 | import org.json.JSONArray;
7 | import org.json.JSONException;
8 | import org.xml.sax.Attributes;
9 | import org.xml.sax.InputSource;
10 | import org.xml.sax.SAXException;
11 | import org.xml.sax.XMLReader;
12 | import org.xml.sax.helpers.DefaultHandler;
13 | import org.xml.sax.helpers.XMLReaderFactory;
14 |
15 | import java.io.IOException;
16 | import java.util.Locale;
17 |
18 | import master.flame.danmaku.danmaku.model.AlphaValue;
19 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
20 | import master.flame.danmaku.danmaku.model.Duration;
21 | import master.flame.danmaku.danmaku.model.IDisplayer;
22 | import master.flame.danmaku.danmaku.model.SpecialDanmaku;
23 | import master.flame.danmaku.danmaku.model.android.DanmakuFactory;
24 | import master.flame.danmaku.danmaku.model.android.Danmakus;
25 | import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
26 | import master.flame.danmaku.danmaku.parser.android.AndroidFileSource;
27 | import master.flame.danmaku.danmaku.util.DanmakuUtils;
28 |
29 | import static master.flame.danmaku.danmaku.model.IDanmakus.ST_BY_TIME;
30 |
31 | /**
32 | * @author wapchief
33 | * @date 2018/3/20
34 | */
35 |
36 | public class BiliDanmukuParser extends BaseDanmakuParser {
37 |
38 | static {
39 | System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
40 | }
41 |
42 | protected float mDispScaleX;
43 | protected float mDispScaleY;
44 |
45 | @Override
46 | public Danmakus parse() {
47 |
48 | if (mDataSource != null) {
49 | AndroidFileSource source = (AndroidFileSource) mDataSource;
50 | try {
51 | XMLReader xmlReader = XMLReaderFactory.createXMLReader();
52 | XmlContentHandler contentHandler = new XmlContentHandler();
53 | xmlReader.setContentHandler(contentHandler);
54 | xmlReader.parse(new InputSource(source.data()));
55 | return contentHandler.getResult();
56 | } catch (SAXException e) {
57 | e.printStackTrace();
58 | } catch (IOException e) {
59 | e.printStackTrace();
60 | }
61 |
62 | }
63 |
64 | return null;
65 | }
66 |
67 | public class XmlContentHandler extends DefaultHandler {
68 |
69 | private static final String TRUE_STRING = "true";
70 |
71 | public Danmakus result;
72 |
73 | public BaseDanmaku item = null;
74 |
75 | public boolean completed = false;
76 |
77 | public int index = 0;
78 |
79 | public Danmakus getResult() {
80 | return result;
81 | }
82 |
83 | @Override
84 | public void startDocument() throws SAXException {
85 | result = new Danmakus(ST_BY_TIME, false, mContext.getBaseComparator());
86 | }
87 |
88 | @Override
89 | public void endDocument() throws SAXException {
90 | completed = true;
91 | }
92 |
93 | @Override
94 | public void startElement(String uri, String localName, String qName, Attributes attributes)
95 | throws SAXException {
96 | String tagName = localName.length() != 0 ? localName : qName;
97 | tagName = tagName.toLowerCase(Locale.getDefault()).trim();
98 | if (tagName.equals("d")) {
99 | // 我从未见过如此厚颜无耻之猴
100 | // 0:时间(弹幕出现时间)
101 | // 1:类型(1从右至左滚动弹幕|6从左至右滚动弹幕|5顶端固定弹幕|4底端固定弹幕|7高级弹幕|8脚本弹幕)
102 | // 2:字号
103 | // 3:颜色
104 | // 4:时间戳 ?
105 | // 5:弹幕池id
106 | // 6:用户hash
107 | // 7:弹幕id
108 | String pValue = attributes.getValue("p");
109 | // parse p value to danmaku
110 | String[] values = pValue.split(",");
111 | if (values.length > 0) {
112 | long time = (long) (parseFloat(values[0]) * 1000); // 出现时间
113 | int type = parseInteger(values[1]); // 弹幕类型
114 | float textSize = parseFloat(values[2]); // 字体大小
115 | int color = (int) ((0x00000000ff000000 | parseLong(values[3])) & 0x00000000ffffffff); // 颜色
116 | // int poolType = parseInteger(values[5]); // 弹幕池类型(忽略
117 | item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
118 | if (item != null) {
119 | item.setTime(time);
120 | item.textSize = textSize * (mDispDensity - 0.6f);
121 | item.textColor = color;
122 | item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
123 | }
124 | }
125 | }
126 | }
127 |
128 | @Override
129 | public void endElement(String uri, String localName, String qName) throws SAXException {
130 | if (item != null && item.text != null) {
131 | if (item.duration != null) {
132 | String tagName = localName.length() != 0 ? localName : qName;
133 | if (tagName.equalsIgnoreCase("d")) {
134 | item.setTimer(mTimer);
135 | item.flags = mContext.mGlobalFlagValues;
136 | Object lock = result.obtainSynchronizer();
137 | synchronized (lock) {
138 | result.addItem(item);
139 | }
140 | }
141 | }
142 | item = null;
143 | }
144 | }
145 |
146 | @Override
147 | public void characters(char[] ch, int start, int length) {
148 | if (item != null) {
149 | DanmakuUtils.fillText(item, decodeXmlString(new String(ch, start, length)));
150 | item.index = index++;
151 |
152 | // initial specail danmaku data
153 | String text = String.valueOf(item.text).trim();
154 | if (item.getType() == BaseDanmaku.TYPE_SPECIAL && text.startsWith("[")
155 | && text.endsWith("]")) {
156 | //text = text.substring(1, text.length() - 1);
157 | String[] textArr = null;//text.split(",", -1);
158 | try {
159 | JSONArray jsonArray = new JSONArray(text);
160 | textArr = new String[jsonArray.length()];
161 | for (int i = 0; i < textArr.length; i++) {
162 | textArr[i] = jsonArray.getString(i);
163 | }
164 | } catch (JSONException e) {
165 | e.printStackTrace();
166 | }
167 |
168 | if (textArr == null || textArr.length < 5 || TextUtils.isEmpty(textArr[4])) {
169 | item = null;
170 | return;
171 | }
172 | DanmakuUtils.fillText(item, textArr[4]);
173 | float beginX = parseFloat(textArr[0]);
174 | float beginY = parseFloat(textArr[1]);
175 | float endX = beginX;
176 | float endY = beginY;
177 | String[] alphaArr = textArr[2].split("-");
178 | int beginAlpha = (int) (AlphaValue.MAX * parseFloat(alphaArr[0]));
179 | int endAlpha = beginAlpha;
180 | if (alphaArr.length > 1) {
181 | endAlpha = (int) (AlphaValue.MAX * parseFloat(alphaArr[1]));
182 | }
183 | long alphaDuraion = (long) (parseFloat(textArr[3]) * 1000);
184 | long translationDuration = alphaDuraion;
185 | long translationStartDelay = 0;
186 | float rotateY = 0, rotateZ = 0;
187 | if (textArr.length >= 7) {
188 | rotateZ = parseFloat(textArr[5]);
189 | rotateY = parseFloat(textArr[6]);
190 | }
191 | if (textArr.length >= 11) {
192 | endX = parseFloat(textArr[7]);
193 | endY = parseFloat(textArr[8]);
194 | if (!"".equals(textArr[9])) {
195 | translationDuration = parseInteger(textArr[9]);
196 | }
197 | if (!"".equals(textArr[10])) {
198 | translationStartDelay = (long) (parseFloat(textArr[10]));
199 | }
200 | }
201 | if (isPercentageNumber(textArr[0])) {
202 | beginX *= DanmakuFactory.BILI_PLAYER_WIDTH;
203 | }
204 | if (isPercentageNumber(textArr[1])) {
205 | beginY *= DanmakuFactory.BILI_PLAYER_HEIGHT;
206 | }
207 | if (textArr.length >= 8 && isPercentageNumber(textArr[7])) {
208 | endX *= DanmakuFactory.BILI_PLAYER_WIDTH;
209 | }
210 | if (textArr.length >= 9 && isPercentageNumber(textArr[8])) {
211 | endY *= DanmakuFactory.BILI_PLAYER_HEIGHT;
212 | }
213 | item.duration = new Duration(alphaDuraion);
214 | item.rotationZ = rotateZ;
215 | item.rotationY = rotateY;
216 | mContext.mDanmakuFactory.fillTranslationData(item, beginX,
217 | beginY, endX, endY, translationDuration, translationStartDelay, mDispScaleX, mDispScaleY);
218 | mContext.mDanmakuFactory.fillAlphaData(item, beginAlpha, endAlpha, alphaDuraion);
219 |
220 | if (textArr.length >= 12) {
221 | // 是否有描边
222 | if (!TextUtils.isEmpty(textArr[11]) && TRUE_STRING.equalsIgnoreCase(textArr[11])) {
223 | item.textShadowColor = Color.TRANSPARENT;
224 | }
225 | }
226 | if (textArr.length >= 13) {
227 | //TODO 字体 textArr[12]
228 | }
229 | if (textArr.length >= 14) {
230 | // Linear.easeIn or Quadratic.easeOut
231 | ((SpecialDanmaku) item).isQuadraticEaseOut = ("0".equals(textArr[13]));
232 | }
233 | if (textArr.length >= 15) {
234 | // 路径数据
235 | if (!"".equals(textArr[14])) {
236 | String motionPathString = textArr[14].substring(1);
237 | if (!TextUtils.isEmpty(motionPathString)) {
238 | String[] pointStrArray = motionPathString.split("L");
239 | if (pointStrArray.length > 0) {
240 | float[][] points = new float[pointStrArray.length][2];
241 | for (int i = 0; i < pointStrArray.length; i++) {
242 | String[] pointArray = pointStrArray[i].split(",");
243 | if (pointArray.length >= 2) {
244 | points[i][0] = parseFloat(pointArray[0]);
245 | points[i][1] = parseFloat(pointArray[1]);
246 | }
247 | }
248 | mContext.mDanmakuFactory.fillLinePathData(item, points, mDispScaleX,
249 | mDispScaleY);
250 | }
251 | }
252 | }
253 | }
254 | }
255 |
256 | }
257 | }
258 |
259 | private String decodeXmlString(String title) {
260 | if (title.contains("&")) {
261 | title = title.replace("&", "&");
262 | }
263 | if (title.contains(""")) {
264 | title = title.replace(""", "\"");
265 | }
266 | if (title.contains(">")) {
267 | title = title.replace(">", ">");
268 | }
269 | if (title.contains("<")) {
270 | title = title.replace("<", "<");
271 | }
272 | return title;
273 | }
274 |
275 | }
276 |
277 | private boolean isPercentageNumber(String number) {
278 | //return number >= 0f && number <= 1f;
279 | return number != null && number.contains(".");
280 | }
281 |
282 | private float parseFloat(String floatStr) {
283 | try {
284 | return Float.parseFloat(floatStr);
285 | } catch (NumberFormatException e) {
286 | return 0.0f;
287 | }
288 | }
289 |
290 | private int parseInteger(String intStr) {
291 | try {
292 | return Integer.parseInt(intStr);
293 | } catch (NumberFormatException e) {
294 | return 0;
295 | }
296 | }
297 |
298 | private long parseLong(String longStr) {
299 | try {
300 | return Long.parseLong(longStr);
301 | } catch (NumberFormatException e) {
302 | return 0;
303 | }
304 | }
305 |
306 | @Override
307 | public BaseDanmakuParser setDisplayer(IDisplayer disp) {
308 | super.setDisplayer(disp);
309 | mDispScaleX = mDispWidth / DanmakuFactory.BILI_PLAYER_WIDTH;
310 | mDispScaleY = mDispHeight / DanmakuFactory.BILI_PLAYER_HEIGHT;
311 | return this;
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/DanmakuController.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.drawable.BitmapDrawable;
8 | import android.graphics.drawable.Drawable;
9 | import android.text.Spannable;
10 | import android.text.SpannableStringBuilder;
11 | import android.text.Spanned;
12 | import android.text.TextPaint;
13 | import android.text.style.BackgroundColorSpan;
14 | import android.text.style.ImageSpan;
15 | import android.util.Log;
16 |
17 | import java.io.IOException;
18 | import java.io.InputStream;
19 | import java.net.MalformedURLException;
20 | import java.net.URL;
21 | import java.net.URLConnection;
22 | import java.util.HashMap;
23 | import java.util.Timer;
24 | import java.util.TimerTask;
25 |
26 | import master.flame.danmaku.controller.IDanmakuView;
27 | import master.flame.danmaku.danmaku.loader.ILoader;
28 | import master.flame.danmaku.danmaku.loader.IllegalDataException;
29 | import master.flame.danmaku.danmaku.loader.android.DanmakuLoaderFactory;
30 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
31 | import master.flame.danmaku.danmaku.model.DanmakuTimer;
32 | import master.flame.danmaku.danmaku.model.IDanmakus;
33 | import master.flame.danmaku.danmaku.model.IDisplayer;
34 | import master.flame.danmaku.danmaku.model.android.BaseCacheStuffer;
35 | import master.flame.danmaku.danmaku.model.android.DanmakuContext;
36 | import master.flame.danmaku.danmaku.model.android.Danmakus;
37 | import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer;
38 | import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
39 | import master.flame.danmaku.danmaku.parser.IDataSource;
40 | import master.flame.danmaku.danmaku.util.IOUtils;
41 | import master.flame.danmaku.danmaku.util.SystemClock;
42 | import master.flame.danmaku.ui.widget.DanmakuView;
43 |
44 | /**
45 | * @author wapchief
46 | * @date 2018/3/21
47 | */
48 |
49 | public class DanmakuController {
50 | /**
51 | * 弹幕
52 | */
53 | private DanmakuContext mContext;
54 | private DanmakuView mDanmakuView;
55 | private Context content;
56 | BaseDanmakuParser mParser;
57 | public DanmakuController(DanmakuView danmakuView, Context content) {
58 | mDanmakuView = danmakuView;
59 | this.content = content;
60 | }
61 |
62 | /**初始化弹幕*/
63 | public void initDanmaKu() {
64 |
65 | // 设置最大显示行数
66 | HashMap maxLinesPair = new HashMap();
67 | maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 5); // 滚动弹幕最大显示5行
68 | // 设置是否禁止重叠
69 | HashMap overlappingEnablePair = new HashMap();
70 | overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
71 | overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
72 |
73 | mContext = DanmakuContext.create();
74 | mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3).setDuplicateMergingEnabled(false).setScrollSpeedFactor(1.2f).setScaleTextSize(1.2f)
75 | .setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer
76 | // .setCacheStuffer(new BackgroundCacheStuffer()) // 绘制背景使用BackgroundCacheStuffer
77 | .setMaximumLines(maxLinesPair)
78 | .preventOverlapping(overlappingEnablePair).setDanmakuMargin(40);
79 | if (mDanmakuView != null) {
80 | //本地弹幕资源
81 | mParser = createParser(content.getResources().openRawResource(R.raw.comments));
82 | mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() {
83 | @Override
84 | public void updateTimer(DanmakuTimer timer) {
85 | }
86 |
87 | @Override
88 | public void drawingFinished() {
89 |
90 | }
91 |
92 | @Override
93 | public void danmakuShown(BaseDanmaku danmaku) {
94 | // Log.d("DFM", "danmakuShown(): text=" + danmaku.text);
95 | }
96 |
97 | @Override
98 | public void prepared() {
99 | mDanmakuView.start();
100 | }
101 | });
102 | mDanmakuView.setOnDanmakuClickListener(new IDanmakuView.OnDanmakuClickListener() {
103 |
104 | @Override
105 | public boolean onDanmakuClick(IDanmakus danmakus) {
106 | Log.d("DFM", "onDanmakuClick: danmakus size:" + danmakus.size());
107 | BaseDanmaku latest = danmakus.last();
108 | if (null != latest) {
109 | Log.d("DFM", "onDanmakuClick: text of latest danmaku:" + latest.text);
110 | return true;
111 | }
112 | return false;
113 | }
114 |
115 | @Override
116 | public boolean onDanmakuLongClick(IDanmakus danmakus) {
117 | return false;
118 | }
119 |
120 | @Override
121 | public boolean onViewClick(IDanmakuView view) {
122 | // mMediaController.setVisibility(View.VISIBLE);
123 | return false;
124 | }
125 | });
126 | mDanmakuView.prepare(mParser, mContext);
127 | mDanmakuView.showFPS(false);
128 | mDanmakuView.enableDanmakuDrawingCache(true);
129 | }
130 |
131 | // if (mVideoView != null) {
132 | // mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
133 | // @Override
134 | // public void onPrepared(MediaPlayer mediaPlayer) {
135 | // mediaPlayer.start();
136 | // }
137 | // });
138 | // mVideoView.setVideoPath(Environment.getExternalStorageDirectory() + "/1.flv");
139 | // }
140 | }
141 |
142 | private void addDanmaku(boolean islive) {
143 | BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
144 | if (danmaku == null || mDanmakuView == null) {
145 | return;
146 | }
147 | // for(int i=0;i<100;i++){
148 | // }
149 | danmaku.text = "这是一条弹幕" + System.nanoTime();
150 | danmaku.padding = 5;
151 | danmaku.priority = 0; // 可能会被各种过滤器过滤并隐藏显示
152 | danmaku.isLive = islive;
153 | danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
154 | danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
155 | danmaku.textColor = Color.RED;
156 | danmaku.textShadowColor = Color.WHITE;
157 | // danmaku.underlineColor = Color.GREEN;
158 | danmaku.borderColor = Color.GREEN;
159 | mDanmakuView.addDanmaku(danmaku);
160 |
161 | }
162 |
163 | /**
164 | * 绘制背景(自定义弹幕样式)
165 | */
166 | private static class BackgroundCacheStuffer extends SpannedCacheStuffer {
167 | // 通过扩展SimpleTextCacheStuffer或SpannedCacheStuffer个性化你的弹幕样式
168 | final Paint paint = new Paint();
169 |
170 | @Override
171 | public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {
172 | danmaku.padding = 10; // 在背景绘制模式下增加padding
173 | super.measure(danmaku, paint, fromWorkerThread);
174 | }
175 |
176 | @Override
177 | public void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top) {
178 | paint.setColor(0x8125309b);
179 | canvas.drawRect(left + 2, top + 2, left + danmaku.paintWidth - 2, top + danmaku.paintHeight - 2, paint);
180 | }
181 |
182 | @Override
183 | public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, Paint paint) {
184 | // 禁用描边绘制
185 | }
186 | }
187 |
188 | private BaseDanmakuParser createParser(InputStream stream) {
189 |
190 | if (stream == null) {
191 | return new BaseDanmakuParser() {
192 |
193 | @Override
194 | protected Danmakus parse() {
195 | return new Danmakus();
196 | }
197 | };
198 | }
199 |
200 | ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI);
201 |
202 | try {
203 | loader.load(stream);
204 | } catch (IllegalDataException e) {
205 | e.printStackTrace();
206 | }
207 | BaseDanmakuParser parser = new BiliDanmukuParser();
208 | IDataSource> dataSource = loader.getDataSource();
209 | parser.load(dataSource);
210 | return parser;
211 |
212 | }
213 |
214 | Timer timer = new Timer();
215 |
216 | class AsyncAddTask extends TimerTask {
217 |
218 | @Override
219 | public void run() {
220 | for (int i = 0; i < 20; i++) {
221 | addDanmaku(true);
222 | SystemClock.sleep(20);
223 | }
224 | }
225 | };
226 |
227 | /**发送一条弹幕*/
228 | public void addDanmaku(boolean islive,String content) {
229 | BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
230 | if (danmaku == null || mDanmakuView == null) {
231 | return;
232 | }
233 | danmaku.text = "我:"+content + "~来自iPhone X";
234 | danmaku.padding = 5;
235 | //可能会被各种过滤器过滤并隐藏显示
236 | danmaku.priority = 1;
237 | danmaku.isLive = islive;
238 | //设置发送后多久显示
239 | danmaku.setTime(mDanmakuView.getCurrentTime() + 1500);
240 | danmaku.textSize = 50f * (mParser.getDisplayer().getDensity() - 0.6f);
241 | danmaku.textColor = Color.RED;
242 | danmaku.textShadowColor = Color.WHITE;
243 | // danmaku.underlineColor = Color.GREEN;
244 | danmaku.borderColor = Color.GREEN;
245 | danmaku.setTimer(new DanmakuTimer(3000));
246 | mDanmakuView.addDanmaku(danmaku);
247 |
248 | }
249 |
250 | /**发送其它类型的弹幕*/
251 | private void addDanmaKuShowTextAndImage(boolean islive) {
252 | BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
253 | Drawable drawable = content.getResources().getDrawable(R.mipmap.ic_launcher);
254 | drawable.setBounds(0, 0, 100, 100);
255 | SpannableStringBuilder spannable = createSpannable(drawable);
256 | danmaku.text = spannable;
257 | danmaku.padding = 5;
258 | danmaku.priority = 1; // 一定会显示, 一般用于本机发送的弹幕
259 | danmaku.isLive = islive;
260 | danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
261 | danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
262 | danmaku.textColor = Color.RED;
263 | danmaku.textShadowColor = 0; // 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低
264 | danmaku.underlineColor = Color.GREEN;
265 | mDanmakuView.addDanmaku(danmaku);
266 | }
267 |
268 | private SpannableStringBuilder createSpannable(Drawable drawable) {
269 | String text = "bitmap";
270 | SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
271 | ImageSpan span = new ImageSpan(drawable);//ImageSpan.ALIGN_BOTTOM);
272 | spannableStringBuilder.setSpan(span, 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
273 | spannableStringBuilder.append("图文混排");
274 | spannableStringBuilder.setSpan(new BackgroundColorSpan(Color.parseColor("#8A2233B1")), 0, spannableStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
275 | return spannableStringBuilder;
276 | }
277 |
278 |
279 | private BaseCacheStuffer.Proxy mCacheStufferAdapter = new BaseCacheStuffer.Proxy() {
280 |
281 | private Drawable mDrawable;
282 |
283 | @Override
284 | public void prepareDrawing(final BaseDanmaku danmaku, boolean fromWorkerThread) {
285 | if (danmaku.text instanceof Spanned) { // 根据你的条件检查是否需要需要更新弹幕
286 | // FIXME 这里只是简单启个线程来加载远程url图片,请使用你自己的异步线程池,最好加上你的缓存池
287 | new Thread() {
288 |
289 | @Override
290 | public void run() {
291 | String url = "http://www.bilibili.com/favicon.ico";
292 | InputStream inputStream = null;
293 | Drawable drawable = mDrawable;
294 | if(drawable == null) {
295 | try {
296 | URLConnection urlConnection = new URL(url).openConnection();
297 | inputStream = urlConnection.getInputStream();
298 | drawable = BitmapDrawable.createFromStream(inputStream, "bitmap");
299 | mDrawable = drawable;
300 | } catch (MalformedURLException e) {
301 | e.printStackTrace();
302 | } catch (IOException e) {
303 | e.printStackTrace();
304 | } finally {
305 | IOUtils.closeQuietly(inputStream);
306 | }
307 | }
308 | if (drawable != null) {
309 | drawable.setBounds(0, 0, 100, 100);
310 | SpannableStringBuilder spannable = createSpannable(drawable);
311 | danmaku.text = spannable;
312 | if(mDanmakuView != null) {
313 | mDanmakuView.invalidateDanmaku(danmaku, false);
314 | }
315 | return;
316 | }
317 | }
318 | }.start();
319 | }
320 | }
321 |
322 | @Override
323 | public void releaseResource(BaseDanmaku danmaku) {
324 | // TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable
325 | }
326 | };
327 | }
328 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/TecentVideoTestApplication.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo;
2 |
3 | import android.support.multidex.MultiDexApplication;
4 |
5 | /**
6 | * Created by zjp on 2018/5/29 17:20.
7 | */
8 |
9 | public class TecentVideoTestApplication extends MultiDexApplication {
10 |
11 | private static TecentVideoTestApplication instance;
12 |
13 | @Override
14 | public void onCreate() {
15 | super.onCreate();
16 | instance = this;
17 | }
18 |
19 | public static TecentVideoTestApplication getApplication() {
20 | return instance;
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/beautysettings/TCHorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.beautysettings;
2 |
3 | import android.content.Context;
4 | import android.database.DataSetObserver;
5 | import android.os.Build;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Adapter;
10 |
11 |
12 | public class TCHorizontalScrollView extends android.widget.HorizontalScrollView {
13 |
14 | public TCHorizontalScrollView(Context context) {
15 | super(context);
16 | initialize();
17 | }
18 |
19 | public TCHorizontalScrollView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | initialize();
22 | }
23 |
24 | public TCHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
25 | super(context, attrs, defStyleAttr);
26 | initialize();
27 | }
28 |
29 | private DataSetObserver observer;
30 | public void setAdapter(Adapter adapter) {
31 | if (this.adapter != null) {
32 | this.adapter.unregisterDataSetObserver(observer);
33 | }
34 | this.adapter = adapter;
35 | adapter.registerDataSetObserver(observer);
36 | updateAdapter();
37 | }
38 |
39 | private void updateAdapter() {
40 | ViewGroup group = (ViewGroup)getChildAt(0);
41 | group.removeAllViews();
42 |
43 | for (int i = 0; i= Build.VERSION_CODES.JELLY_BEAN_MR1) {
71 | getChildAt(0).setPaddingRelative(side, 0, side, 0);
72 | } else {
73 | getChildAt(0).setPadding(side,0,side,0);
74 | }
75 |
76 | }
77 |
78 | public void setClicked(int position) {
79 | ((ViewGroup)getChildAt(0)).getChildAt(position).performClick();
80 | }
81 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/ui/LiveActivity.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.ui;
2 |
3 | import android.content.Intent;
4 | import android.content.res.Configuration;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.SwitchCompat;
10 | import android.text.TextUtils;
11 | import android.util.Log;
12 | import android.view.Display;
13 | import android.view.View;
14 | import android.view.WindowManager;
15 | import android.widget.Button;
16 | import android.widget.CompoundButton;
17 | import android.widget.FrameLayout;
18 | import android.widget.ImageView;
19 | import android.widget.ListView;
20 | import android.widget.ProgressBar;
21 | import android.widget.TextView;
22 | import android.widget.Toast;
23 |
24 | import com.opensource.svgaplayer.SVGADrawable;
25 | import com.opensource.svgaplayer.SVGAImageView;
26 | import com.opensource.svgaplayer.SVGAParser;
27 | import com.opensource.svgaplayer.SVGAVideoEntity;
28 | import com.tencent.rtmp.ITXLivePlayListener;
29 | import com.tencent.rtmp.TXLiveConstants;
30 | import com.tencent.rtmp.TXLivePlayConfig;
31 | import com.tencent.rtmp.TXLivePlayer;
32 | import com.tencent.rtmp.ui.TXCloudVideoView;
33 | import com.tencent.ugc.TXRecordCommon;
34 | import com.zjp.tencentvideo.DanmakuController;
35 | import com.zjp.tencentvideo.R;
36 | import com.zjp.tencentvideo.utils.TCFrequeControl;
37 | import com.zjp.tencentvideo.view.TCInputTextMsgDialog;
38 | import com.zjp.tencentvideo.view.like.TCHeartLayout;
39 |
40 | import java.io.File;
41 | import java.net.MalformedURLException;
42 | import java.net.URL;
43 |
44 | import master.flame.danmaku.ui.widget.DanmakuView;
45 |
46 | /**
47 | * Created by zjp on 2018/5/30 13:53.
48 | */
49 |
50 | public class LiveActivity extends AppCompatActivity implements TCInputTextMsgDialog.OnTextSendListener, View.OnClickListener, ITXLivePlayListener {
51 |
52 | private TXCloudVideoView mTxCloudVideoView;
53 | private DanmakuView danmakuView;
54 | private SwitchCompat mSwitchBt;
55 | private RecyclerView mRv_user_avatar;
56 | private ImageView mBtn_message_input, mbtn_record, mbtn_like, mclose_record, mrecord, mretry_record, mPlayBtn, mbtn_linkmic, mBtnRenderRotation;
57 | private Button mbtn_back;
58 | private ListView mim_msg_listview;
59 | private ProgressBar mrecord_progress;
60 | private TCHeartLayout mheart_layout;
61 | private DanmakuView mDanmakuView;
62 | private TCHeartLayout mHeartLayout;
63 | private TextView mtv_animation;
64 | private SVGAImageView mimageView;
65 |
66 | private TCFrequeControl mLikeFrequeControl;
67 |
68 | private int mCurrentRenderMode;
69 | private int mCurrentRenderRotation;
70 |
71 | private boolean flag;
72 | private boolean isStopAnimation;
73 |
74 | private TXLivePlayConfig mPlayConfig;
75 | private long mStartPlayTS = 0;
76 |
77 | /**
78 | * inputDialog
79 | */
80 | TCInputTextMsgDialog mInputTextMsgDialog;
81 |
82 | /**
83 | * 弹幕
84 | */
85 | DanmakuController mDanmakuController;
86 |
87 | private TXLivePlayer mLivePlayer;
88 |
89 | @Override
90 | protected void onCreate(@Nullable Bundle savedInstanceState) {
91 | super.onCreate(savedInstanceState);
92 | setContentView(R.layout.activity_live);
93 |
94 | initView();
95 | initData();
96 | initListener();
97 | }
98 |
99 | private void initView() {
100 |
101 | mCurrentRenderMode = TXLiveConstants.RENDER_MODE_ADJUST_RESOLUTION;
102 | mCurrentRenderRotation = TXLiveConstants.RENDER_ROTATION_PORTRAIT;
103 |
104 | mTxCloudVideoView = findViewById(R.id.video_view);
105 | danmakuView = findViewById(R.id.danmaku);
106 | mSwitchBt = findViewById(R.id.switch_bt);
107 | mRv_user_avatar = findViewById(R.id.rv_user_avatar);
108 | mBtn_message_input = findViewById(R.id.btn_message_input);
109 | mtv_animation = findViewById(R.id.tv_animation);
110 | mbtn_record = findViewById(R.id.btn_record);
111 | mbtn_like = findViewById(R.id.btn_like);
112 | mbtn_back = findViewById(R.id.btn_back);
113 | mim_msg_listview = findViewById(R.id.im_msg_listview);
114 | mrecord_progress = findViewById(R.id.record_progress);
115 | mclose_record = findViewById(R.id.close_record);
116 | mrecord = findViewById(R.id.record);
117 | mretry_record = findViewById(R.id.retry_record);
118 | mheart_layout = findViewById(R.id.heart_layout);
119 | mDanmakuView = findViewById(R.id.danmakuView);
120 | mPlayBtn = findViewById(R.id.play_btn);
121 | mbtn_linkmic = findViewById(R.id.btn_linkmic);
122 | mHeartLayout = findViewById(R.id.heart_layout);
123 | mBtnRenderRotation = findViewById(R.id.btnOrientation);
124 | mimageView = findViewById(R.id.imageView);
125 | }
126 |
127 | private void initData() {
128 |
129 | mbtn_record.setVisibility(View.GONE);
130 |
131 |
132 | mInputTextMsgDialog = new TCInputTextMsgDialog(this, R.style.InputDialog);
133 | mInputTextMsgDialog.setmOnTextSendListener(this);
134 | initRtmpPlayer();
135 | initDanmaKu();
136 | }
137 |
138 | private void initListener() {
139 | mBtn_message_input.setOnClickListener(this);
140 | mbtn_linkmic.setOnClickListener(this);
141 | mbtn_like.setOnClickListener(this);
142 | mBtnRenderRotation.setOnClickListener(this);
143 | mtv_animation.setOnClickListener(this);
144 | }
145 |
146 | /**
147 | * 初始化播放
148 | */
149 | private void initRtmpPlayer() {
150 |
151 | mTxCloudVideoView.setLogMargin(12, 12, 110, 60);
152 | mTxCloudVideoView.showLog(false);
153 | //创建 player 对象
154 | mLivePlayer = new TXLivePlayer(this);
155 | //关键 player 对象与界面 view
156 | mLivePlayer.setPlayerView(mTxCloudVideoView);
157 |
158 |
159 | mPlayConfig = new TXLivePlayConfig();
160 | //自动模式
161 | mPlayConfig.setAutoAdjustCacheTime(true);
162 | mPlayConfig.setCacheTime(5.0f);
163 | mPlayConfig.setMaxAutoAdjustCacheTime(5.0f);
164 | mPlayConfig.setMinAutoAdjustCacheTime(1.0f);
165 |
166 | // 设置播放器缓存时间.
167 | mPlayConfig.setMaxCacheItems(2);
168 | //设置播放器重连次数.
169 | mPlayConfig.setConnectRetryCount(5);
170 | //设置播放器重连间隔.
171 | mPlayConfig.setConnectRetryInterval(3);
172 | //开启就近选路 非腾讯云不用
173 | mPlayConfig.setEnableNearestIP(false);
174 | //设置自动调整时播放器最大缓存时间.
175 | mPlayConfig.setMaxAutoAdjustCacheTime(5.0f);
176 |
177 | //设置RTMP传输通道的类型
178 | // mPlayConfig.setRtmpChannelType(TXLivePlayer.PLAY_TYPE_LIVE_RTMP);
179 | mLivePlayer.setConfig(mPlayConfig);
180 | mLivePlayer.setPlayListener(this);
181 | //将图像等比例铺满整个屏幕,多余部分裁剪掉,此模式下画面不会留黑边,但可能因为部分区域被裁剪而显示不全。
182 | mLivePlayer.setRenderMode(TXLiveConstants.RENDER_MODE_FULL_FILL_SCREEN);
183 | //正常播放
184 | mLivePlayer.setRenderRotation(TXLiveConstants.RENDER_ROTATION_PORTRAIT);
185 | //硬件加速
186 | mLivePlayer.enableHardwareDecode(true);
187 |
188 | mTxCloudVideoView.setVisibility(View.VISIBLE);
189 |
190 | String url = "rtmp://24649.liveplay.myqcloud.com/live/24649_743e7a0df4";
191 | mLivePlayer.startPlay(url, TXLivePlayer.PLAY_TYPE_LIVE_RTMP);
192 |
193 | mStartPlayTS = System.currentTimeMillis();
194 | }
195 |
196 | /**
197 | * 初始化弹幕
198 | */
199 | private void initDanmaKu() {
200 | mDanmakuController = new DanmakuController(mDanmakuView, this);
201 | mDanmakuController.initDanmaKu();
202 | //默认不显示
203 | mDanmakuView.hide();
204 | //总开关
205 | mSwitchBt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
206 | @Override
207 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
208 | if (isChecked) {
209 | mDanmakuView.show();
210 | } else {
211 | mDanmakuView.hide();
212 | }
213 | }
214 | });
215 | }
216 |
217 | /**
218 | * 发送弹幕后的回调
219 | */
220 | @Override
221 | public void onTextSend(String msg, boolean tanmuOpen) {
222 | if (msg.length() == 0) {
223 |
224 | return;
225 | }
226 | //关联弹幕总开关
227 | if (tanmuOpen) {
228 | mDanmakuView.show();
229 | mSwitchBt.setChecked(true);
230 | }
231 | //消息显示
232 | mDanmakuController.addDanmaku(tanmuOpen, msg);
233 | }
234 |
235 | /**
236 | * 发送消息弹出框
237 | */
238 | private void showInputMsgDialog() {
239 | WindowManager windowManager = getWindowManager();
240 | Display display = windowManager.getDefaultDisplay();
241 | WindowManager.LayoutParams lp = mInputTextMsgDialog.getWindow().getAttributes();
242 | lp.width = (display.getWidth());
243 | mInputTextMsgDialog.getWindow().setAttributes(lp);
244 | mInputTextMsgDialog.setCancelable(true);
245 | mInputTextMsgDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
246 | mInputTextMsgDialog.show();
247 | }
248 |
249 | @Override
250 | public void onConfigurationChanged(Configuration newConfig) {
251 | super.onConfigurationChanged(newConfig);
252 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
253 | mDanmakuView.getConfig().setDanmakuMargin(20);
254 | } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
255 | mDanmakuView.getConfig().setDanmakuMargin(40);
256 | }
257 | }
258 |
259 | @Override
260 | public void onClick(View v) {
261 | switch (v.getId()) {
262 | case R.id.btn_message_input:
263 | showInputMsgDialog();
264 | break;
265 | case R.id.btn_linkmic:
266 | flag = !flag;
267 | if (flag) {
268 | stopPlay();
269 | } else {
270 | startPlay();
271 | }
272 | break;
273 |
274 | case R.id.btn_like:
275 | /**点赞*/
276 | if (mHeartLayout != null) {
277 | mHeartLayout.setVisibility(View.VISIBLE);
278 | mHeartLayout.addFavor();
279 | }
280 | //点赞发送请求限制
281 | if (mLikeFrequeControl == null) {
282 | mLikeFrequeControl = new TCFrequeControl();
283 | mLikeFrequeControl.init(2, 1);
284 | }
285 | break;
286 |
287 | case R.id.btnOrientation:
288 | if (mLivePlayer == null) {
289 | return;
290 | }
291 |
292 | if (mCurrentRenderRotation == TXLiveConstants.RENDER_ROTATION_PORTRAIT) {
293 | mBtnRenderRotation.setBackgroundResource(R.drawable.portrait);
294 | mCurrentRenderRotation = TXLiveConstants.RENDER_ROTATION_LANDSCAPE;
295 | } else if (mCurrentRenderRotation == TXLiveConstants.RENDER_ROTATION_LANDSCAPE) {
296 | mBtnRenderRotation.setBackgroundResource(R.drawable.landscape);
297 | mCurrentRenderRotation = TXLiveConstants.RENDER_ROTATION_PORTRAIT;
298 | }
299 |
300 | mLivePlayer.setRenderRotation(mCurrentRenderRotation);
301 |
302 | break;
303 |
304 | case R.id.tv_animation:
305 | isStopAnimation = !isStopAnimation;
306 | if (isStopAnimation) {
307 | mimageView.setVisibility(View.VISIBLE);
308 | SVGAParser parser = new SVGAParser(this);
309 | try {
310 | parser.parse(new URL("https://github.com/yyued/SVGA-Samples/blob/master/kingset.svga?raw=true"), new SVGAParser.ParseCompletion() {
311 | @Override
312 | public void onComplete(SVGAVideoEntity mSVGAVideoEntity) {
313 | SVGADrawable drawable = new SVGADrawable(mSVGAVideoEntity);
314 | mimageView.setImageDrawable(drawable);
315 | mimageView.startAnimation();
316 | }
317 |
318 | @Override
319 | public void onError() {
320 | Toast.makeText(LiveActivity.this, "parse error!", Toast.LENGTH_SHORT).show();
321 | }
322 | });
323 | } catch (Exception e) {
324 | System.out.print(true);
325 | }
326 | } else {
327 | mimageView.stopAnimation();
328 | mimageView.setVisibility(View.GONE);
329 | }
330 | break;
331 | }
332 | }
333 |
334 | private void stopPlay() {
335 | if (mLivePlayer != null) {
336 | mLivePlayer.pause(); // 暂停
337 | }
338 | mbtn_linkmic.setBackgroundResource(R.drawable.play_start);
339 | }
340 |
341 | private void startPlay() {
342 | if (mLivePlayer != null) {
343 | mLivePlayer.resume(); // 继续
344 | }
345 | mbtn_linkmic.setBackgroundResource(R.drawable.play_pause);
346 | }
347 |
348 | @Override
349 | protected void onPause() {
350 | super.onPause();
351 | if (mDanmakuView != null && mDanmakuView.isPrepared()) {
352 | mDanmakuView.pause();
353 | }
354 | }
355 |
356 | @Override
357 | protected void onResume() {
358 | super.onResume();
359 | if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
360 | mDanmakuView.resume();
361 | }
362 | }
363 |
364 | @Override
365 | protected void onDestroy() {
366 | super.onDestroy();
367 | if (mDanmakuView != null) {
368 | // dont forget release!
369 | mDanmakuView.release();
370 | mDanmakuView = null;
371 | }
372 | if (mTxCloudVideoView != null) {
373 | mLivePlayer.stopPlay(true); // true 代表清除最后一帧画面
374 | mTxCloudVideoView.onDestroy();
375 |
376 | }
377 | }
378 |
379 | @Override
380 | public void onBackPressed() {
381 | super.onBackPressed();
382 | if (mDanmakuView != null) {
383 | // dont forget release!
384 | mDanmakuView.release();
385 | mDanmakuView = null;
386 | }
387 | }
388 |
389 | @Override
390 | public void onPlayEvent(int event, Bundle bundle) {
391 | String playEventLog = "receive event: " + event + ", " + bundle.getString(TXLiveConstants.EVT_DESCRIPTION);
392 | Log.d("zjp", "playEventLog=" + playEventLog);
393 |
394 | if (event == TXLiveConstants.PLAY_EVT_PLAY_BEGIN) {
395 | Log.d("zjp", "PlayFirstRender,cost=" + (System.currentTimeMillis() - mStartPlayTS));
396 | } else if (event == TXLiveConstants.PLAY_ERR_NET_DISCONNECT || event == TXLiveConstants.PLAY_EVT_PLAY_END) {
397 | stopPlay();
398 | } else if (event == TXLiveConstants.PLAY_EVT_PLAY_LOADING) {
399 | // startLoadingAnimation();
400 | } else if (event == TXLiveConstants.PLAY_EVT_RCV_FIRST_I_FRAME) {
401 | // stopLoadingAnimation();
402 | } else if (event == TXLiveConstants.PLAY_EVT_CHANGE_RESOLUTION) {
403 | // streamRecord(false);
404 | } else if (event == TXLiveConstants.PLAY_EVT_CHANGE_ROTATION) {
405 | return;
406 | }
407 |
408 | if (event < 0) {
409 | Toast.makeText(getApplicationContext(), bundle.getString(TXLiveConstants.EVT_DESCRIPTION), Toast.LENGTH_SHORT).show();
410 | }
411 | }
412 |
413 | @Override
414 | public void onNetStatus(Bundle bundle) {
415 | String str = getNetStatusString(bundle);
416 | Log.d("zjp", "str=" + str);
417 | Log.d("zjp", "Current status, CPU:" + bundle.getString(TXLiveConstants.NET_STATUS_CPU_USAGE) +
418 | ", RES:" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH) + "*" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT) +
419 | ", SPD:" + bundle.getInt(TXLiveConstants.NET_STATUS_NET_SPEED) + "Kbps" +
420 | ", FPS:" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_FPS) +
421 | ", ARA:" + bundle.getInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE) + "Kbps" +
422 | ", VRA:" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE) + "Kbps");
423 | }
424 |
425 |
426 | //公用打印辅助函数
427 | protected String getNetStatusString(Bundle status) {
428 | String str = String.format("%-14s %-14s %-12s\n%-8s %-8s %-8s %-8s\n%-14s %-14s\n%-14s %-14s",
429 | "CPU:" + status.getString(TXLiveConstants.NET_STATUS_CPU_USAGE),
430 | "RES:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH) + "*" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT),
431 | "SPD:" + status.getInt(TXLiveConstants.NET_STATUS_NET_SPEED) + "Kbps",
432 | "JIT:" + status.getInt(TXLiveConstants.NET_STATUS_NET_JITTER),
433 | "FPS:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_FPS),
434 | "GOP:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_GOP) + "s",
435 | "ARA:" + status.getInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE) + "Kbps",
436 | "QUE:" + status.getInt(TXLiveConstants.NET_STATUS_CODEC_CACHE)
437 | + "|" + status.getInt(TXLiveConstants.NET_STATUS_CACHE_SIZE)
438 | + "," + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_CACHE_SIZE)
439 | + "," + status.getInt(TXLiveConstants.NET_STATUS_V_DEC_CACHE_SIZE)
440 | + "|" + status.getInt(TXLiveConstants.NET_STATUS_AV_RECV_INTERVAL)
441 | + "," + status.getInt(TXLiveConstants.NET_STATUS_AV_PLAY_INTERVAL)
442 | + "," + String.format("%.1f", status.getFloat(TXLiveConstants.NET_STATUS_AUDIO_PLAY_SPEED)).toString(),
443 | "VRA:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE) + "Kbps",
444 | "SVR:" + status.getString(TXLiveConstants.NET_STATUS_SERVER_IP),
445 | "AUDIO:" + status.getString(TXLiveConstants.NET_STATUS_AUDIO_INFO));
446 | return str;
447 | }
448 | }
449 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.ui;
2 |
3 | import android.Manifest;
4 | import android.app.ListActivity;
5 | import android.content.Intent;
6 | import android.content.pm.PackageManager;
7 | import android.os.Build;
8 | import android.support.annotation.NonNull;
9 | import android.support.v4.app.ActivityCompat;
10 | import android.os.Bundle;
11 | import android.view.View;
12 | import android.widget.ArrayAdapter;
13 | import android.widget.ListView;
14 | import android.widget.Toast;
15 |
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | public class MainActivity extends ListActivity {
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | // setContentView(R.layout.activity_main);
26 |
27 | setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mTitles));
28 | checkPermission();
29 | }
30 |
31 | private String[] mTitles = new String[]{
32 | "推流",
33 | "直播"
34 | };
35 |
36 | private Class[] mActivities = new Class[]{
37 | RTMPActivity.class,
38 | LiveActivity.class,
39 | };
40 |
41 | @Override
42 | protected void onListItemClick(ListView l, View v, int position, long id) {
43 | super.onListItemClick(l, v, position, id);
44 | if (position == 0) {
45 | startActivity(new Intent(this, mActivities[0]));
46 |
47 | } else if (position == 1) {
48 | if (checkPermissionPush()) {
49 | startActivity(new Intent(this, mActivities[1]));
50 | } else {
51 | Toast.makeText(this, "权限不足", Toast.LENGTH_SHORT).show();
52 | }
53 | }
54 | }
55 |
56 | private boolean checkPermissionPush() {
57 | if (Build.VERSION.SDK_INT >= 23) {
58 | List permissions = new ArrayList<>();
59 | if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
60 | permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
61 | }
62 | if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)) {
63 | permissions.add(Manifest.permission.CAMERA);
64 | }
65 | if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)) {
66 | permissions.add(Manifest.permission.RECORD_AUDIO);
67 | }
68 | if (permissions.size() != 0) {
69 | ActivityCompat.requestPermissions(this,
70 | permissions.toArray(new String[0]),
71 | 1);
72 | return false;
73 | }
74 | }
75 |
76 | return true;
77 | }
78 |
79 | private boolean checkPermission() {
80 | if (Build.VERSION.SDK_INT >= 26) {
81 | List permissions = new ArrayList<>();
82 | if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW)) {
83 | permissions.add(Manifest.permission.SYSTEM_ALERT_WINDOW);
84 | }
85 | if (permissions.size() != 0) {
86 | ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), 2);
87 | return false;
88 | }
89 | }
90 | return true;
91 | }
92 |
93 |
94 | @Override
95 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
96 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
97 | switch (requestCode) {
98 | case 1:
99 | for (int ret : grantResults) {
100 | if (ret != PackageManager.PERMISSION_GRANTED) {
101 | return;
102 | }
103 | }
104 | break;
105 | default:
106 | break;
107 | }
108 | }
109 |
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/ui/RTMPActivity.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.ui;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.provider.Settings;
8 | import android.support.annotation.Nullable;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.util.Log;
11 | import android.view.Surface;
12 | import android.view.View;
13 | import android.widget.Button;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import com.tencent.rtmp.ITXLivePushListener;
18 | import com.tencent.rtmp.TXLiveConstants;
19 | import com.tencent.rtmp.TXLivePushConfig;
20 | import com.tencent.rtmp.TXLivePusher;
21 | import com.tencent.rtmp.ui.TXCloudVideoView;
22 | import com.zjp.tencentvideo.R;
23 | import com.zjp.tencentvideo.beautysettings.BeautyDialogFragment;
24 | import com.zjp.tencentvideo.utils.BitmapUtils;
25 | import com.zjp.tencentvideo.utils.TCUtils;
26 |
27 | /**
28 | * Created by zjp on 2018/5/29 14:48.
29 | * 推流
30 | */
31 |
32 | public class RTMPActivity extends AppCompatActivity implements ITXLivePushListener, BeautyDialogFragment.OnBeautyParamsChangeListener, View.OnClickListener {
33 |
34 | private TXCloudVideoView mTxCloudVideoView;
35 | private TXLivePushConfig mLivePushConfig;
36 | private TXLivePusher mLivePusher;
37 | private Button mBtnFaceBeauty, mBtnMsgInput, mBtnCameraChange, mBtnClose, mBtnLinkMic;
38 | private View mRootView;
39 | private TextView mNetBusyTips;
40 |
41 | // private l
42 |
43 |
44 | private static final int VIDEO_SRC_CAMERA = 0;
45 | private static final int VIDEO_SRC_SCREEN = 1;
46 | private int mVideoSrc = VIDEO_SRC_CAMERA;
47 |
48 | boolean mVideoPublish;
49 | private int mNetBusyCount = 0;
50 |
51 | private Handler mMainHandler;
52 |
53 | //美颜管理
54 | BeautyDialogFragment mBeautyDialogFragment;
55 | BeautyDialogFragment.BeautyParams mBeautyParams;
56 |
57 |
58 | @Override
59 | protected void onCreate(@Nullable Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.activity_rtmp);
62 |
63 | // String version = TXLiveBase.getSDKVersionStr();
64 | // Log.d("zjp", "version=" + version);
65 |
66 | initView();
67 | initData();
68 | initListener();
69 | }
70 |
71 | private void initView() {
72 | mMainHandler = new Handler(Looper.getMainLooper());
73 | mTxCloudVideoView = findViewById(R.id.txcloutvideo);
74 | mBtnFaceBeauty = findViewById(R.id.btnFaceBeauty);
75 | mRootView = findViewById(R.id.rootview);
76 | mBtnMsgInput = findViewById(R.id.btn_message_input);
77 | mBtnCameraChange = findViewById(R.id.btnCameraChange);
78 | mBtnClose = findViewById(R.id.btn_close);
79 | mNetBusyTips = findViewById(R.id.netbusy_tv);
80 | mBtnLinkMic = findViewById(R.id.rtmproom_linkmic_btn);
81 |
82 | }
83 |
84 | private void initData() {
85 |
86 | mTxCloudVideoView.setLogMargin(12, 12, 110, 60);
87 | mTxCloudVideoView.showLog(false);
88 |
89 | //推流
90 | mLivePusher = new TXLivePusher(this);
91 |
92 | mLivePushConfig = new TXLivePushConfig();
93 | mLivePusher.setConfig(mLivePushConfig);
94 |
95 | mVideoPublish = startPusherRtmp();
96 |
97 | mBeautyDialogFragment = new BeautyDialogFragment();
98 | mBeautyParams = new BeautyDialogFragment.BeautyParams();
99 | //美颜选择监听
100 | mBeautyDialogFragment.setBeautyParamsListner(mBeautyParams, this);
101 | }
102 |
103 | private void initListener() {
104 | mBtnMsgInput.setOnClickListener(this);
105 | mBtnFaceBeauty.setOnClickListener(this);
106 | mBtnCameraChange.setOnClickListener(this);
107 | mBtnClose.setOnClickListener(this);
108 | mBtnLinkMic.setOnClickListener(this);
109 | }
110 |
111 | /**
112 | * 启动推流
113 | */
114 | private boolean startPusherRtmp() {
115 |
116 | //开启相机
117 | if (mVideoSrc != VIDEO_SRC_SCREEN) {
118 | mTxCloudVideoView.setVisibility(View.VISIBLE);
119 | }
120 |
121 | Bitmap bitmap = BitmapUtils.decodeResource(getResources(), R.mipmap.pause_publish);
122 | //水印
123 | mLivePushConfig.setWatermark(bitmap, 0.02f, 0.05f, 0.2f);
124 | //参数分别是水印图片的 Bitmap、水印位置的 X 轴坐标,水印位置的 Y 轴坐标,水印宽度。后面三个参数取值范围是[0, 1],后面两个参数分别是水印位置的X轴坐标和 Y 轴坐标
125 |
126 | int customModeType = 0;
127 |
128 | // if (isActivityCanRotation()) {
129 | // onActivityRotation();
130 | // }
131 |
132 | mLivePushConfig.setCustomModeType(customModeType);
133 | mLivePusher.setPushListener(this);
134 | mLivePushConfig.setPauseImg(300, 5);
135 | mLivePushConfig.setPauseImg(bitmap);
136 | mLivePushConfig.setPauseFlag(TXLiveConstants.PAUSE_FLAG_PAUSE_VIDEO | TXLiveConstants.PAUSE_FLAG_PAUSE_AUDIO);
137 | if (mVideoSrc != VIDEO_SRC_SCREEN) {
138 | mLivePushConfig.setFrontCamera(true);
139 | mLivePushConfig.setBeautyFilter(5, 3, 2);
140 | mLivePusher.setConfig(mLivePushConfig);
141 | mLivePusher.startCameraPreview(mTxCloudVideoView); // //是将界面元素和 Pusher 对象关联起来,从而能够将手机摄像头采集到的画面渲染到屏幕上。
142 | } else {
143 | mLivePusher.setConfig(mLivePushConfig);
144 | mLivePusher.startScreenCapture();
145 | }
146 |
147 | String rtmpUrl = "rtmp://24649.livepush.myqcloud.com/live/24649_743e7a0df4?bizid=24649&txSecret=980911a90e1d3dbcde9ee86746bc0ee6&txTime=5B1561FF";
148 | mLivePusher.startPusher(rtmpUrl); //告诉 SDK 音视频流要推到哪个推流URL上去
149 | return true;
150 | }
151 |
152 |
153 | /**
154 | * 开始直播的回调
155 | */
156 | @Override
157 | public void onPushEvent(int event, Bundle bundle) {
158 | String msg = bundle.getString(TXLiveConstants.EVT_DESCRIPTION);
159 | Log.d("zjp", "receive event: " + event + ", " + msg);
160 |
161 | //错误还是要明确的报一下
162 | if (event < 0) {
163 | Toast.makeText(getApplicationContext(), bundle.getString(TXLiveConstants.EVT_DESCRIPTION), Toast.LENGTH_SHORT).show();
164 | if (event == TXLiveConstants.PUSH_ERR_OPEN_CAMERA_FAIL || event == TXLiveConstants.PUSH_ERR_OPEN_MIC_FAIL) {
165 | stopPublishRtmp();
166 | }
167 | }
168 |
169 | if (event == TXLiveConstants.PUSH_ERR_NET_DISCONNECT) { //网络断连,且经三次抢救无效,可以放弃治疗,更多重试请自行重启推流
170 | stopPublishRtmp();
171 | } else if (event == TXLiveConstants.PUSH_WARNING_HW_ACCELERATION_FAIL) { //硬编码启动失败,采用软编码
172 | Toast.makeText(getApplicationContext(), bundle.getString(TXLiveConstants.EVT_DESCRIPTION), Toast.LENGTH_SHORT).show();
173 | mLivePushConfig.setHardwareAcceleration(TXLiveConstants.ENCODE_VIDEO_SOFTWARE);
174 | // mBtnHWEncode.setBackgroundResource(R.drawable.quick2);
175 | mLivePusher.setConfig(mLivePushConfig);
176 | // mHWVideoEncode = false;
177 | } else if (event == TXLiveConstants.PUSH_ERR_SCREEN_CAPTURE_UNSURPORT) {
178 | stopPublishRtmp();
179 | } else if (event == TXLiveConstants.PUSH_ERR_SCREEN_CAPTURE_START_FAILED) {
180 | stopPublishRtmp();
181 | } else if (event == TXLiveConstants.PUSH_EVT_CHANGE_RESOLUTION) { //推流动态调整分辨率
182 | Log.d("zjp", "change resolution to " + bundle.getInt(TXLiveConstants.EVT_PARAM2) + ", bitrate to" + bundle.getInt(TXLiveConstants.EVT_PARAM1));
183 | } else if (event == TXLiveConstants.PUSH_EVT_CHANGE_BITRATE) { //推流动态调整码率
184 | Log.d("zjp", "change bitrate to" + bundle.getInt(TXLiveConstants.EVT_PARAM1));
185 | } else if (event == TXLiveConstants.PUSH_WARNING_NET_BUSY) { //当前网络已经非常糟糕
186 | ++mNetBusyCount;
187 | Log.d("zjp", "net busy. count=" + mNetBusyCount);
188 | showNetBusyTips();
189 | } else if (event == TXLiveConstants.PUSH_EVT_START_VIDEO_ENCODER) {
190 | int encType = bundle.getInt(TXLiveConstants.EVT_PARAM1);
191 | // mHWVideoEncode = (encType == 1);
192 | // mBtnHWEncode.getBackground().setAlpha(mHWVideoEncode ? 255 : 100);
193 | }
194 | }
195 |
196 | @Override
197 | public void onNetStatus(Bundle bundle) {
198 | String str = getNetStatusString(bundle);
199 | Log.d("zjp", "Current status, CPU:" + bundle.getString(TXLiveConstants.NET_STATUS_CPU_USAGE) +
200 | ", RES:" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH) + "*" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT) +
201 | ", SPD:" + bundle.getInt(TXLiveConstants.NET_STATUS_NET_SPEED) + "Kbps" +
202 | ", FPS:" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_FPS) +
203 | ", ARA:" + bundle.getInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE) + "Kbps" +
204 | ", VRA:" + bundle.getInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE) + "Kbps");
205 | // if (mLivePusher != null){
206 | // mLivePusher.onLogRecord("[net state]:\n"+str+"\n");
207 | // }
208 | }
209 |
210 | /**
211 | * 关闭推流
212 | */
213 | private void stopPublishRtmp() {
214 | mVideoPublish = false;
215 | mLivePusher.stopBGM();
216 | mLivePusher.stopCameraPreview(true);
217 | mLivePusher.stopScreenCapture();
218 | mLivePusher.setPushListener(null);
219 | mLivePusher.stopPusher();
220 | mTxCloudVideoView.setVisibility(View.GONE);
221 |
222 | if (mLivePushConfig != null) {
223 | mLivePushConfig.setPauseImg(null);
224 | }
225 | }
226 |
227 | protected void onActivityRotation() {
228 | // 自动旋转打开,Activity随手机方向旋转之后,需要改变推流方向
229 | int mobileRotation = this.getWindowManager().getDefaultDisplay().getRotation();
230 | int pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_DOWN;
231 | boolean screenCaptureLandscape = false;
232 | switch (mobileRotation) {
233 | case Surface.ROTATION_0:
234 | pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_DOWN;
235 | break;
236 | case Surface.ROTATION_180:
237 | pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_UP;
238 | break;
239 | case Surface.ROTATION_90:
240 | pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_RIGHT;
241 | screenCaptureLandscape = true;
242 | break;
243 | case Surface.ROTATION_270:
244 | pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_LEFT;
245 | screenCaptureLandscape = true;
246 | break;
247 | default:
248 | break;
249 | }
250 | mLivePusher.setRenderRotation(0); //因为activity也旋转了,本地渲染相对正方向的角度为0。
251 | mLivePushConfig.setHomeOrientation(pushRotation);
252 | if (mLivePusher.isPushing()) {
253 | if (VIDEO_SRC_CAMERA == mVideoSrc) {
254 | mLivePusher.setConfig(mLivePushConfig);
255 | mLivePusher.stopCameraPreview(true);
256 | mLivePusher.startCameraPreview(mTxCloudVideoView);
257 | } else if (VIDEO_SRC_SCREEN == mVideoSrc) {
258 |
259 | mLivePusher.setConfig(mLivePushConfig);
260 | mLivePusher.stopScreenCapture();
261 | mLivePusher.startScreenCapture();
262 | }
263 | }
264 | }
265 |
266 | private void showNetBusyTips() {
267 | if (mNetBusyTips.isShown()) {
268 | return;
269 | }
270 | mNetBusyTips.setVisibility(View.VISIBLE);
271 | mMainHandler.postDelayed(new Runnable() {
272 | @Override
273 | public void run() {
274 | mNetBusyTips.setVisibility(View.GONE);
275 | }
276 | }, 5000);
277 | }
278 |
279 | /**
280 | * 判断Activity是否可旋转。只有在满足以下条件的时候,Activity才是可根据重力感应自动旋转的。
281 | * 系统“自动旋转”设置项打开;
282 | *
283 | * @return false---Activity可根据重力感应自动旋转
284 | */
285 | protected boolean isActivityCanRotation() {
286 | // 判断自动旋转是否打开
287 | int flag = Settings.System.getInt(this.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0);
288 | if (flag == 0) {
289 | return false;
290 | }
291 | return true;
292 | }
293 |
294 | //公用打印辅助函数
295 | protected String getNetStatusString(Bundle status) {
296 | String str = String.format("%-14s %-14s %-12s\n%-8s %-8s %-8s %-8s\n%-14s %-14s %-12s\n%-14s %-14s",
297 | "CPU:" + status.getString(TXLiveConstants.NET_STATUS_CPU_USAGE),
298 | "RES:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH) + "*" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT),
299 | "SPD:" + status.getInt(TXLiveConstants.NET_STATUS_NET_SPEED) + "Kbps",
300 | "JIT:" + status.getInt(TXLiveConstants.NET_STATUS_NET_JITTER),
301 | "FPS:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_FPS),
302 | "GOP:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_GOP) + "s",
303 | "ARA:" + status.getInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE) + "Kbps",
304 | "QUE:" + status.getInt(TXLiveConstants.NET_STATUS_CODEC_CACHE) + "|" + status.getInt(TXLiveConstants.NET_STATUS_CACHE_SIZE),
305 | "DRP:" + status.getInt(TXLiveConstants.NET_STATUS_CODEC_DROP_CNT) + "|" + status.getInt(TXLiveConstants.NET_STATUS_DROP_SIZE),
306 | "VRA:" + status.getInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE) + "Kbps",
307 | "SVR:" + status.getString(TXLiveConstants.NET_STATUS_SERVER_IP),
308 | "AUDIO:" + status.getString(TXLiveConstants.NET_STATUS_AUDIO_INFO));
309 | return str;
310 | }
311 |
312 | /**
313 | * 美颜回调
314 | */
315 | @Override
316 | public void onBeautyParamsChange(BeautyDialogFragment.BeautyParams params, int key) {
317 | switch (key) {
318 | case BeautyDialogFragment.BEAUTYPARAM_BEAUTY:
319 | case BeautyDialogFragment.BEAUTYPARAM_WHITE:
320 | if (mLivePusher != null) {
321 | mLivePusher.setBeautyFilter(params.mBeautyStyle, params.mBeautyProgress, params.mWhiteProgress, params.mRuddyProgress);
322 | }
323 | break;
324 | case BeautyDialogFragment.BEAUTYPARAM_FACE_LIFT:
325 | if (mLivePusher != null) {
326 | mLivePusher.setFaceSlimLevel(params.mFaceLiftProgress);
327 | }
328 | break;
329 | case BeautyDialogFragment.BEAUTYPARAM_BIG_EYE:
330 | if (mLivePusher != null) {
331 | mLivePusher.setEyeScaleLevel(params.mBigEyeProgress);
332 | }
333 | break;
334 | case BeautyDialogFragment.BEAUTYPARAM_FILTER:
335 | if (mLivePusher != null) {
336 | mLivePusher.setFilter(TCUtils.getFilterBitmap(getResources(), params.mFilterIdx));
337 | }
338 | break;
339 | case BeautyDialogFragment.BEAUTYPARAM_MOTION_TMPL:
340 | if (mLivePusher != null) {
341 | mLivePusher.setMotionTmpl(params.mMotionTmplPath);
342 | }
343 | break;
344 | case BeautyDialogFragment.BEAUTYPARAM_GREEN:
345 | if (mLivePusher != null) {
346 | mLivePusher.setGreenScreenFile(TCUtils.getGreenFileName(params.mGreenIdx));
347 | }
348 | break;
349 | default:
350 | break;
351 | }
352 | }
353 |
354 | @Override
355 | public void onClick(View v) {
356 | switch (v.getId()) {
357 |
358 | case R.id.btn_message_input:
359 | break;
360 |
361 | case R.id.btnFaceBeauty:
362 | //美颜
363 | if (mBeautyDialogFragment.isAdded()) {
364 | mBeautyDialogFragment.dismiss();
365 | } else {
366 | mBeautyDialogFragment.show(getSupportFragmentManager(), "");
367 | }
368 | break;
369 |
370 | case R.id.btnCameraChange:
371 | //摄像头切换
372 | mLivePusher.switchCamera();
373 | break;
374 |
375 | case R.id.btn_close:
376 |
377 | //关闭推流
378 | stopPublishRtmp();
379 | finish();
380 | break;
381 |
382 | case R.id.rtmproom_linkmic_btn:
383 | startLinkMic();
384 | break;
385 | }
386 | }
387 |
388 | private void startLinkMic() {
389 | mBtnLinkMic.setEnabled(false);
390 | Toast.makeText(RTMPActivity.this, "等待主播接受......", 2).show();
391 |
392 |
393 | }
394 |
395 | @Override
396 | protected void onResume() {
397 | super.onResume();
398 | if (mTxCloudVideoView != null) {
399 | mTxCloudVideoView.onResume();
400 | }
401 |
402 | if (mVideoPublish && mLivePusher != null && mVideoSrc == VIDEO_SRC_CAMERA) {
403 | mLivePusher.resumePusher();
404 | mLivePusher.resumeBGM();
405 | }
406 | }
407 |
408 |
409 | @Override
410 | public void onStop() {
411 | super.onStop();
412 | if (mTxCloudVideoView != null) {
413 | mTxCloudVideoView.onPause();
414 | }
415 |
416 | if (mVideoPublish && mLivePusher != null && mVideoSrc == VIDEO_SRC_CAMERA) {
417 | mLivePusher.pausePusher();
418 | mLivePusher.pauseBGM();
419 | }
420 | }
421 |
422 | @Override
423 | protected void onDestroy() {
424 | super.onDestroy();
425 | stopPublishRtmp();
426 | if (mTxCloudVideoView != null) {
427 | mTxCloudVideoView.onDestroy();
428 | }
429 | }
430 | }
431 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/utils/BitmapUtils.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.utils;
2 |
3 | import android.content.res.Resources;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.util.TypedValue;
7 |
8 | /**
9 | * @author wapchief
10 | * @date 2018/3/24
11 | */
12 |
13 | public class BitmapUtils {
14 |
15 | public static Bitmap decodeResource(Resources resources, int id) {
16 | TypedValue value = new TypedValue();
17 | resources.openRawResource(id, value);
18 | BitmapFactory.Options opts = new BitmapFactory.Options();
19 | opts.inTargetDensity = value.density;
20 | return BitmapFactory.decodeResource(resources, id, opts);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/utils/TCFrequeControl.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.utils;
2 |
3 | /**
4 | * Created by carolsuo on 2016/9/21.
5 | * 频率控制类,用于控制一定时间内的触发次数不能过多
6 | * 规则为在设定时间内,最开始的nCounts次请求能触发;忽略后面超出的请求,距离上个时间段内首次触发时间超过设定时间后重启下一个时间段逻辑。
7 | */
8 |
9 | public class TCFrequeControl {
10 | private int mCounts = 0; //设定时间内允许触发的次数
11 | private int mSeconds = 0; //设定的时间秒数
12 | private int mCurrentCounts = 0; //当前已经触发的次数
13 | private long mFirstTriggerTime = 0; //当前时间段内首次触发的时间
14 |
15 | public void init(int nCounts, int nSeconds) {
16 | this.mCounts = nCounts;
17 | this.mSeconds = nSeconds;
18 | this.mCurrentCounts = 0;
19 | this.mFirstTriggerTime = 0;
20 | }
21 |
22 | public boolean canTrigger() {
23 | long time = System.currentTimeMillis();
24 |
25 |
26 | //重置首次触发时间和已经触发次数
27 | if (mFirstTriggerTime == 0 || time - mFirstTriggerTime > 1000*mSeconds) {
28 | mFirstTriggerTime = time;
29 | mCurrentCounts = 0;
30 | }
31 |
32 | //已经触发了mCounts次,本次不能触发
33 | if (mCurrentCounts >= mCounts) {
34 | return false;
35 | }
36 |
37 | ++mCurrentCounts;
38 | return true;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/view/TCInputTextMsgDialog.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo.view;
2 |
3 | import android.app.Dialog;
4 | import android.content.Context;
5 | import android.graphics.PorterDuff;
6 | import android.graphics.Rect;
7 | import android.text.InputType;
8 | import android.text.TextUtils;
9 | import android.util.Log;
10 | import android.view.KeyEvent;
11 | import android.view.View;
12 | import android.view.inputmethod.InputMethodManager;
13 | import android.widget.Button;
14 | import android.widget.EditText;
15 | import android.widget.LinearLayout;
16 | import android.widget.RelativeLayout;
17 | import android.widget.TextView;
18 | import android.widget.Toast;
19 |
20 | import com.zjp.tencentvideo.R;
21 |
22 |
23 | /**
24 | * 文本输入框
25 | */
26 | public class TCInputTextMsgDialog extends Dialog {
27 |
28 | public interface OnTextSendListener {
29 |
30 | void onTextSend(String msg, boolean tanmuOpen);
31 | }
32 | private TextView confirmBtn;
33 | private LinearLayout mBarrageArea;
34 | private EditText messageTextView;
35 | private static final String TAG = TCInputTextMsgDialog.class.getSimpleName();
36 | private Context mContext;
37 | private InputMethodManager imm;
38 | private RelativeLayout rlDlg;
39 | private int mLastDiff = 0;
40 | private LinearLayout mConfirmArea;
41 | private OnTextSendListener mOnTextSendListener;
42 | private boolean mDanmuOpen = false;
43 | // private final String reg = "[`~@#$%^&*()-_+=|{}':;,/.<>¥…()—【】‘;:”“’。,、]";
44 | // private Pattern pattern = Pattern.compile(reg);
45 |
46 | public TCInputTextMsgDialog(Context context, int theme) {
47 | super(context, theme);
48 | mContext = context;
49 | setContentView(R.layout.dialog_input_text);
50 |
51 | messageTextView = (EditText) findViewById(R.id.et_input_message);
52 | messageTextView.setInputType(InputType.TYPE_CLASS_TEXT);
53 | //修改下划线颜色
54 | messageTextView.getBackground().setColorFilter(context.getResources().getColor(R.color.transparent), PorterDuff.Mode.CLEAR);
55 |
56 |
57 | confirmBtn = (TextView) findViewById(R.id.confrim_btn);
58 | imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
59 | confirmBtn.setOnClickListener(new View.OnClickListener() {
60 | @Override
61 | public void onClick(View view) {
62 | String msg = messageTextView.getText().toString().trim();
63 | if (!TextUtils.isEmpty(msg)) {
64 |
65 | mOnTextSendListener.onTextSend(msg, mDanmuOpen);
66 | imm.showSoftInput(messageTextView, InputMethodManager.SHOW_FORCED);
67 | imm.hideSoftInputFromWindow(messageTextView.getWindowToken(), 0);
68 | messageTextView.setText("");
69 | dismiss();
70 | } else {
71 | Toast.makeText(mContext, "input can not be empty!", Toast.LENGTH_LONG).show();
72 | }
73 | messageTextView.setText(null);
74 | }
75 | });
76 |
77 | final Button barrageBtn = (Button) findViewById(R.id.barrage_btn);
78 | barrageBtn.setOnClickListener(new View.OnClickListener() {
79 | @Override
80 | public void onClick(View view) {
81 | mDanmuOpen = !mDanmuOpen;
82 | if (mDanmuOpen) {
83 | barrageBtn.setBackgroundResource(R.drawable.barrage_slider_on);
84 | } else {
85 | barrageBtn.setBackgroundResource(R.drawable.barrage_slider_off);
86 | }
87 | }
88 | });
89 |
90 | mBarrageArea = (LinearLayout) findViewById(R.id.barrage_area);
91 | mBarrageArea.setOnClickListener(new View.OnClickListener() {
92 | @Override
93 | public void onClick(View v) {
94 | mDanmuOpen = !mDanmuOpen;
95 | if (mDanmuOpen) {
96 | barrageBtn.setBackgroundResource(R.drawable.barrage_slider_on);
97 | } else {
98 | barrageBtn.setBackgroundResource(R.drawable.barrage_slider_off);
99 | }
100 | }
101 | });
102 |
103 | messageTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
104 | @Override
105 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
106 | switch (actionId) {
107 | case KeyEvent.KEYCODE_ENDCALL:
108 | case KeyEvent.KEYCODE_ENTER:
109 | if (messageTextView.getText().length() > 0) {
110 | // mOnTextSendListener.onTextSend("" + messageTextView.getText(), mDanmuOpen);
111 | //sendText("" + messageTextView.getText());
112 | //imm.showSoftInput(messageTextView, InputMethodManager.SHOW_FORCED);
113 | imm.hideSoftInputFromWindow(messageTextView.getWindowToken(), 0);
114 | // messageTextView.setText("");
115 | dismiss();
116 | } else {
117 | Toast.makeText(mContext, "input can not be empty!", Toast.LENGTH_LONG).show();
118 | }
119 | return true;
120 | case KeyEvent.KEYCODE_BACK:
121 | dismiss();
122 | return false;
123 | default:
124 | return false;
125 | }
126 | }
127 | });
128 |
129 | mConfirmArea = (LinearLayout) findViewById(R.id.confirm_area);
130 | mConfirmArea.setOnClickListener(new View.OnClickListener() {
131 | @Override
132 | public void onClick(View v) {
133 | String msg = messageTextView.getText().toString().trim();
134 | if (!TextUtils.isEmpty(msg)) {
135 |
136 | mOnTextSendListener.onTextSend(msg, mDanmuOpen);
137 | imm.showSoftInput(messageTextView, InputMethodManager.SHOW_FORCED);
138 | imm.hideSoftInputFromWindow(messageTextView.getWindowToken(), 0);
139 | messageTextView.setText("");
140 | dismiss();
141 | } else {
142 | Toast.makeText(mContext, "input can not be empty!", Toast.LENGTH_LONG).show();
143 | }
144 | messageTextView.setText(null);
145 | }
146 | });
147 |
148 | messageTextView.setOnKeyListener(new View.OnKeyListener() {
149 | @Override
150 | public boolean onKey(View view, int i, KeyEvent keyEvent) {
151 | Log.d("My test", "onKey " + keyEvent.getCharacters());
152 | return false;
153 | }
154 | });
155 |
156 | rlDlg = (RelativeLayout) findViewById(R.id.rl_outside_view);
157 | rlDlg.setOnClickListener(new View.OnClickListener() {
158 | @Override
159 | public void onClick(View v) {
160 | if (v.getId() != R.id.rl_inputdlg_view) {
161 |
162 | dismiss();
163 | }
164 | }
165 | });
166 |
167 | final LinearLayout rldlgview = (LinearLayout) findViewById(R.id.rl_inputdlg_view);
168 |
169 | rldlgview.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
170 | @Override
171 | public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
172 | Rect r = new Rect();
173 | //获取当前界面可视部分
174 | getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
175 | //获取屏幕的高度
176 | int screenHeight = getWindow().getDecorView().getRootView().getHeight();
177 | //此处就是用来获取键盘的高度的, 在键盘没有弹出的时候 此高度为0 键盘弹出的时候为一个正数
178 | int heightDifference = screenHeight - r.bottom;
179 |
180 | if (heightDifference <= 0 && mLastDiff > 0){
181 | //imm.hideSoftInputFromWindow(messageTextView.getWindowToken(), 0);
182 | dismiss();
183 | }
184 | mLastDiff = heightDifference;
185 | }
186 | });
187 | rldlgview.setOnClickListener(new View.OnClickListener() {
188 | @Override
189 | public void onClick(View v) {
190 | imm.hideSoftInputFromWindow(messageTextView.getWindowToken(), 0);
191 | dismiss();
192 | }
193 | });
194 | }
195 |
196 | public void setmOnTextSendListener(OnTextSendListener onTextSendListener) {
197 | this.mOnTextSendListener = onTextSendListener;
198 | }
199 |
200 | @Override
201 | public void dismiss() {
202 | super.dismiss();
203 | //dismiss之前重置mLastDiff值避免下次无法打开
204 | mLastDiff = 0;
205 | }
206 |
207 | @Override
208 | public void show() {
209 | super.show();
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/view/like/TCAbstractPathAnimator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 tyrantgit
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zjp.tencentvideo.view.like;
17 |
18 | import android.content.res.Resources;
19 | import android.content.res.TypedArray;
20 | import android.graphics.Path;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 |
24 | import com.zjp.tencentvideo.R;
25 |
26 | import java.util.Random;
27 | import java.util.concurrent.atomic.AtomicInteger;
28 |
29 |
30 | /**
31 | * 飘心路径
32 | */
33 | public abstract class TCAbstractPathAnimator {
34 | private final Random mRandom;
35 | protected final Config mConfig;
36 |
37 |
38 | public TCAbstractPathAnimator(Config config) {
39 | mConfig = config;
40 | mRandom = new Random();
41 | }
42 |
43 | public float randomRotation() {
44 | return mRandom.nextFloat() * 28.6F - 14.3F;
45 | }
46 |
47 | public Path createPath(AtomicInteger counter, View view, int factor) {
48 | Random r = mRandom;
49 | int x = r.nextInt(mConfig.xRand);
50 | int x2 = r.nextInt(mConfig.xRand);
51 | int y = view.getHeight() - mConfig.initY;
52 | int y2 = counter.intValue() * 15 + mConfig.animLength * factor + r.nextInt(mConfig.animLengthRand);
53 | factor = y2 / mConfig.bezierFactor;
54 | x = mConfig.xPointFactor + x;
55 | x2 = mConfig.xPointFactor + x2;
56 | int y3 = y - y2;
57 | y2 = y - y2 / 2;
58 | Path p = new Path();
59 | p.moveTo(mConfig.initX, y);
60 | p.cubicTo(mConfig.initX, y - factor, x, y2 + factor, x, y2);
61 | p.moveTo(x, y2);
62 | p.cubicTo(x, y2 - factor, x2, y3 + factor, x2, y3);
63 | return p;
64 | }
65 |
66 | public abstract void start(View child, ViewGroup parent);
67 |
68 | public static class Config {
69 | public int initX;
70 | public int initY;
71 | public int xRand;
72 | public int animLengthRand;
73 | public int bezierFactor;
74 | public int xPointFactor;
75 | public int animLength;
76 | public int heartWidth;
77 | public int heartHeight;
78 | public int animDuration;
79 |
80 | static public Config fromTypeArray(TypedArray typedArray, float x, float y, int pointx, int heartWidth, int heartHeight) {
81 | Config config = new Config();
82 | Resources res = typedArray.getResources();
83 | config.initX = (int) typedArray.getDimension(R.styleable.HeartLayout_initX,
84 | x);
85 | config.initY = (int) typedArray.getDimension(R.styleable.HeartLayout_initY,
86 | y);
87 | config.xRand = (int) typedArray.getDimension(R.styleable.HeartLayout_xRand,
88 | res.getDimensionPixelOffset(R.dimen.heart_anim_bezier_x_rand));
89 | config.animLength = (int) typedArray.getDimension(R.styleable.HeartLayout_animLength,
90 | res.getDimensionPixelOffset(R.dimen.heart_anim_length));//动画长度
91 | config.animLengthRand = (int) typedArray.getDimension(R.styleable.HeartLayout_animLengthRand,
92 | res.getDimensionPixelOffset(R.dimen.heart_anim_length_rand));
93 | config.bezierFactor = typedArray.getInteger(R.styleable.HeartLayout_bezierFactor,
94 | res.getInteger(R.integer.heart_anim_bezier_factor));
95 | config.xPointFactor = pointx;
96 | // config.heartWidth = (int) typedArray.getDimension(R.styleable.HeartLayout_heart_width,
97 | // res.getDimensionPixelOffset(R.dimen.heart_size_width));//动画图片宽度
98 | // config.heartHeight = (int) typedArray.getDimension(R.styleable.HeartLayout_heart_height,
99 | // res.getDimensionPixelOffset(R.dimen.heart_size_height));//动画图片高度
100 | config.heartWidth = heartWidth;
101 | config.heartHeight = heartHeight;
102 | config.animDuration = typedArray.getInteger(R.styleable.HeartLayout_anim_duration,
103 | res.getInteger(R.integer.anim_duration));//持续期
104 | return config;
105 | }
106 |
107 |
108 | }
109 |
110 |
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/view/like/TCHeartLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 tyrantgit
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zjp.tencentvideo.view.like;
17 |
18 | import android.content.Context;
19 | import android.content.res.TypedArray;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.graphics.drawable.BitmapDrawable;
23 | import android.graphics.drawable.Drawable;
24 | import android.util.AttributeSet;
25 | import android.view.LayoutInflater;
26 | import android.widget.RelativeLayout;
27 |
28 |
29 | import com.zjp.tencentvideo.R;
30 |
31 | import java.util.Random;
32 |
33 |
34 | /**
35 | * 飘心动画界面布局类
36 | * 通过动画控制每个心形界面的显示
37 | * TCPathAnimator 控制显示路径
38 | * TCHeartView 单个心形界面
39 | */
40 | public class TCHeartLayout extends RelativeLayout {
41 |
42 | private TCAbstractPathAnimator mAnimator;
43 | private int defStyleAttr = 0;
44 |
45 | private int textHight;
46 | private int dHeight;
47 | private int dWidth;
48 | private int initX;
49 | private int pointx;
50 |
51 | public TCHeartLayout(Context context, AttributeSet attrs) {
52 | super(context, attrs);
53 | findViewById(context);
54 | initHeartDrawable();
55 | init(attrs, defStyleAttr);
56 | }
57 |
58 | private void findViewById(Context context) {
59 | LayoutInflater.from(context).inflate(R.layout.layout_periscope, this);
60 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_like_png);
61 | dHeight = bitmap.getWidth();
62 | dWidth = bitmap.getHeight();
63 | textHight = sp2px(getContext(), 20) + dHeight / 2;
64 |
65 | pointx = dWidth;//随机上浮方向的x坐标
66 |
67 | bitmap.recycle();
68 | }
69 |
70 | private static int sp2px(Context context, float spValue) {
71 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
72 | return (int) (spValue * fontScale + 0.5f);
73 | }
74 |
75 |
76 | private void init(AttributeSet attrs, int defStyleAttr) {
77 | final TypedArray a = getContext().obtainStyledAttributes(
78 | attrs, R.styleable.HeartLayout, defStyleAttr, 0);
79 |
80 | //todo:获取确切值
81 | initX = 30;
82 | if (pointx <= initX && pointx >= 0) {
83 | pointx -= 10;
84 | } else if (pointx >= -initX && pointx <= 0) {
85 | pointx += 10;
86 | } else {
87 |
88 | pointx = initX;
89 | }
90 |
91 | mAnimator = new TCPathAnimator(
92 | TCAbstractPathAnimator.Config.fromTypeArray(a, initX, textHight, pointx, dWidth, dHeight));
93 | a.recycle();
94 | }
95 |
96 | @Override
97 | public void clearAnimation() {
98 | for (int i = 0; i < getChildCount(); i++) {
99 | getChildAt(i).clearAnimation();
100 | }
101 | removeAllViews();
102 | }
103 | public void resourceLoad(){
104 | mHearts = new Bitmap[drawableIds.length];
105 | mHeartsDrawable = new BitmapDrawable[drawableIds.length];
106 | for (int i =0;i < drawableIds.length;i++){
107 | mHearts[i] = BitmapFactory.decodeResource(getResources(), drawableIds[i]);
108 | mHeartsDrawable[i] = new BitmapDrawable(getResources(), mHearts[i]);
109 | }
110 | }
111 | private static int[] drawableIds = new int[]{R.drawable.heart0, R.drawable.heart1, R.drawable.heart2, R.drawable.heart3, R.drawable.heart4, R.drawable.heart5, R.drawable.heart6, R.drawable.heart7, R.drawable.heart8,};
112 | private Random mRandom = new Random();
113 | private static Drawable[] sDrawables;
114 | private Bitmap[] mHearts;
115 | private BitmapDrawable[] mHeartsDrawable;
116 | private void initHeartDrawable() {
117 | int size = drawableIds.length;
118 | sDrawables = new Drawable[size];
119 | for (int i = 0 ; i < size; i++) {
120 | sDrawables[i] = getResources().getDrawable(drawableIds[i]);
121 | }
122 | resourceLoad();
123 | }
124 |
125 | public void addFavor() {
126 | TCHeartView heartView = new TCHeartView(getContext());
127 | heartView.setDrawable(mHeartsDrawable[mRandom.nextInt(8)]);
128 | // heartView.setImageDrawable(sDrawables[random.nextInt(8)]);
129 | // init(attrs, defStyleAttr);
130 | mAnimator.start(heartView, this);
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/view/like/TCHeartView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 tyrantgit
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zjp.tencentvideo.view.like;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.graphics.Canvas;
23 | import android.graphics.Paint;
24 | import android.graphics.PorterDuff;
25 | import android.graphics.PorterDuffColorFilter;
26 | import android.graphics.drawable.BitmapDrawable;
27 | import android.util.AttributeSet;
28 | import android.widget.ImageView;
29 |
30 | import com.zjp.tencentvideo.R;
31 |
32 |
33 | /**
34 | * 飘心动画心形界面类
35 | * 一个TCHeartView代表一个心形,由heart.png组成
36 | */
37 | @SuppressLint("AppCompatCustomView")
38 | public class TCHeartView extends ImageView {
39 |
40 | private static final Paint sPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
41 | private int mHeartResId = R.drawable.heart0;
42 | private int mHeartBorderResId = R.drawable.heart1;
43 | private static Bitmap sHeart;
44 | private static Bitmap sHeartBorder;
45 | private static final Canvas sCanvas = new Canvas();
46 |
47 | public TCHeartView(Context context, AttributeSet attrs) {
48 | super(context, attrs);
49 | }
50 |
51 | public TCHeartView(Context context, AttributeSet attrs, int defStyleAttr) {
52 | super(context, attrs, defStyleAttr);
53 | }
54 |
55 | public TCHeartView(Context context) {
56 | super(context);
57 | }
58 |
59 | public void setDrawable(BitmapDrawable bitmap) {
60 | setImageDrawable(bitmap);
61 | }
62 |
63 | public void setColor(int color) {
64 | Bitmap heart = createHeart(color);
65 | setImageDrawable(new BitmapDrawable(getResources(), heart));
66 | }
67 |
68 | public void setColorAndDrawables(int color, int heartResId, int heartBorderResId) {
69 | if (heartResId != mHeartResId) {
70 | sHeart = null;
71 | }
72 | if (heartBorderResId != mHeartBorderResId) {
73 | sHeartBorder = null;
74 | }
75 | mHeartResId = heartResId;
76 | mHeartBorderResId = heartBorderResId;
77 | setColor(color);
78 | }
79 |
80 | public Bitmap createHeart(int color) {
81 | if (sHeart == null) {
82 | sHeart = BitmapFactory.decodeResource(getResources(), mHeartResId);
83 | }
84 | if (sHeartBorder == null) {
85 | sHeartBorder = BitmapFactory.decodeResource(getResources(), mHeartBorderResId);
86 | }
87 | Bitmap heart = sHeart;
88 | Bitmap heartBorder = sHeartBorder;
89 | Bitmap bm = createBitmapSafely(heartBorder.getWidth(), heartBorder.getHeight());
90 | if (bm == null) {
91 | return null;
92 | }
93 | Canvas canvas = sCanvas;
94 | canvas.setBitmap(bm);
95 | Paint p = sPaint;
96 | canvas.drawBitmap(heartBorder, 0, 0, p);
97 | p.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
98 | float dx = (heartBorder.getWidth() - heart.getWidth()) / 2f;
99 | float dy = (heartBorder.getHeight() - heart.getHeight()) / 2f;
100 | canvas.drawBitmap(heart, dx, dy, p);
101 | p.setColorFilter(null);
102 | canvas.setBitmap(null);
103 | return bm;
104 | }
105 |
106 | private static Bitmap createBitmapSafely(int width, int height) {
107 | try {
108 | return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
109 | } catch (OutOfMemoryError error) {
110 | error.printStackTrace();
111 | }
112 | return null;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjp/tencentvideo/view/like/TCPathAnimator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 tyrantgit
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zjp.tencentvideo.view.like;
17 |
18 | import android.graphics.Matrix;
19 | import android.graphics.Path;
20 | import android.graphics.PathMeasure;
21 | import android.os.Handler;
22 | import android.os.Looper;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.view.animation.Animation;
26 | import android.view.animation.LinearInterpolator;
27 | import android.view.animation.Transformation;
28 |
29 | import java.util.HashMap;
30 | import java.util.Random;
31 | import java.util.concurrent.atomic.AtomicInteger;
32 |
33 | /**
34 | * 飘心路径动画器
35 | */
36 | public class TCPathAnimator extends TCAbstractPathAnimator {
37 | private final AtomicInteger mCounter = new AtomicInteger(0);
38 | private Handler mHandler;
39 |
40 | //路径的缓存
41 | private final static int MAX_PATH_COUNTS = 10; //最多生成的路径数目
42 | private int mCurrentPathCounts = 0; //已经生成的路径数目
43 | private HashMap mPathVec = null; //已经生成的路径缓存
44 | private final Random mRandom; //随机数
45 |
46 | public TCPathAnimator(Config config) {
47 | super(config);
48 | mHandler = new Handler(Looper.getMainLooper());
49 | mPathVec = new HashMap<>();
50 | mRandom = new Random();
51 | }
52 |
53 | @Override
54 | public void start(final View child, final ViewGroup parent) {
55 | parent.addView(child, new ViewGroup.LayoutParams(mConfig.heartWidth, mConfig.heartHeight));
56 |
57 | Path path;
58 | ++mCurrentPathCounts;
59 |
60 | //如果已经生成的路径数目超过最大设定,就从路径缓存中随机取一个路径用于绘制,否则新生成一个
61 | if (mCurrentPathCounts > MAX_PATH_COUNTS) {
62 | path = mPathVec.get(Math.abs(mRandom.nextInt()%MAX_PATH_COUNTS) + 1);
63 | } else {
64 | path = createPath(mCounter, parent, 2);
65 | mPathVec.put(mCurrentPathCounts, path);
66 | }
67 |
68 | FloatAnimation anim = new FloatAnimation(path, randomRotation(), parent, child);
69 | anim.setDuration(mConfig.animDuration);
70 | anim.setInterpolator(new LinearInterpolator());
71 | anim.setAnimationListener(new Animation.AnimationListener() {
72 | @Override
73 | public void onAnimationEnd(Animation animation) {
74 | mHandler.post(new Runnable() {
75 | @Override
76 | public void run() {
77 | parent.removeView(child);
78 | }
79 | });
80 | mCounter.decrementAndGet();
81 | }
82 |
83 | @Override
84 | public void onAnimationRepeat(Animation animation) {
85 |
86 | }
87 |
88 | @Override
89 | public void onAnimationStart(Animation animation) {
90 | mCounter.incrementAndGet();
91 | }
92 | });
93 | child.startAnimation(anim);
94 | }
95 |
96 | static class FloatAnimation extends Animation {
97 | private PathMeasure mPm;
98 | private View mView;
99 | private float mDistance;
100 | private float mRotation;
101 |
102 | public FloatAnimation(Path path, float rotation, View parent, View child) {
103 | mPm = new PathMeasure(path, false);
104 | mDistance = mPm.getLength();
105 | mView = child;
106 | mRotation = rotation;
107 | parent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
108 | }
109 |
110 | @Override
111 | protected void applyTransformation(float factor, Transformation transformation) {
112 | Matrix matrix = transformation.getMatrix();
113 | mPm.getMatrix(mDistance * factor, matrix, PathMeasure.POSITION_MATRIX_FLAG);
114 | mView.setRotation(mRotation * factor);
115 | float scale = 1F;
116 | if (3000.0F * factor < 200.0F) {
117 | scale = scale(factor, 0.0D, 0.06666667014360428D, 0.20000000298023224D, 1.100000023841858D);
118 | } else if (3000.0F * factor < 300.0F) {
119 | scale = scale(factor, 0.06666667014360428D, 0.10000000149011612D, 1.100000023841858D, 1.0D);
120 | }
121 | mView.setScaleX(scale);
122 | mView.setScaleY(scale);
123 | transformation.setAlpha(1.0F - factor);
124 | }
125 | }
126 |
127 | private static float scale(double a, double b, double c, double d, double e) {
128 | return (float) ((a - b) / (c - b) * (e - d) + d);
129 | }
130 | }
131 |
132 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/load_progress_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/again.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/again.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/barrage_slider_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/barrage_slider_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/barrage_slider_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/barrage_slider_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/beautiful.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/beautiful.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/beautiful_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/beautiful_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/beauty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/beauty.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/btn_back_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/btn_back_gray.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/camera_change.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/camera_change.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/face.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/face.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_beauty_png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/icon_beauty_png.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_like_png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/icon_like_png.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_log_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/icon_log_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_message_png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/icon_message_png.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_share_png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/icon_share_png.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_switch_camera_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/icon_switch_camera_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/linkmic_on_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/linkmic_on_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/loading_circle_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/loading_circle_progress.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/play_seekbar_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/play_seekbar_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/text_accent_gray_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xhdpi/video.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/drawable_face_beauty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/drawable_face_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/drawable_face_green.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/drawable_face_move.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fennen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/fennen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_fennen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_fennen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_huaijiu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_huaijiu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_landiao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_landiao.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_langman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_langman.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_qingliang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_qingliang.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_qingxin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_qingxin.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_rixi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_rixi.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_weimei.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_weimei.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/filter_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/filter_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/greens.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/greens.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/greens_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/greens_1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/greens_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/greens_2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/greens_no.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/greens_no.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/greens_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/greens_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/greens_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/greens_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart0.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart10.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart11.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart4.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart5.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart6.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart7.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart8.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/heart9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/heart9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/huaijiu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/huaijiu.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/landiao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/landiao.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/landscape.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/langman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/langman.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/linkmic_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/linkmic_start.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/liveshow_item_dot.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/move.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/move.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/move_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/move_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/orginal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/orginal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/play_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/play_pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/play_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/play_start.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/portrait.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/progress_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/progress_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/progress_front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/progress_front.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/progress_primary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/progress_primary.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/qingliang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/qingliang.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/qingxin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/qingxin.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/rixi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/rixi.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/start_record.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/start_record.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/weimei.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable-xxhdpi/weimei.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_send_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_seekbar_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/drawable/progress_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pusher_info_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/record_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
8 |
9 |
10 | -
13 |
14 |
15 |
16 | -
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seekbar_progress_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | -
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_live.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
19 |
20 |
27 |
28 |
39 |
40 |
46 |
47 |
51 |
52 |
60 |
61 |
62 |
66 |
67 |
73 |
74 |
82 |
83 |
89 |
90 |
94 |
95 |
99 |
100 |
106 |
107 |
108 |
112 |
113 |
120 |
121 |
122 |
123 |
128 |
129 |
135 |
136 |
137 |
141 |
142 |
148 |
149 |
150 |
154 |
155 |
161 |
162 |
163 |
167 |
168 |
174 |
175 |
176 |
180 |
181 |
187 |
188 |
189 |
190 |
194 |
195 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
221 |
222 |
223 |
230 |
231 |
242 |
243 |
249 |
250 |
254 |
255 |
259 |
260 |
264 |
265 |
266 |
273 |
274 |
281 |
282 |
290 |
291 |
292 |
293 |
294 |
299 |
300 |
307 |
308 |
309 |
310 |
315 |
316 |
323 |
324 |
325 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_rtmp.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
20 |
21 |
27 |
28 |
33 |
34 |
41 |
42 |
48 |
49 |
56 |
57 |
63 |
64 |
65 |
66 |
69 |
70 |
76 |
77 |
83 |
84 |
94 |
95 |
96 |
104 |
105 |
106 |
118 |
119 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/beauty_pannel.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
33 |
41 |
42 |
43 |
49 |
50 |
59 |
60 |
61 |
67 |
68 |
74 |
75 |
82 |
83 |
89 |
90 |
91 |
92 |
99 |
100 |
107 |
108 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_input_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
24 |
31 |
32 |
33 |
40 |
41 |
55 |
56 |
63 |
64 |
69 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/filter_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_beauty_area.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
23 |
29 |
30 |
37 |
38 |
43 |
44 |
56 |
57 |
58 |
65 |
66 |
71 |
72 |
84 |
85 |
86 |
87 |
88 |
94 |
95 |
102 |
103 |
108 |
109 |
122 |
123 |
124 |
131 |
132 |
137 |
138 |
151 |
152 |
153 |
154 |
155 |
164 |
165 |
171 |
172 |
173 |
182 |
183 |
189 |
190 |
191 |
195 |
196 |
197 |
201 |
202 |
206 |
207 |
221 |
222 |
236 |
237 |
251 |
252 |
266 |
267 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/green_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_live_pusher_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
21 |
34 |
35 |
45 |
46 |
56 |
57 |
58 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_loading_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_periscope.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
31 |
41 |
52 |
53 |
64 |
65 |
79 |
80 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/pause_publish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xhdpi/pause_publish.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #FFFFFF
8 | #000000
9 | #D8D8D8
10 | #00000000
11 | #FF3333
12 | #FFFFFF
13 | #44777777
14 | #b4ffffff
15 | #777777
16 | #FFFFFF
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 35dp
4 |
5 |
6 | 50.0dp
7 | 50.0dp
8 | 25.0dp
9 | 100.0dp
10 | 350.0dp
11 | 30.0dp
12 |
13 | 27.3dp
14 | 32.5dp
15 |
16 |
17 | 14sp
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 6
5 | 1000
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TencentVideoTest
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
19 |
20 |
26 |
27 |
31 |
32 |
33 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zjp/tencentvideo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.zjp.tencentvideo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | flatDir {
23 | dirs 'libs'
24 | }
25 | maven {
26 | url 'https://jitpack.io'
27 | }
28 | }
29 | }
30 |
31 | task clean(type: Delete) {
32 | delete rootProject.buildDir
33 | }
34 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jsonjia/TencentVideoTest/5fc0be40c243aaff6e7f0c652c37c70c31db75ca/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed May 23 15:57:46 CST 2018
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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------