集成完直播后提交代码
2
LiveCommon/live_commonbiz/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/release
|
||||
75
LiveCommon/live_commonbiz/build.gradle
Normal file
@@ -0,0 +1,75 @@
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
ext.MTL_buildId = getEnvValue("MUPP_BUILD_ID", 'localbuild')
|
||||
ext.MTL_buildTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())
|
||||
// special configurations, only used for test.
|
||||
ext.Interactive_AppID = getEnvValue("INTERACTIVE_APP_ID", '')
|
||||
ext.Interactive_AppKey = getEnvValue("INTERACTIVE_APP_KEY", '')
|
||||
ext.Interactive_PlayDomain = getEnvValue("INTERACTIVE_PLAY_DOMAIN", '')
|
||||
ext.isAllInOne = allInOne
|
||||
|
||||
String getEnvValue(key, defValue) {
|
||||
def val = System.getProperty(key)
|
||||
if (null != val) {
|
||||
return val
|
||||
}
|
||||
val = System.getenv(key)
|
||||
if (null != val) {
|
||||
return val
|
||||
}
|
||||
return defValue
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdkVersion
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion androidMinSdkVersion
|
||||
targetSdkVersion androidTargetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
|
||||
Properties properties = new Properties()
|
||||
if (project.rootProject.file('local.properties').canRead()) {
|
||||
properties.load(project.rootProject.file("local.properties").newDataInputStream())
|
||||
}
|
||||
resValue "string", "test_push_url", properties.getProperty("push.url", "")
|
||||
resValue "string", "test_pull_url", properties.getProperty("pull.url", "")
|
||||
resValue "string", "interactive_appid", properties.getProperty("interactive.appid", "")
|
||||
resValue "string", "interactive_appkey", properties.getProperty("interactive.appkey", "")
|
||||
resValue "string", "interactive_push_domain", properties.getProperty("interactive.push.domain", "")
|
||||
resValue "string", "interactive_play_domain", properties.getProperty("interactive.play.domain", "")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
all {
|
||||
buildConfigField "String", "MTL_BUILD_ID", "\"${MTL_buildId}\""
|
||||
buildConfigField "String", "MTL_BUILD_TIMESTAMP", "\"${MTL_buildTimestamp}\""
|
||||
buildConfigField "String", "INTERACTIVE_APP_ID", "\"${Interactive_AppID}\""
|
||||
buildConfigField "String", "INTERACTIVE_APP_KEY", "\"${Interactive_AppKey}\""
|
||||
buildConfigField "String", "INTERACTIVE_PLAY_DOMAIN", "\"${Interactive_PlayDomain}\""
|
||||
buildConfigField "Boolean", "MTL_BUILD_FOR_AIO", "${isAllInOne}"
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation externalAndroidDesign
|
||||
implementation 'commons-net:commons-net:3.8.0'
|
||||
api project(':LiveCommon:live_commonui')
|
||||
}
|
||||
0
LiveCommon/live_commonbiz/consumer-rules.pro
Normal file
22
LiveCommon/live_commonbiz/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.alivc.live.commonbiz">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="com.alivc.live.commonbiz.backdoor.BackDoorActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:host="backdoor"
|
||||
android:scheme="livepush" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,216 @@
|
||||
package com.alivc.live.commonbiz;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @note 该类为读取本地音视频流的实现类,用于外部音视频推流
|
||||
* 注意:为了适配本地不同格式的音视频流,需要传入对应的profiles才能正常播放
|
||||
* 如:当前项目中,capture0.yuv为720p,请注意调节demo配置页中的分辨率为720p
|
||||
*/
|
||||
public class LocalStreamReader {
|
||||
|
||||
private static final String TAG = "LocalStreamReader";
|
||||
|
||||
private boolean videoThreadOn = false;
|
||||
private boolean audioThreadOn = false;
|
||||
private int videoWidth;
|
||||
private int videoHeight;
|
||||
private int videoStride;
|
||||
private int videoSize;
|
||||
private int videoRotation;
|
||||
private int audioSampleRate;
|
||||
private int audioChannel;
|
||||
private int audioBufferSize;
|
||||
|
||||
public static final class Builder {
|
||||
private final LocalStreamReader localStreamReader = new LocalStreamReader();
|
||||
|
||||
public Builder setVideoWith(int videoWith) {
|
||||
localStreamReader.videoWidth = videoWith;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVideoHeight(int videoHeight) {
|
||||
localStreamReader.videoHeight = videoHeight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVideoSize(int videoSize) {
|
||||
localStreamReader.videoSize = videoSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVideoStride(int videoStride) {
|
||||
localStreamReader.videoStride = videoStride;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVideoRotation(int videoRotation) {
|
||||
localStreamReader.videoRotation = videoRotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAudioSampleRate(int audioSampleRate) {
|
||||
localStreamReader.audioSampleRate = audioSampleRate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAudioChannel(int audioChannel) {
|
||||
localStreamReader.audioChannel = audioChannel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAudioBufferSize(int audioBufferSize) {
|
||||
localStreamReader.audioBufferSize = audioBufferSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LocalStreamReader build() {
|
||||
return localStreamReader;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void readYUVData(File f, ReadYUVFileListener listener) {
|
||||
new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
|
||||
private AtomicInteger atoInteger = new AtomicInteger(0);
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setName("LivePushActivity-readYUV-Thread" + atoInteger.getAndIncrement());
|
||||
return t;
|
||||
}
|
||||
}).execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
videoThreadOn = true;
|
||||
InputStream myInput;
|
||||
try {
|
||||
myInput = new FileInputStream(f);
|
||||
byte[] buffer = new byte[videoSize];
|
||||
int length = myInput.read(buffer);
|
||||
//发数据
|
||||
while (length > 0 && videoThreadOn) {
|
||||
long pts = System.currentTimeMillis() * 1000;
|
||||
listener.onVideoStreamData(buffer, pts, videoWidth, videoHeight, videoStride, videoSize, videoRotation);
|
||||
try {
|
||||
Thread.sleep(40);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//发数据
|
||||
length = myInput.read(buffer);
|
||||
if (length <= 0) {
|
||||
myInput.close();
|
||||
myInput = new FileInputStream(f);
|
||||
length = myInput.read(buffer);
|
||||
}
|
||||
}
|
||||
myInput.close();
|
||||
videoThreadOn = false;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void readPCMData(File f, ReadPCMFileListener listener) {
|
||||
new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
|
||||
private AtomicInteger atoInteger = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setName("LivePushActivity-readPCM-Thread" + atoInteger.getAndIncrement());
|
||||
return t;
|
||||
}
|
||||
}).execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
audioThreadOn = true;
|
||||
int allSended = 0;
|
||||
int sizePerSecond = audioSampleRate * 2;
|
||||
InputStream myInput;
|
||||
long startPts = System.nanoTime() / 1000;
|
||||
try {
|
||||
myInput = new FileInputStream(f);
|
||||
byte[] buffer = new byte[audioBufferSize];
|
||||
int length = myInput.read(buffer, 0, audioBufferSize);
|
||||
if (audioSampleRate <= 0) {
|
||||
Log.e(TAG, "audio sample rate error cause return: " + audioSampleRate);
|
||||
return;
|
||||
}
|
||||
double sleep_time = 1000 / (audioSampleRate / 1000);
|
||||
while (length > 0 && audioThreadOn) {
|
||||
long start = System.nanoTime();
|
||||
long pts = System.currentTimeMillis() * 1000;
|
||||
listener.onAudioStreamData(buffer, length, pts, audioSampleRate, audioChannel);
|
||||
allSended += length;
|
||||
if ((allSended * 1000000L / sizePerSecond - 50000) > (pts - startPts)) {
|
||||
try {
|
||||
Thread.sleep(45);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
length = myInput.read(buffer);
|
||||
if (length < audioBufferSize) {
|
||||
myInput.close();
|
||||
myInput = new FileInputStream(f);
|
||||
length = myInput.read(buffer);
|
||||
}
|
||||
long end = System.nanoTime();
|
||||
try {
|
||||
long real_sleep_time = (long) (sleep_time - (end - start) / 1000 / 1000);
|
||||
if (real_sleep_time > 0) {
|
||||
Thread.sleep(real_sleep_time);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
myInput.close();
|
||||
audioThreadOn = false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "audio IOException: " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void stopYUV() {
|
||||
videoThreadOn = false;
|
||||
}
|
||||
|
||||
public void stopPcm() {
|
||||
audioThreadOn = false;
|
||||
}
|
||||
|
||||
public interface ReadYUVFileListener {
|
||||
void onVideoStreamData(byte[] buffer, long pts, int videoWidth, int videoHeight, int videoStride, int videoSize, int videoRotation);
|
||||
}
|
||||
|
||||
public interface ReadPCMFileListener {
|
||||
void onAudioStreamData(byte[] buffer, int length, long pts, int audioSampleRate, int audioChannel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.alivc.live.commonbiz;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ResourcesConst {
|
||||
|
||||
private ResourcesConst() {
|
||||
}
|
||||
|
||||
/**
|
||||
* capture0.yuv 文件本地保存路径
|
||||
*/
|
||||
public static File localCaptureYUVFilePath(Context context) {
|
||||
return new File(context.getApplicationContext().getExternalFilesDir(null), "capture0.yuv");
|
||||
}
|
||||
|
||||
/**
|
||||
* 441.pcm 文件本地保存路径
|
||||
*/
|
||||
public static File localCapturePCMFilePath(Context context) {
|
||||
return new File(context.getFilesDir().getPath() + File.separator + "alivc_resource/441.pcm");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.alivc.live.commonbiz;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.alivc.live.commonutils.DownloadUtil;
|
||||
import com.alivc.live.commonutils.HttpUtils;
|
||||
import com.alivc.live.commonutils.FileUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import okhttp3.Response;
|
||||
|
||||
/**
|
||||
* 远端资源下载管理类
|
||||
*
|
||||
* @note 用于下载存放在云端的yuv文件,该yuv文件在外部音视频推流时使用
|
||||
*/
|
||||
public class ResourcesDownload {
|
||||
|
||||
private static final String TAG = "ResourcesDownload";
|
||||
|
||||
private static final String BASIC_YUV_OSS_URL = "https://alivc-demo-cms.alicdn.com/versionProduct/resources/livePush/capture0.yuv";
|
||||
private static final String GLOBAL_YUV_OSS_URL = "https://alivc-demo-cms.alicdn.com/versionProduct/resources/livePush/capture0_SG.yuv";
|
||||
private static final String FINAL_OSS_YUV_URL = BASIC_YUV_OSS_URL;
|
||||
|
||||
private static final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
private ResourcesDownload() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载yuv文件
|
||||
*/
|
||||
public static long downloadCaptureYUV(Context context, DownloadUtil.OnDownloadListener listener) {
|
||||
DownloadUtil downloadUtil = new DownloadUtil(context.getApplicationContext());
|
||||
File file = ResourcesConst.localCaptureYUVFilePath(context);
|
||||
Log.d(TAG, "downloadYUV file : " + file.getAbsolutePath());
|
||||
|
||||
downloadUtil.setDownloadListener(new DownloadUtil.OnDownloadListener() {
|
||||
@Override
|
||||
public void onDownloadSuccess(long downloadId) {
|
||||
Log.d(TAG, "onDownloadSuccess : " + downloadId);
|
||||
verifyFile(downloadUtil, file, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadProgress(long downloadId, double percent) {
|
||||
Log.i(TAG, "onDownloadProgress : " + downloadId + ", " + percent);
|
||||
if (listener != null) {
|
||||
mHandler.post(() -> listener.onDownloadProgress(downloadId, percent));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadError(long downloadId, int errorCode, String errorMsg) {
|
||||
Log.e(TAG, "onDownloadError : " + downloadId + ", " + errorCode + ", " + errorMsg);
|
||||
if (listener != null) {
|
||||
mHandler.post(() -> listener.onDownloadError(downloadId, errorCode, errorMsg));
|
||||
}
|
||||
FileUtil.safeDeleteFile(file);
|
||||
}
|
||||
});
|
||||
|
||||
if (file.exists()) {
|
||||
//文件存在,验证完整性
|
||||
verifyFile(downloadUtil, file, listener);
|
||||
return -1;
|
||||
} else {
|
||||
return downloadUtil.startDownload(FINAL_OSS_YUV_URL, file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证文件完整性
|
||||
* 通过 Response 中 etag 字段获取 OSS 文件的 MD5
|
||||
*/
|
||||
private static void verifyFile(DownloadUtil downloadUtil, File file, DownloadUtil.OnDownloadListener listener) {
|
||||
HttpUtils.get(FINAL_OSS_YUV_URL, new HttpUtils.OnNetWorkListener() {
|
||||
@Override
|
||||
public void onSuccess(Object obj) {
|
||||
Response response = (Response) obj;
|
||||
|
||||
// 1、通过oss url获取etag,和本地文件的md5进行比对,是否一致
|
||||
String responseMD5 = "";
|
||||
try {
|
||||
responseMD5 = response.header("etag").replace("\"", "");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!TextUtils.isEmpty(responseMD5)) {
|
||||
String fileMD5 = FileUtil.getFileMD5(file).trim();
|
||||
if (responseMD5.equalsIgnoreCase(fileMD5)) {
|
||||
if (listener != null) {
|
||||
mHandler.post(() -> listener.onDownloadSuccess(-1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 2、有时候etag是个非法值,并不代表文件的实际md5(坑),那么直接对比文件的大小是否一致
|
||||
long serverFileSize = -1;
|
||||
try {
|
||||
serverFileSize = Long.parseLong(response.header("Content-Length").trim());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (file != null && serverFileSize == file.length()) {
|
||||
if (listener != null) {
|
||||
mHandler.post(() -> listener.onDownloadSuccess(-1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
FileUtil.safeDeleteFile(file);
|
||||
downloadUtil.startDownload(FINAL_OSS_YUV_URL, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int code, String msg) {
|
||||
if (listener != null) {
|
||||
mHandler.post(() -> listener.onDownloadError(-1, DownloadManager.ERROR_HTTP_DATA_ERROR, "code=" + code + ",msg=" + msg));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
if (listener != null) {
|
||||
mHandler.post(() -> listener.onDownloadError(-1, DownloadManager.ERROR_HTTP_DATA_ERROR, "NetWork error"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.alivc.live.commonbiz;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.alivc.live.commonutils.SharedPrefUtils;
|
||||
|
||||
/**
|
||||
* 推流Demo业务SharedPreference
|
||||
*/
|
||||
public class SharedPreferenceUtils {
|
||||
private static final String AUTO_FOCUS = "autofocus";
|
||||
private static final String PREVIEW_MIRROR = "previewmirror";
|
||||
private static final String PUSH_MIRROR = "pushmirror";
|
||||
private static final String TARGET_BIT = "target_bit";
|
||||
private static final String MIN_BIT = "min_bit";
|
||||
private static final String SHOW_GUIDE = "guide";
|
||||
private static final String BEAUTY_ON = "beautyon";
|
||||
private static final String HINT_TARGET_BIT = "hint_target_bit";
|
||||
private static final String HINT_MIN_BIT = "hint_min_bit";
|
||||
private static final String DISPLAY_FIT = "display_fit";
|
||||
private static final String APP_ID = "app_id";
|
||||
private static final String APP_KEY = "app_key";
|
||||
private static final String PLAY_DOMAIN = "play_domain";
|
||||
|
||||
private static final String BARE_STREAM = "bare_stream";
|
||||
private static final String USE_MULTI_PK_16IN = "useMultiPK16IN";
|
||||
private static final String FORCE_RTC_PRE_ENVIRONMENT = "force_rtc_pre_environment";
|
||||
|
||||
public static void setPreviewMirror(@NonNull Context context, boolean previewMirror) {
|
||||
SharedPrefUtils.saveData(context, PREVIEW_MIRROR, previewMirror);
|
||||
}
|
||||
|
||||
public static boolean isPreviewMirror(@NonNull Context context, boolean defaultValue) {
|
||||
return SharedPrefUtils.getBooleanData(context, PREVIEW_MIRROR, defaultValue);
|
||||
}
|
||||
|
||||
public static void setPushMirror(@NonNull Context context, boolean pushMirror) {
|
||||
SharedPrefUtils.saveData(context, PUSH_MIRROR, pushMirror);
|
||||
}
|
||||
|
||||
public static boolean isPushMirror(@NonNull Context context, boolean defaultValue) {
|
||||
return SharedPrefUtils.getBooleanData(context, PUSH_MIRROR, defaultValue);
|
||||
}
|
||||
|
||||
public static void setAutofocus(@NonNull Context context, boolean autofocus) {
|
||||
SharedPrefUtils.saveData(context, AUTO_FOCUS, autofocus);
|
||||
}
|
||||
|
||||
public static boolean isAutoFocus(@NonNull Context context, boolean defaultValue) {
|
||||
return SharedPrefUtils.getBooleanData(context, AUTO_FOCUS, defaultValue);
|
||||
}
|
||||
|
||||
public static void setTargetBit(@NonNull Context context, int target) {
|
||||
SharedPrefUtils.saveData(context, TARGET_BIT, target);
|
||||
}
|
||||
|
||||
public static int getTargetBit(@NonNull Context context) {
|
||||
return SharedPrefUtils.getIntData(context, TARGET_BIT, 0);
|
||||
}
|
||||
|
||||
public static void setMinBit(@NonNull Context context, int min) {
|
||||
SharedPrefUtils.saveData(context, MIN_BIT, min);
|
||||
}
|
||||
|
||||
public static int getMinBit(@NonNull Context context) {
|
||||
return SharedPrefUtils.getIntData(context, MIN_BIT, 0);
|
||||
}
|
||||
|
||||
public static void setHintTargetBit(@NonNull Context context, int hintTarget) {
|
||||
SharedPrefUtils.saveData(context, HINT_TARGET_BIT, hintTarget);
|
||||
}
|
||||
|
||||
public static int getHintTargetBit(@NonNull Context context) {
|
||||
return SharedPrefUtils.getIntData(context, HINT_TARGET_BIT, 0);
|
||||
}
|
||||
|
||||
public static void setHintMinBit(@NonNull Context context, int hintMin) {
|
||||
SharedPrefUtils.saveData(context, HINT_MIN_BIT, hintMin);
|
||||
}
|
||||
|
||||
public static int getHintMinBit(@NonNull Context context) {
|
||||
return SharedPrefUtils.getIntData(context, HINT_MIN_BIT, 0);
|
||||
}
|
||||
|
||||
public static void setGuide(@NonNull Context context, boolean guide) {
|
||||
SharedPrefUtils.saveData(context, SHOW_GUIDE, guide);
|
||||
}
|
||||
|
||||
public static boolean isGuide(@NonNull Context context) {
|
||||
return SharedPrefUtils.getBooleanData(context, SHOW_GUIDE, true);
|
||||
}
|
||||
|
||||
public static void setBeautyOn(@NonNull Context context, boolean beautyOn) {
|
||||
SharedPrefUtils.saveData(context, BEAUTY_ON, beautyOn);
|
||||
}
|
||||
|
||||
public static boolean isBeautyOn(@NonNull Context context) {
|
||||
return SharedPrefUtils.getBooleanData(context, BEAUTY_ON, true);
|
||||
}
|
||||
|
||||
public static void setDisplayFit(@NonNull Context context, int displayfit) {
|
||||
SharedPrefUtils.saveData(context, DISPLAY_FIT, displayfit);
|
||||
}
|
||||
|
||||
public static int getDisplayFit(@NonNull Context context, int defaultValue) {
|
||||
return SharedPrefUtils.getIntData(context, DISPLAY_FIT, defaultValue);
|
||||
}
|
||||
|
||||
public static void setAppInfo(@NonNull Context context, String appId, String appKey, String playDomain) {
|
||||
SharedPrefUtils.saveData(context, APP_ID, appId);
|
||||
SharedPrefUtils.saveData(context, APP_KEY, appKey);
|
||||
SharedPrefUtils.saveData(context, PLAY_DOMAIN, playDomain);
|
||||
}
|
||||
|
||||
public static String getAppId(@NonNull Context context) {
|
||||
return SharedPrefUtils.getStringData(context, APP_ID, "");
|
||||
}
|
||||
|
||||
public static String getAppKey(@NonNull Context context) {
|
||||
return SharedPrefUtils.getStringData(context, APP_KEY, "");
|
||||
}
|
||||
|
||||
public static String getPlayDomain(@NonNull Context context) {
|
||||
return SharedPrefUtils.getStringData(context, PLAY_DOMAIN, "");
|
||||
}
|
||||
|
||||
public static void setMultiPK16IN(@NonNull Context context, boolean value) {
|
||||
SharedPrefUtils.saveData(context, USE_MULTI_PK_16IN, value);
|
||||
}
|
||||
|
||||
public static boolean getMultiPK16IN(@NonNull Context context) {
|
||||
return SharedPrefUtils.getBooleanData(context, USE_MULTI_PK_16IN, false);
|
||||
}
|
||||
|
||||
public static void setForceRTCPreEnvironment(@NonNull Context context, boolean value) {
|
||||
SharedPrefUtils.saveData(context, FORCE_RTC_PRE_ENVIRONMENT, value);
|
||||
}
|
||||
|
||||
public static boolean getForceRTCPreEnvironment(@NonNull Context context) {
|
||||
return SharedPrefUtils.getBooleanData(context, FORCE_RTC_PRE_ENVIRONMENT, false);
|
||||
}
|
||||
|
||||
public static void clear(@NonNull Context context) {
|
||||
SharedPrefUtils.clear(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.alivc.live.commonbiz.backdoor;
|
||||
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.alivc.live.commonbiz.R;
|
||||
import com.alivc.live.commonbiz.SharedPreferenceUtils;
|
||||
import com.alivc.live.commonui.utils.StatusBarUtil;
|
||||
import com.alivc.live.commonui.widgets.LivePushTextSwitch;
|
||||
import com.alivc.live.commonutils.AppUtil;
|
||||
import com.alivc.live.commonutils.FileUtil;
|
||||
import com.alivc.live.commonutils.ToastUtils;
|
||||
import com.alivc.live.pusher.AlivcLiveBase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/10/13
|
||||
* @brief
|
||||
*/
|
||||
public class BackDoorActivity extends AppCompatActivity {
|
||||
|
||||
private static final String SD_CARD_LOG_SUFFIX = "device-info.log";
|
||||
|
||||
private TextView mInfoTv;
|
||||
|
||||
private LivePushTextSwitch mForceRTCPreEnvSw;
|
||||
private LivePushTextSwitch mMultiPK16InSw;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
StatusBarUtil.translucent(this, Color.TRANSPARENT);
|
||||
|
||||
setContentView(R.layout.push_activity_backdoor);
|
||||
initViews();
|
||||
initData();
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
mForceRTCPreEnvSw = findViewById(R.id.sw_force_rtc_pre_env);
|
||||
mForceRTCPreEnvSw.setTextViewText(getString(R.string.backdoor_rtc_force_pre_env));
|
||||
mForceRTCPreEnvSw.setOnSwitchToggleListener(isChecked -> {
|
||||
if (BackDoorInstance.getInstance().isForceRTCPreEnvironment() != isChecked) {
|
||||
BackDoorInstance.getInstance().setForceRTCPreEnvironment(isChecked);
|
||||
// 清除当前连麦配置信息
|
||||
SharedPreferenceUtils.setAppInfo(getApplicationContext(), "", "", "");
|
||||
// 退出APP
|
||||
killApp();
|
||||
}
|
||||
});
|
||||
|
||||
mMultiPK16InSw = findViewById(R.id.sw_multi_pk_16in);
|
||||
mMultiPK16InSw.setTextViewText(getString(R.string.backdoor_multi_pk_16in));
|
||||
mMultiPK16InSw.setOnSwitchToggleListener(isChecked -> {
|
||||
if (BackDoorInstance.getInstance().isUseMultiPK16IN() != isChecked) {
|
||||
BackDoorInstance.getInstance().setUseMultiPK16IN(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
mInfoTv = findViewById(R.id.info_tv);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getDemoBuildInfo());
|
||||
sb.append("\n\n");
|
||||
sb.append(getSdkBuildInfo());
|
||||
sb.append("\n\n");
|
||||
sb.append(AppUtil.getBriefDeviceInfo());
|
||||
sb.append("\n\n");
|
||||
sb.append(AppUtil.getDeviceInfo());
|
||||
sb.append("\n\n");
|
||||
sb.append(AppUtil.getFullCPUInfo());
|
||||
sb.append("\n\n");
|
||||
sb.append(AppUtil.getOpenGLESInfo(this));
|
||||
sb.append("\n\n");
|
||||
mInfoTv.setText(sb.toString());
|
||||
mInfoTv.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
copyInfo2Clipboard();
|
||||
dumpInfo2SdCard();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mForceRTCPreEnvSw.setSwitchChecked(BackDoorInstance.getInstance().isForceRTCPreEnvironment());
|
||||
mMultiPK16InSw.setSwitchChecked(BackDoorInstance.getInstance().isUseMultiPK16IN());
|
||||
}
|
||||
|
||||
private static String getDemoBuildInfo() {
|
||||
return String.format("%s%n%s%n%s%n%s",
|
||||
"Demo Build Type: " + com.alivc.live.commonbiz.BuildConfig.BUILD_TYPE,
|
||||
"Demo Build AIO: " + com.alivc.live.commonbiz.BuildConfig.MTL_BUILD_FOR_AIO,
|
||||
"Demo Build ID: " + com.alivc.live.commonbiz.BuildConfig.MTL_BUILD_ID,
|
||||
"Demo Build Timestamp: " + com.alivc.live.commonbiz.BuildConfig.MTL_BUILD_TIMESTAMP
|
||||
);
|
||||
}
|
||||
|
||||
private static String getSdkBuildInfo() {
|
||||
return String.format("%s%n%s%n%s%n%s%n%s%n%s",
|
||||
"SDK Version: " + AlivcLiveBase.getSDKVersion(),
|
||||
"SDK Build Type: " + com.alivc.live.pusher.BuildConfig.BUILD_TYPE,
|
||||
"SDK Build Interactive: " + com.alivc.live.pusher.BuildConfig.BUILD_INTERACTIVE,
|
||||
"SDK Pre Environment: " + com.alivc.live.pusher.BuildConfig.PUSH_SDK_PRE_ENV,
|
||||
"SDK Head Commit ID: " + com.alivc.live.pusher.BuildConfig.HEAD_COMMIT_ID,
|
||||
"SDK Build ID: " + com.alivc.live.pusher.BuildConfig.MTL_BUILD_ID,
|
||||
"SDK Build Timestamp: " + com.alivc.live.pusher.BuildConfig.MTL_BUILD_TIMESTAMP
|
||||
);
|
||||
}
|
||||
|
||||
private void copyInfo2Clipboard() {
|
||||
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm == null) {
|
||||
return;
|
||||
}
|
||||
cm.setText(mInfoTv.getText());
|
||||
ToastUtils.show("copy to clipboard success!");
|
||||
}
|
||||
|
||||
private void dumpInfo2SdCard() {
|
||||
removeOldSdCardLogs();
|
||||
String folderPath = getSdCardLogPath();
|
||||
String filename = String.format("%s-%s", new SimpleDateFormat("yyMMddHHmmss").format(new Date()), SD_CARD_LOG_SUFFIX);
|
||||
String finalPath = FileUtil.combinePaths(folderPath, filename);
|
||||
|
||||
FileWriter fr = null;
|
||||
try {
|
||||
fr = new FileWriter(finalPath);
|
||||
fr.write(mInfoTv.getText().toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
fr.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeOldSdCardLogs() {
|
||||
String folderPath = getSdCardLogPath();
|
||||
ArrayList<File> files = FileUtil.listAllFiles(new File(folderPath), false);
|
||||
if (files != null && !files.isEmpty()) {
|
||||
for (File file : files) {
|
||||
String path = file.getAbsolutePath();
|
||||
if (path.endsWith(SD_CARD_LOG_SUFFIX)) {
|
||||
FileUtil.safeDeleteFile(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getSdCardLogPath() {
|
||||
String parentPath = getExternalFilesDir("").getAbsolutePath();
|
||||
String folderPath = FileUtil.combinePaths(parentPath, "Ali_RTS_Log");
|
||||
FileUtil.safeCreateFolder(folderPath);
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制退出APP
|
||||
*/
|
||||
private static void killApp() {
|
||||
try {
|
||||
Thread.sleep(2 * 1000L);
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(0);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.alivc.live.commonbiz.backdoor;
|
||||
|
||||
import com.alivc.live.commonbiz.SharedPreferenceUtils;
|
||||
import com.alivc.live.commonutils.ContextUtils;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/10/13
|
||||
* @brief
|
||||
*/
|
||||
public class BackDoorInstance {
|
||||
|
||||
private boolean forceRTCPreEnvironment;
|
||||
|
||||
private boolean useMultiPK16IN;
|
||||
|
||||
private BackDoorInstance() {
|
||||
forceRTCPreEnvironment = SharedPreferenceUtils.getForceRTCPreEnvironment(ContextUtils.getContext());
|
||||
useMultiPK16IN = SharedPreferenceUtils.getMultiPK16IN(ContextUtils.getContext());
|
||||
}
|
||||
|
||||
public static BackDoorInstance getInstance() {
|
||||
return Inner.instance;
|
||||
}
|
||||
|
||||
public boolean isForceRTCPreEnvironment() {
|
||||
return this.forceRTCPreEnvironment;
|
||||
}
|
||||
|
||||
public void setForceRTCPreEnvironment(boolean forceRTCPreEnvironment) {
|
||||
this.forceRTCPreEnvironment = forceRTCPreEnvironment;
|
||||
SharedPreferenceUtils.setForceRTCPreEnvironment(ContextUtils.getContext(), forceRTCPreEnvironment);
|
||||
}
|
||||
|
||||
public boolean isUseMultiPK16IN() {
|
||||
return this.useMultiPK16IN;
|
||||
}
|
||||
|
||||
public void setUseMultiPK16IN(boolean useMultiPK16IN) {
|
||||
this.useMultiPK16IN = useMultiPK16IN;
|
||||
SharedPreferenceUtils.setMultiPK16IN(ContextUtils.getContext(), useMultiPK16IN);
|
||||
}
|
||||
|
||||
private static class Inner {
|
||||
private static final BackDoorInstance instance = new BackDoorInstance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.alivc.live.commonbiz.seidelay;
|
||||
|
||||
import com.alivc.live.commonbiz.seidelay.api.ISEIDelayEventListener;
|
||||
import com.alivc.live.commonbiz.seidelay.handle.SEIDelayProvider;
|
||||
import com.alivc.live.commonbiz.seidelay.handle.SEIDelayReceiver;
|
||||
import com.alivc.live.commonbiz.seidelay.time.SEIDelayTimeHandler;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public class SEIDelayManager {
|
||||
private SEIDelayProvider mProvider;
|
||||
private SEIDelayReceiver mReceiver;
|
||||
|
||||
public SEIDelayManager() {
|
||||
requestNTPTime();
|
||||
}
|
||||
|
||||
public void registerProvider(String src, ISEIDelayEventListener listener) {
|
||||
mProvider = new SEIDelayProvider();
|
||||
mProvider.addListener(src, listener);
|
||||
}
|
||||
|
||||
public void registerReceiver(ISEIDelayEventListener listener) {
|
||||
mReceiver = new SEIDelayReceiver();
|
||||
mReceiver.addListener("receiver", listener);
|
||||
}
|
||||
|
||||
public void receiveSEI(SEISourceType sourceType, String sei) {
|
||||
if (mReceiver != null) {
|
||||
mReceiver.receiveSEI(sourceType, sei);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestNTPTime() {
|
||||
try {
|
||||
new Thread(SEIDelayTimeHandler::requestNTPTime).start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mProvider != null) {
|
||||
mProvider.destroy();
|
||||
mProvider = null;
|
||||
}
|
||||
if (mReceiver != null) {
|
||||
mReceiver.destroy();
|
||||
mReceiver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.alivc.live.commonbiz.seidelay;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public enum SEISourceType {
|
||||
CDN,
|
||||
RTC
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.alivc.live.commonbiz.seidelay.api;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public interface ISEIDelayEventListener {
|
||||
/**
|
||||
* SEI delay event callback
|
||||
*
|
||||
* @param src SEI delay event source
|
||||
* @param type SEI delay event type
|
||||
* @param msg SEI delay event message
|
||||
*/
|
||||
void onEvent(String src, String type, String msg);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.alivc.live.commonbiz.seidelay.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public abstract class ISEIDelayHandle {
|
||||
public final Map<String, ISEIDelayEventListener> listenerHashMap = new HashMap<>();
|
||||
|
||||
public void addListener(String src, ISEIDelayEventListener listener) {
|
||||
listenerHashMap.put(src, listener);
|
||||
}
|
||||
|
||||
public void removeListener(String src) {
|
||||
listenerHashMap.remove(src);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
listenerHashMap.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.alivc.live.commonbiz.seidelay.data;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public class SEIDelayProtocol {
|
||||
|
||||
private static final String SEI_DELAY = "sei_delay";
|
||||
|
||||
private static final String TIMESTAMP = "tm";
|
||||
private static final String SRC = "src";
|
||||
|
||||
public String src = null;
|
||||
public long tm = -1L;
|
||||
|
||||
public SEIDelayProtocol(String src, long tm) {
|
||||
this.src = src;
|
||||
this.tm = tm;
|
||||
}
|
||||
|
||||
public SEIDelayProtocol(String json) {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(json);
|
||||
String seiDelay = jsonObject.getString(SEI_DELAY);
|
||||
|
||||
JSONObject jsonObject2 = new JSONObject(seiDelay);
|
||||
this.src = jsonObject2.getString(SRC);
|
||||
this.tm = jsonObject2.getLong(TIMESTAMP);
|
||||
} catch (JSONException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private String generate() {
|
||||
JSONObject jsonObject1 = new JSONObject();
|
||||
try {
|
||||
jsonObject1.put(SRC, this.src);
|
||||
jsonObject1.put(TIMESTAMP, this.tm);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
JSONObject jsonObject2 = new JSONObject();
|
||||
try {
|
||||
jsonObject2.put(SEI_DELAY, jsonObject1.toString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return jsonObject2.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return generate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.alivc.live.commonbiz.seidelay.handle;
|
||||
|
||||
import com.alivc.live.commonbiz.seidelay.api.ISEIDelayEventListener;
|
||||
import com.alivc.live.commonbiz.seidelay.api.ISEIDelayHandle;
|
||||
import com.alivc.live.commonbiz.seidelay.data.SEIDelayProtocol;
|
||||
import com.alivc.live.commonbiz.seidelay.time.SEIDelayTimeHandler;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Handles SEIDelay tasks and events.
|
||||
* 对象 SEIDelayProvider 是一个处理 SEIDelay 任务和事件的类。
|
||||
* 它使用一个计划好的任务执行器来定期运行任务。
|
||||
* 当有监听器被添加或移除时,它会相应地启动或停止任务。
|
||||
* 这个类主要处理 SEI 延迟相关的逻辑。
|
||||
*
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public class SEIDelayProvider extends ISEIDelayHandle {
|
||||
private static final long SCHEDULED_EXECUTOR_SERVICE_PERIOD = 2 * 1000L;
|
||||
private static final int CORE_POOL_SIZE = 1;
|
||||
|
||||
private ScheduledThreadPoolExecutor mScheduledExecutorService;
|
||||
private volatile boolean mTaskRun = false;
|
||||
|
||||
@Override
|
||||
public void addListener(String src, ISEIDelayEventListener listener) {
|
||||
super.addListener(src, listener);
|
||||
if (!mTaskRun && !listenerHashMap.isEmpty()) {
|
||||
mTaskRun = true;
|
||||
startTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(String src) {
|
||||
super.removeListener(src);
|
||||
if (mTaskRun && listenerHashMap.isEmpty()) {
|
||||
mTaskRun = false;
|
||||
stopTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
stopTask();
|
||||
}
|
||||
|
||||
private void startTask() {
|
||||
stopTask();
|
||||
mScheduledExecutorService = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(CORE_POOL_SIZE);
|
||||
mScheduledExecutorService.scheduleAtFixedRate(this::provideSEI, 0, SCHEDULED_EXECUTOR_SERVICE_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void stopTask() {
|
||||
if (mScheduledExecutorService != null) {
|
||||
mScheduledExecutorService.shutdown();
|
||||
try {
|
||||
if (!mScheduledExecutorService.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
mScheduledExecutorService.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
mScheduledExecutorService.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
mScheduledExecutorService = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void provideSEI() {
|
||||
for (Map.Entry<String, ISEIDelayEventListener> entry : listenerHashMap.entrySet()) {
|
||||
ISEIDelayEventListener eventListener = entry.getValue();
|
||||
if (eventListener != null && SEIDelayTimeHandler.isNtpTimeUpdated()) {
|
||||
long ntpTimestamp = SEIDelayTimeHandler.getCurrentTimestamp();
|
||||
SEIDelayProtocol dataProtocol = new SEIDelayProtocol(entry.getKey(), ntpTimestamp);
|
||||
eventListener.onEvent(dataProtocol.src, dataProtocol.src, dataProtocol.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.alivc.live.commonbiz.seidelay.handle;
|
||||
|
||||
import com.alivc.live.commonbiz.seidelay.SEISourceType;
|
||||
import com.alivc.live.commonbiz.seidelay.api.ISEIDelayEventListener;
|
||||
import com.alivc.live.commonbiz.seidelay.api.ISEIDelayHandle;
|
||||
import com.alivc.live.commonbiz.seidelay.data.SEIDelayProtocol;
|
||||
import com.alivc.live.commonbiz.seidelay.time.SEIDelayTimeHandler;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SEIDelayReceiver handles the reception and processing of SEI data.
|
||||
* It notifies listeners with the delay information.
|
||||
*
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
public class SEIDelayReceiver extends ISEIDelayHandle {
|
||||
|
||||
private static final long INVALID_THRESH_HOLD = 1000 * 60L;
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives SEI data and processes it to calculate delay and notify listeners.
|
||||
*
|
||||
* @param sourceType The type of SEI source.
|
||||
* @param sei The SEI data.
|
||||
*/
|
||||
public void receiveSEI(SEISourceType sourceType, String sei) {
|
||||
if (listenerHashMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SEIDelayTimeHandler.isNtpTimeUpdated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SEIDelayProtocol dataProtocol = new SEIDelayProtocol(sei);
|
||||
long ntpTimestamp = SEIDelayTimeHandler.getCurrentTimestamp();
|
||||
long delay = ntpTimestamp - dataProtocol.tm;
|
||||
if (delay > INVALID_THRESH_HOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
notifyListeners(dataProtocol, sourceType, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered listeners with the delay information.
|
||||
*
|
||||
* @param dataProtocol The SEIDelayProtocol containing SEI data.
|
||||
* @param sourceType The type of SEI source.
|
||||
* @param delay The calculated delay.
|
||||
*/
|
||||
private void notifyListeners(SEIDelayProtocol dataProtocol, SEISourceType sourceType, long delay) {
|
||||
for (Map.Entry<String, ISEIDelayEventListener> entry : listenerHashMap.entrySet()) {
|
||||
ISEIDelayEventListener eventListener = entry.getValue();
|
||||
if (eventListener != null) {
|
||||
eventListener.onEvent(dataProtocol.src, sourceType.toString(), String.valueOf(delay));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.alivc.live.commonbiz.seidelay.time;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/12/5
|
||||
* @brief
|
||||
*/
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.net.ntp.NTPUDPClient;
|
||||
import org.apache.commons.net.ntp.TimeInfo;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class SEIDelayTimeHandler {
|
||||
|
||||
private static final String TAG = "SEIDelayTimeHandler";
|
||||
private static final String NTP_HOST = "ntp.aliyun.com";
|
||||
|
||||
private static long NTP_DELAY = 0L;
|
||||
private static boolean NTP_TIME_UPDATED = false;
|
||||
|
||||
private SEIDelayTimeHandler() {
|
||||
}
|
||||
|
||||
public static void requestNTPTime() {
|
||||
NTPUDPClient client = new NTPUDPClient();
|
||||
client.setDefaultTimeout(5000);
|
||||
try {
|
||||
InetAddress ntpServerAddress = InetAddress.getByName(NTP_HOST);
|
||||
Log.i(TAG, "Connecting to NTP server: " + NTP_HOST);
|
||||
|
||||
TimeInfo timeInfo = client.getTime(ntpServerAddress);
|
||||
timeInfo.computeDetails();
|
||||
long returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime();
|
||||
long systemTime = System.currentTimeMillis();
|
||||
NTP_DELAY = returnTime - systemTime;
|
||||
NTP_TIME_UPDATED = true;
|
||||
Log.i(TAG, "Current time (from " + NTP_HOST + "): " + returnTime);
|
||||
Log.i(TAG, "Current time (from system): " + systemTime);
|
||||
Log.i(TAG, "Delay (NTP-system): " + NTP_DELAY + "ms");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNtpTimeUpdated() {
|
||||
return NTP_TIME_UPDATED;
|
||||
}
|
||||
|
||||
public static long getCurrentTimestamp() {
|
||||
return System.currentTimeMillis() + NTP_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.alivc.live.commonbiz.test;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class AliLiveStreamURLUtil {
|
||||
|
||||
/**
|
||||
* 连麦推拉流地址的APPID/APPKEY/PLAY_DOMAIN
|
||||
*/
|
||||
public static final String APP_ID = PushDemoTestConstants.getTestInteractiveAppID();
|
||||
public static final String APP_KEY = PushDemoTestConstants.getTestInteractiveAppKey();
|
||||
public static final String PLAY_DOMAIN = PushDemoTestConstants.getTestInteractivePlayDomain();
|
||||
|
||||
/**
|
||||
* 连麦推拉流地址的RTMP/HTTP-FLV/ARTC协议头
|
||||
*/
|
||||
private static final String RTMP = "rtmp://";
|
||||
private static final String HTTP = "http://";
|
||||
private static final String FLV = ".flv";
|
||||
private static final String ARTC = "artc://";
|
||||
|
||||
/**
|
||||
* DOMAIN 固定字段。
|
||||
*/
|
||||
public static final String ALILIVE_INTERACTIVE_DOMAIN = "live.aliyun.com";
|
||||
|
||||
/**
|
||||
* 连麦推拉流地址的二级域名(Second-level domain)
|
||||
*/
|
||||
private static final String PULL_SLD = "play";
|
||||
private static final String PUSH_SLD = "push";
|
||||
|
||||
/**
|
||||
* 连麦推拉流地址的参数配置key
|
||||
*/
|
||||
public static final String BASIC_DOMAIN = "basicDomain";
|
||||
public static final String SDK_APP_ID = "sdkAppId";
|
||||
public static final String USER_ID = "userId";
|
||||
public static final String TIMESTAMP = "timestamp";
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
private static final String APP_NAME = "live";
|
||||
|
||||
/**
|
||||
* 旁路混流地址用,纯音频--->audio,音视频--->camera
|
||||
*/
|
||||
private static final String STREAM_TASK_TYPE_CAMERA = "camera";
|
||||
private static final String STREAM_TASK_TYPE_AUDIO = "audio";
|
||||
|
||||
private AliLiveStreamURLUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 APPID/APPKEY/PLAY_DOMAIN 连麦配置信息,生成连麦推流地址
|
||||
* <p>
|
||||
* 需提前配置好以下连麦配置:
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_APPID}
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_APPKEY}
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_PLAY_DOMAIN}
|
||||
*
|
||||
* @param channelId 频道 ID
|
||||
* @param userId 用户 ID
|
||||
* @return 连麦推流地址
|
||||
*/
|
||||
public static String generateInteractivePushUrl(String channelId, String userId) {
|
||||
return generateInteractiveUrl(channelId, userId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 APPID/APPKEY/PLAY_DOMAIN 连麦配置信息,生成连麦拉流地址
|
||||
* <p>
|
||||
* 需提前配置好以下连麦配置:
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_APPID}
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_APPKEY}
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_PLAY_DOMAIN}
|
||||
*
|
||||
* @param channelId 频道 ID
|
||||
* @param userId 用户 ID
|
||||
* @return 连麦实时拉流地址,RTC用户实时互通用
|
||||
*/
|
||||
public static String generateInteractivePullUrl(String channelId, String userId) {
|
||||
return generateInteractiveUrl(channelId, userId, false);
|
||||
}
|
||||
|
||||
private static String generateInteractiveUrl(String channelId, String userId, boolean isPush) {
|
||||
String sld = isPush ? PUSH_SLD : PULL_SLD;
|
||||
long timestamp = AliLiveUserSigGenerate.getTimesTamp();
|
||||
String token = AliLiveUserSigGenerate.createToken(APP_ID, APP_KEY, channelId, userId, timestamp);
|
||||
|
||||
return new StringBuilder(ARTC)
|
||||
.append(ALILIVE_INTERACTIVE_DOMAIN).append("/")
|
||||
.append(sld).append("/")
|
||||
.append(channelId)
|
||||
.append("?")
|
||||
.append(SDK_APP_ID).append("=").append(APP_ID).append("&")
|
||||
.append(USER_ID).append("=").append(userId).append("&")
|
||||
.append(TIMESTAMP).append("=").append(timestamp).append("&")
|
||||
.append(TOKEN).append("=").append(token)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 APPID/APPKEY/PLAY_DOMAIN 连麦配置信息,生成普通观众的CDN拉流地址
|
||||
* <p>
|
||||
* 需提前配置好以下连麦配置:
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_APPID}
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_APPKEY}
|
||||
* {@link AliLiveUserSigGenerate#ALILIVE_PLAY_DOMAIN}
|
||||
*
|
||||
* @param channelId 频道 ID
|
||||
* @param userId 用户 ID
|
||||
* @return 旁路直播拉流地址,普通观众用
|
||||
*/
|
||||
public static String generateCDNPullUrl(String channelId, String userId, boolean isAudioOnly) {
|
||||
/**
|
||||
* 建议将rtmp换成http-flv的形式。理由如下:
|
||||
* 在阿里云点播控制台生成地址时,会同时生成RTMP与HTTP-FLV的地址,这两个协议里包含的数据内容是一致的,只是网络协议通道不一样。
|
||||
* <p>
|
||||
* HTTP协议是互联网主要协议,CDN、运营商、中间网络设备等链路中都对HTTP有很长时间的网络优化,
|
||||
* HTTP的默认80/443端口号也是常见白名单端口,不容易被禁用,而RTMP协议比较老,其默认端口号是1935有可能被防火墙等设备禁用,导致异常。
|
||||
* 因此在综合网络环境下,HTTP-FLV的稳定性、性能(卡顿、延时)会比RTMP更好。
|
||||
*/
|
||||
return generateCDNFlvPullUrl(channelId, userId, isAudioOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse url into auth info
|
||||
*
|
||||
* @param url url
|
||||
* @return url params
|
||||
*/
|
||||
public static HashMap<String, String> parseUrl(String url) {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return map;
|
||||
}
|
||||
|
||||
String[] urlParts = url.trim().split("\\?");
|
||||
map.put(BASIC_DOMAIN, urlParts[0]);
|
||||
if (urlParts.length == 1) {
|
||||
return map;
|
||||
}
|
||||
|
||||
String[] params = urlParts[1].split("&");
|
||||
for (String param : params) {
|
||||
String[] keyValue = param.split("=");
|
||||
if (keyValue.length < 2) {
|
||||
continue;
|
||||
}
|
||||
map.put(keyValue[0], keyValue[1]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse stream name from url params
|
||||
*
|
||||
* @param params url params
|
||||
* @return stream name
|
||||
*/
|
||||
public static String parseURLStreamName(HashMap<String, String> params) {
|
||||
if (params == null || !params.containsKey(BASIC_DOMAIN)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String domain = params.get(BASIC_DOMAIN);
|
||||
if (TextUtils.isEmpty(domain)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String[] parts = domain.split("/");
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
private static String generateCDNFlvPullUrl(String channelId, String userId, boolean isAudioOnly) {
|
||||
String streamTaskType = isAudioOnly ? STREAM_TASK_TYPE_AUDIO : STREAM_TASK_TYPE_CAMERA;
|
||||
|
||||
return new StringBuilder(HTTP)
|
||||
.append(PLAY_DOMAIN).append('/')
|
||||
.append(APP_NAME).append('/')
|
||||
.append(APP_ID).append('_')
|
||||
.append(channelId).append('_')
|
||||
.append(userId).append('_')
|
||||
.append(streamTaskType)
|
||||
.append(FLV)
|
||||
.toString();
|
||||
}
|
||||
|
||||
private static String generateCDNRtmpPullUrl(String channelId, String userId, boolean isAudioOnly) {
|
||||
String streamTaskType = isAudioOnly ? STREAM_TASK_TYPE_AUDIO : STREAM_TASK_TYPE_CAMERA;
|
||||
|
||||
return new StringBuilder(RTMP)
|
||||
.append(PLAY_DOMAIN).append('/')
|
||||
.append(APP_NAME).append('/')
|
||||
.append(APP_ID).append('_')
|
||||
.append(channelId).append('_')
|
||||
.append(userId).append('_')
|
||||
.append(streamTaskType)
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.alivc.live.commonbiz.test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @note 备注:该文件被直播连麦控制台的demo试用所链接,请谨慎改动此文件的目录位置。
|
||||
*/
|
||||
public class AliLiveUserSigGenerate {
|
||||
|
||||
/**
|
||||
* APP_ID,在阿里云控制台应用管理页面创建和查看。
|
||||
*/
|
||||
public static final String ALILIVE_APPID = "PLACEHOLDER";
|
||||
/**
|
||||
* APP_KEY,在阿里云控制台应用管理页面创建和查看。
|
||||
*/
|
||||
public static final String ALILIVE_APPKEY = "PLACEHOLDER";
|
||||
|
||||
/**
|
||||
* CDN_DOMAIN,在阿里云控制台应用管理页面创建和查看。
|
||||
*/
|
||||
public static final String ALILIVE_PLAY_DOMAIN = "PLACEHOLDER";
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
* 时间单位秒,代表令牌有效时间。可设置最大范围是小于等于1天,建议不要设置的过短或超过1天,超过1天会不安全。
|
||||
* 默认时间1天。1天 = 60 x 60 x 24。
|
||||
*/
|
||||
public static long getTimesTamp() {
|
||||
return System.currentTimeMillis() / 1000 + 60 * 60 * 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 appid,appkey,channelId,userId,nonc,timestamp 生层 token
|
||||
*
|
||||
* @param appid 应用ID。在控制台应用管理页面创建和查看。
|
||||
* @param appkey 在控制台应用管理页面创建和查看。
|
||||
* @param channelId 频道 ID
|
||||
* @param userId 用户 ID
|
||||
* @param timestamp 过期时间戳
|
||||
* @return token
|
||||
*/
|
||||
public static String createToken(String appid, String appkey, String channelId, String userId, long timestamp) {
|
||||
StringBuilder stringBuilder = new StringBuilder()
|
||||
.append(appid)
|
||||
.append(appkey)
|
||||
.append(channelId)
|
||||
.append(userId)
|
||||
.append(timestamp);
|
||||
return getSHA256(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串签名
|
||||
*
|
||||
* @param str 输入源
|
||||
* @return 返回签名
|
||||
*/
|
||||
public static String getSHA256(String str) {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = messageDigest.digest(str.getBytes(StandardCharsets.UTF_8));
|
||||
return byte2Hex(hash);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Consider logging the exception and/or re-throwing as a RuntimeException
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String byte2Hex(byte[] bytes) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
// Use single quote for char
|
||||
stringBuilder.append('0');
|
||||
}
|
||||
stringBuilder.append(hex);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.alivc.live.commonbiz.test;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.alivc.live.commonbiz.BuildConfig;
|
||||
import com.alivc.live.commonbiz.R;
|
||||
import com.alivc.live.commonbiz.SharedPreferenceUtils;
|
||||
import com.alivc.live.commonutils.ContextUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Created by baorunchen on 2022/8/31.
|
||||
* <p>
|
||||
* Develop test data class. ONLY FOR TEST!!!!
|
||||
* <p>
|
||||
* First, we store dev test data into `local.properties` file, it's a gitignore file.
|
||||
* <p>
|
||||
* Such as:
|
||||
* sdk.dir=/Users/keria/Library/Android/sdk
|
||||
* push.url=rtmp://push-demo-rtmp.aliyunlive.com/test/stream/keriatest?&auth_key=xxxx
|
||||
* pull.url=
|
||||
* <p>
|
||||
* And then, we can parse it from `build.gradle` file,
|
||||
* if `local.properties` hasn't the property, it will use the default value.
|
||||
*/
|
||||
public class PushDemoTestConstants {
|
||||
private static final String PLACEHOLDER = "PLACEHOLDER";
|
||||
|
||||
/**
|
||||
* Get test push url, you won't need to scan url again!!!
|
||||
* <p>
|
||||
* put your test push url into `local.properties`
|
||||
* such as: push.url=rtmp://xxx
|
||||
*
|
||||
* @return test push url
|
||||
*/
|
||||
public static String getTestPushUrl() {
|
||||
Context context = ContextUtils.getContext();
|
||||
return (context != null) ? context.getString(R.string.test_push_url) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test pull url, you won't need to scan url again!!!
|
||||
* <p>
|
||||
* put your test pull url into `local.properties`
|
||||
* such as: pull.url=rtmp://xxx
|
||||
*
|
||||
* @return test push url
|
||||
*/
|
||||
public static String getTestPullUrl() {
|
||||
Context context = ContextUtils.getContext();
|
||||
return (context != null) ? context.getString(R.string.test_pull_url) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test interactive app id
|
||||
* <p>
|
||||
* put your app id into `local.properties`
|
||||
* such as: interactive.appid=keriatest-appid
|
||||
* <p>
|
||||
* or, you can export it into system environment
|
||||
* such as: export INTERACTIVE_APP_ID=keriatest-appid
|
||||
*
|
||||
* @return interactive app id
|
||||
*/
|
||||
public static String getTestInteractiveAppID() {
|
||||
if (!checkIsPlaceholder(AliLiveUserSigGenerate.ALILIVE_APPID)) {
|
||||
return AliLiveUserSigGenerate.ALILIVE_APPID;
|
||||
}
|
||||
|
||||
if(!TextUtils.isEmpty(SharedPreferenceUtils.getAppId(ContextUtils.getApplicationContext()))){
|
||||
return SharedPreferenceUtils.getAppId(ContextUtils.getApplicationContext());
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(BuildConfig.INTERACTIVE_APP_ID)) {
|
||||
return BuildConfig.INTERACTIVE_APP_ID;
|
||||
}
|
||||
|
||||
Context context = ContextUtils.getContext();
|
||||
if (context != null) {
|
||||
return context.getString(R.string.interactive_appid);
|
||||
}
|
||||
|
||||
return AliLiveUserSigGenerate.ALILIVE_APPID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test interactive app key
|
||||
* <p>
|
||||
* put your app key into `local.properties`
|
||||
* such as: interactive.appkey=keriatest-appkey
|
||||
* <p>
|
||||
* or, you can export it into system environment
|
||||
* such as: export INTERACTIVE_APP_KEY=keriatest-appkey
|
||||
*
|
||||
* @return interactive app key
|
||||
*/
|
||||
public static String getTestInteractiveAppKey() {
|
||||
if (!checkIsPlaceholder(AliLiveUserSigGenerate.ALILIVE_APPKEY)) {
|
||||
return AliLiveUserSigGenerate.ALILIVE_APPKEY;
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(SharedPreferenceUtils.getAppKey(ContextUtils.getApplicationContext()))) {
|
||||
return SharedPreferenceUtils.getAppKey(ContextUtils.getApplicationContext());
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(BuildConfig.INTERACTIVE_APP_KEY)) {
|
||||
return BuildConfig.INTERACTIVE_APP_KEY;
|
||||
}
|
||||
|
||||
Context context = ContextUtils.getContext();
|
||||
if (context != null) {
|
||||
return context.getString(R.string.interactive_appkey);
|
||||
}
|
||||
|
||||
return AliLiveUserSigGenerate.ALILIVE_APPKEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get test interactive play domain
|
||||
* <p>
|
||||
* put your app key into `local.properties`
|
||||
* such as: interactive.playdomain=pullkeriatest.alivecdn.com
|
||||
* <p>
|
||||
* or, you can export it into system environment
|
||||
* such as: export INTERACTIVE_PLAY_DOMAIN=pullkeriatest.alivecdn.com
|
||||
*
|
||||
* @return interactive play domain
|
||||
*/
|
||||
public static String getTestInteractivePlayDomain() {
|
||||
if (!checkIsPlaceholder(AliLiveUserSigGenerate.ALILIVE_PLAY_DOMAIN)) {
|
||||
return AliLiveUserSigGenerate.ALILIVE_PLAY_DOMAIN;
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(SharedPreferenceUtils.getPlayDomain(ContextUtils.getApplicationContext()))) {
|
||||
return SharedPreferenceUtils.getPlayDomain(ContextUtils.getApplicationContext());
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(BuildConfig.INTERACTIVE_PLAY_DOMAIN)) {
|
||||
return BuildConfig.INTERACTIVE_PLAY_DOMAIN;
|
||||
}
|
||||
|
||||
Context context = ContextUtils.getContext();
|
||||
if (context != null) {
|
||||
return context.getString(R.string.interactive_play_domain);
|
||||
}
|
||||
|
||||
return AliLiveUserSigGenerate.ALILIVE_PLAY_DOMAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether configuration value is placeholder or not
|
||||
*
|
||||
* @param configuration configuration value
|
||||
* @return true, false
|
||||
*/
|
||||
public static boolean checkIsPlaceholder(String configuration) {
|
||||
return TextUtils.isEmpty(configuration) || TextUtils.equals(configuration, PLACEHOLDER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.alivc.live.commonbiz.testapi;
|
||||
|
||||
import android.opengl.EGL14;
|
||||
import android.opengl.EGLConfig;
|
||||
import android.opengl.EGLContext;
|
||||
import android.opengl.EGLDisplay;
|
||||
import android.opengl.GLUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2024/7/5
|
||||
* @brief FIXME keria:测试代码
|
||||
*/
|
||||
public class EGLContextTest {
|
||||
|
||||
private static final String TAG = "EGLContextTest";
|
||||
|
||||
private EGLContextTest() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 EGLContext
|
||||
*/
|
||||
public static void testGLContext() {
|
||||
|
||||
int maxContexts = 0;
|
||||
|
||||
// 假设尝试创建最多1000个上下文
|
||||
EGLContext[] contexts = new EGLContext[1000];
|
||||
|
||||
EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
|
||||
if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
|
||||
Log.e(TAG, "Unable to get EGL14 display");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] version = new int[2];
|
||||
if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) {
|
||||
Log.e(TAG, "Unable to initialize EGL14");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] configAttribs = {
|
||||
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
|
||||
EGL14.EGL_RED_SIZE, 8,
|
||||
EGL14.EGL_GREEN_SIZE, 8,
|
||||
EGL14.EGL_BLUE_SIZE, 8,
|
||||
EGL14.EGL_ALPHA_SIZE, 8,
|
||||
EGL14.EGL_DEPTH_SIZE, 24,
|
||||
EGL14.EGL_NONE
|
||||
};
|
||||
|
||||
EGLConfig[] configs = new EGLConfig[1];
|
||||
int[] numConfigs = new int[1];
|
||||
if (!EGL14.eglChooseConfig(eglDisplay, configAttribs, 0, configs, 0, 1, numConfigs, 0)) {
|
||||
Log.e(TAG, "Unable to choose config");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] contextAttribs = {
|
||||
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL14.EGL_NONE
|
||||
};
|
||||
|
||||
for (int i = 0; i < contexts.length; i++) {
|
||||
contexts[i] = EGL14.eglCreateContext(eglDisplay, configs[0], EGL14.EGL_NO_CONTEXT, contextAttribs, 0);
|
||||
if (contexts[i] == EGL14.EGL_NO_CONTEXT) {
|
||||
Log.e(TAG, "Failed to create EGL context at index " + i + ": " + EGL14.eglGetError() + " - " + GLUtils.getEGLErrorString(EGL14.eglGetError()));
|
||||
break;
|
||||
}
|
||||
maxContexts++;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Maximum number of OpenGL ES contexts supported: " + maxContexts);
|
||||
|
||||
// 清理所有创建的上下文
|
||||
for (int i = 0; i < maxContexts; i++) {
|
||||
if (contexts[i] != EGL14.EGL_NO_CONTEXT) {
|
||||
EGL14.eglDestroyContext(eglDisplay, contexts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
EGL14.eglTerminate(eglDisplay);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="30dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/backdoor_title"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="20dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="5dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/backdoor_tip"
|
||||
android:textColor="#B2B7C4"
|
||||
android:textSize="11dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:background="#3A3D48"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<com.alivc.live.commonui.widgets.LivePushTextSwitch
|
||||
android:id="@+id/sw_force_rtc_pre_env"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.alivc.live.commonui.widgets.LivePushTextSwitch
|
||||
android:id="@+id/sw_multi_pk_16in"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="6dp"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="6dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/info_tv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:lineSpacingMultiplier="1.5"
|
||||
android:padding="6dp"
|
||||
android:textSize="12dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="backdoor_title">Live Push Demo Configuration Page</string>
|
||||
<string name="backdoor_tip">Used to manually configure demo corresponding functions</string>
|
||||
<string name="backdoor_rtc_force_pre_env">Force RTC Pre Environment</string>
|
||||
<string name="backdoor_multi_pk_16in">Multi PK 16IN</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="backdoor_title">Live Push Demo配置页面</string>
|
||||
<string name="backdoor_tip">用于手动配置demo相应功能</string>
|
||||
<string name="backdoor_rtc_force_pre_env">强制RTC预发环境</string>
|
||||
<string name="backdoor_multi_pk_16in">16方多人PK</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="backdoor_title">Live Push Demo Configuration Page</string>
|
||||
<string name="backdoor_tip">Used to manually configure demo corresponding functions</string>
|
||||
<string name="backdoor_rtc_force_pre_env">Force RTC Pre Environment</string>
|
||||
<string name="backdoor_multi_pk_16in">Multi PK 16IN</string>
|
||||
|
||||
</resources>
|
||||
2
LiveCommon/live_commonui/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/release
|
||||
41
LiveCommon/live_commonui/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdkVersion
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion androidMinSdkVersion
|
||||
targetSdkVersion androidTargetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
viewBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation externalAndroidDesign
|
||||
|
||||
api project(':LiveCommon:live_commonutils')
|
||||
|
||||
def isInteractive = project.hasProperty("sdk_type") && "AliVCSDK_InteractiveLive".equalsIgnoreCase(sdk_type)
|
||||
api isInteractive ? externalLivePusherInteractive : externalLivePusher
|
||||
}
|
||||
0
LiveCommon/live_commonui/consumer-rules.pro
Normal file
5
LiveCommon/live_commonui/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.alivc.live.commonui">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.alivc.live.commonui.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
|
||||
public class AUILiveActionBar extends RelativeLayout {
|
||||
|
||||
private ImageView mLeftImageView;
|
||||
private ImageView mRightImageView;
|
||||
private TextView mTitleView;
|
||||
|
||||
public AUILiveActionBar(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AUILiveActionBar(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AUILiveActionBar(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
LayoutInflater.from(context).inflate(R.layout.aui_live_actionbar_layout, this, true);
|
||||
mLeftImageView = findViewById(R.id.aui_player_actionbar_left_image);
|
||||
mRightImageView = findViewById(R.id.aui_player_actionbar_right_image);
|
||||
mTitleView = findViewById(R.id.aui_player_actionbar_title);
|
||||
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.av_actionbar);
|
||||
if (ta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isShowTitle = ta.getBoolean(R.styleable.av_actionbar_showTitle, false);
|
||||
mTitleView.setVisibility(isShowTitle ? VISIBLE : GONE);
|
||||
String title = ta.getString(R.styleable.av_actionbar_title);
|
||||
mTitleView.setText(title);
|
||||
|
||||
boolean isShowLeftImage = ta.getBoolean(R.styleable.av_actionbar_showLeftView, false);
|
||||
mLeftImageView.setVisibility(isShowLeftImage ? VISIBLE : GONE);
|
||||
int leftBackground = ta.getResourceId(R.styleable.av_actionbar_leftImageBackground, 0);
|
||||
if (leftBackground != 0) {
|
||||
mLeftImageView.setBackgroundResource(leftBackground);
|
||||
}
|
||||
int leftImage = ta.getResourceId(R.styleable.av_actionbar_leftImageSrc, 0);
|
||||
if (leftImage != 0) {
|
||||
mLeftImageView.setImageResource(leftImage);
|
||||
}
|
||||
|
||||
|
||||
boolean isShowRightImage = ta.getBoolean(R.styleable.av_actionbar_showRightView, false);
|
||||
mRightImageView.setVisibility(isShowRightImage ? VISIBLE : GONE);
|
||||
int rightBackground = ta.getResourceId(R.styleable.av_actionbar_rightImageBackground, 0);
|
||||
if (rightBackground != 0) {
|
||||
mRightImageView.setBackgroundResource(rightBackground);
|
||||
}
|
||||
int rightImage = ta.getResourceId(R.styleable.av_actionbar_rightImageSrc, 0);
|
||||
if (rightImage != 0) {
|
||||
mRightImageView.setImageResource(rightImage);
|
||||
}
|
||||
}
|
||||
|
||||
public void showLeftView() {
|
||||
mLeftImageView.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void hideLeftView() {
|
||||
mLeftImageView.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public void showRightView() {
|
||||
mRightImageView.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void hideRightView() {
|
||||
mRightImageView.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public void showTitleView() {
|
||||
mTitleView.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void hideTitleView() {
|
||||
mTitleView.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public ImageView getLeftImageView() {
|
||||
return mLeftImageView;
|
||||
}
|
||||
|
||||
public ImageView getRightImageView() {
|
||||
return mRightImageView;
|
||||
}
|
||||
|
||||
public TextView getTitleView() {
|
||||
return mTitleView;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.alivc.live.commonui.activity;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.commonui.utils.StatusBarUtil;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AUILiveBaseListActivity extends AppCompatActivity {
|
||||
|
||||
private AUILiveActionBar mAUILiveActionBar;
|
||||
private RecyclerView mRecyclerView;
|
||||
private AVListAdapter mAVListAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
getWindow().setBackgroundDrawable(null);
|
||||
getDelegate().setLocalNightMode(specifiedThemeMode());
|
||||
super.onCreate(savedInstanceState);
|
||||
StatusBarUtil.translucent(this, Color.TRANSPARENT);
|
||||
setContentView(R.layout.aui_live_activity_list_layout);
|
||||
initBaseView();
|
||||
initBaseData();
|
||||
}
|
||||
|
||||
private void initBaseView() {
|
||||
mAUILiveActionBar = findViewById(R.id.aui_player_base_title);
|
||||
mRecyclerView = findViewById(R.id.aui_player_base_main_recyclerView);
|
||||
mAVListAdapter = new AVListAdapter(this);
|
||||
mRecyclerView.setAdapter(mAVListAdapter);
|
||||
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
mAUILiveActionBar.getLeftImageView().setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onBackPressed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initBaseData() {
|
||||
mAUILiveActionBar.getTitleView().setText(getTitleResId());
|
||||
if (showBackBtn()) {
|
||||
mAUILiveActionBar.showLeftView();
|
||||
} else {
|
||||
mAUILiveActionBar.hideLeftView();
|
||||
}
|
||||
mAVListAdapter.setData(createListData());
|
||||
}
|
||||
|
||||
protected int specifiedThemeMode() {
|
||||
return AppCompatDelegate.MODE_NIGHT_NO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题的resourceID, 不要直接使用文本,要适配多语言
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract int getTitleResId();
|
||||
|
||||
/**
|
||||
* 是否显示返回按钮
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean showBackBtn();
|
||||
|
||||
public abstract List<ListModel> createListData();
|
||||
|
||||
public abstract void onListItemClick(ListModel model);
|
||||
|
||||
public static class ListModel {
|
||||
public int index;
|
||||
public int drawableResId;
|
||||
public String title;
|
||||
public String desc;
|
||||
|
||||
public ListModel(int index, int drawableResId, String title, String desc) {
|
||||
this.index = index;
|
||||
this.drawableResId = drawableResId;
|
||||
this.title = title;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AVListAdapter extends RecyclerView.Adapter<AVListHolder> {
|
||||
|
||||
private List<ListModel> mData = new ArrayList<>();
|
||||
private WeakReference<AUILiveBaseListActivity> mAVBaseListActivityRef;
|
||||
|
||||
public AVListAdapter(AUILiveBaseListActivity activity) {
|
||||
mAVBaseListActivityRef = new WeakReference<>(activity);
|
||||
}
|
||||
|
||||
public void setData(List<ListModel> data) {
|
||||
mData.clear();
|
||||
mData.addAll(data);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AVListHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.aui_live_base_list_item, parent, false);
|
||||
AVListHolder avListHolder = new AVListHolder(itemView);
|
||||
avListHolder.mImageView = itemView.findViewById(R.id.av_list_item_image);
|
||||
avListHolder.mTitle = itemView.findViewById(R.id.av_list_item_title);
|
||||
avListHolder.mDesc = itemView.findViewById(R.id.av_list_item_desc);
|
||||
return avListHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AVListHolder holder, int position) {
|
||||
ListModel listModel = mData.get(position);
|
||||
if (listModel == null) {
|
||||
return;
|
||||
}
|
||||
holder.mImageView.setImageResource(listModel.drawableResId);
|
||||
holder.mTitle.setText(listModel.title);
|
||||
if (!TextUtils.isEmpty(listModel.desc)) {
|
||||
holder.mDesc.setText(listModel.desc);
|
||||
holder.mDesc.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.mDesc.setVisibility(View.GONE);
|
||||
}
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (mAVBaseListActivityRef.get() != null) {
|
||||
mAVBaseListActivityRef.get().onListItemClick(mData.get(position));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mData.size();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AVListHolder extends RecyclerView.ViewHolder {
|
||||
ImageView mImageView;
|
||||
TextView mTitle;
|
||||
TextView mDesc;
|
||||
|
||||
public AVListHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.alivc.live.commonui.avdialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationSet;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
|
||||
|
||||
public class AUILiveDialog extends Dialog {
|
||||
private final static int ANIMATION_DURATION = 200;
|
||||
private View mContentView;
|
||||
private boolean mIsAnimating = false;
|
||||
|
||||
public AUILiveDialog(@NonNull Context context) {
|
||||
super(context, R.style.AUILiveDialog);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().getDecorView().setPadding(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(@NonNull View view) {
|
||||
mContentView = view;
|
||||
super.setContentView(view);
|
||||
}
|
||||
|
||||
|
||||
public void setLayoutBySreenMode() {
|
||||
WindowManager.LayoutParams params = getWindow().getAttributes();
|
||||
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
params.gravity = Gravity.CENTER;
|
||||
|
||||
// int screenWidth = DensityUtil.getDisplayMetrics(getContext()).widthPixels;
|
||||
// int screenHeight = DensityUtil.getDisplayMetrics(getContext()).heightPixels;
|
||||
// params.width = Math.min(screenWidth, screenHeight);
|
||||
getWindow().setAttributes(params);
|
||||
setCanceledOnTouchOutside(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* ChoiceItemBottomDialog从下往上升起的动画动画
|
||||
*/
|
||||
private void animateUp() {
|
||||
if (mContentView != null) {
|
||||
return;
|
||||
}
|
||||
TranslateAnimation translateAnimation = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
|
||||
Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 0f);
|
||||
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
|
||||
AnimationSet animationSet = new AnimationSet(true);
|
||||
animationSet.addAnimation(translateAnimation);
|
||||
animationSet.addAnimation(alphaAnimation);
|
||||
animationSet.setInterpolator(new DecelerateInterpolator());
|
||||
animationSet.setDuration(ANIMATION_DURATION);
|
||||
animationSet.setFillAfter(true);
|
||||
mContentView.startAnimation(animationSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* ChoiceItemBottomDialog从下往上升起的动画动画
|
||||
*/
|
||||
private void animateDown() {
|
||||
if (mContentView == null) {
|
||||
return;
|
||||
}
|
||||
TranslateAnimation translate = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
|
||||
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 1f
|
||||
);
|
||||
AlphaAnimation alpha = new AlphaAnimation(1, 0);
|
||||
AnimationSet set = new AnimationSet(true);
|
||||
set.addAnimation(translate);
|
||||
set.addAnimation(alpha);
|
||||
set.setInterpolator(new DecelerateInterpolator());
|
||||
set.setDuration(ANIMATION_DURATION);
|
||||
set.setFillAfter(true);
|
||||
set.setAnimationListener(new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
mIsAnimating = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
mIsAnimating = false;
|
||||
mContentView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
AUILiveDialog.super.dismiss();
|
||||
} catch (Exception e) {
|
||||
Log.w("Test", "dismiss error\n" + Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
|
||||
}
|
||||
});
|
||||
mContentView.startAnimation(set);
|
||||
}
|
||||
|
||||
private void fullScreenImmersive(View view) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
view.setSystemUiVisibility(uiOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
setLayoutBySreenMode();
|
||||
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
|
||||
super.show();
|
||||
fullScreenImmersive(getWindow().getDecorView());
|
||||
this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
|
||||
animateUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
super.dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.alivc.live.commonui.avdialog;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
public abstract class AVLiveBaseBottomSheetDialog extends AVLiveBaseDialog {
|
||||
private ViewGroup mBottomSheetContainer;
|
||||
private boolean mAnimateToCancel = false;
|
||||
private boolean mAnimateToDismiss = false;
|
||||
private BottomSheetBehavior<ViewGroup> mBottomSheetBehavior;
|
||||
|
||||
public AVLiveBaseBottomSheetDialog(Context context) {
|
||||
super(context,R.style.Live_BottomSheetDialog);
|
||||
}
|
||||
|
||||
public AVLiveBaseBottomSheetDialog(Context context, int theme) {
|
||||
super(context, theme);
|
||||
}
|
||||
|
||||
protected AVLiveBaseBottomSheetDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
|
||||
super(context, cancelable, cancelListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initView(Context context) {
|
||||
super.initView(context);
|
||||
View container = getLayoutInflater().inflate(R.layout.av_live_base_dialog_bottom_sheet, null);
|
||||
mBottomSheetContainer = container.findViewById(R.id.bottom_sheet_container);
|
||||
View contentView = getContentView();
|
||||
ViewGroup.LayoutParams contentParams = getContentLayoutParams();
|
||||
if (contentView != null && contentParams != null) {
|
||||
mBottomSheetContainer.addView(contentView, contentParams);
|
||||
}
|
||||
mBottomSheetBehavior = new BottomSheetBehavior<>();
|
||||
mBottomSheetBehavior.setHideable(true);
|
||||
mBottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
|
||||
@Override
|
||||
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
|
||||
if (mAnimateToCancel) {
|
||||
cancel();
|
||||
} else if (mAnimateToDismiss) {
|
||||
dismiss();
|
||||
} else {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
||||
|
||||
}
|
||||
});
|
||||
mBottomSheetBehavior.setPeekHeight(0);
|
||||
mBottomSheetBehavior.setSkipCollapsed(true);
|
||||
((CoordinatorLayout.LayoutParams) mBottomSheetContainer.getLayoutParams()).setBehavior(mBottomSheetBehavior);
|
||||
container.findViewById(R.id.touch_outside).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_SETTLING) {
|
||||
return;
|
||||
}
|
||||
if (mBottomSheetBehavior.isHideable() && isShowing()) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mBottomSheetContainer.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
setContentView(container, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelable(boolean flag) {
|
||||
super.setCancelable(flag);
|
||||
mBottomSheetBehavior.setHideable(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
ViewCompat.requestApplyInsets(mBottomSheetContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
|
||||
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
|
||||
mAnimateToCancel = false;
|
||||
super.cancel();
|
||||
} else {
|
||||
mAnimateToCancel = true;
|
||||
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN){
|
||||
mAnimateToDismiss = false;
|
||||
super.dismiss();
|
||||
}else {
|
||||
mAnimateToDismiss = true;
|
||||
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
super.show();
|
||||
if (mBottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
|
||||
setToExpandWhenShow();
|
||||
}
|
||||
mAnimateToCancel = false;
|
||||
mAnimateToDismiss = false;
|
||||
}
|
||||
|
||||
private void setToExpandWhenShow() {
|
||||
mBottomSheetContainer.postOnAnimation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected abstract View getContentView();
|
||||
|
||||
protected abstract ViewGroup.LayoutParams getContentLayoutParams();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.alivc.live.commonui.avdialog;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.view.Window;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDialog;
|
||||
|
||||
public class AVLiveBaseDialog extends AppCompatDialog {
|
||||
public AVLiveBaseDialog(Context context) {
|
||||
super(context);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public AVLiveBaseDialog(Context context, int theme) {
|
||||
super(context, theme);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
protected AVLiveBaseDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
|
||||
super(context, cancelable, cancelListener);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public void initView(Context context) {
|
||||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
Context context = getContext();
|
||||
if (context instanceof Activity) {
|
||||
Activity activity = (Activity) context;
|
||||
if (activity.isDestroyed() || activity.isFinishing()) {
|
||||
return;
|
||||
}
|
||||
super.dismiss();
|
||||
} else {
|
||||
try {
|
||||
super.dismiss();
|
||||
} catch (Throwable ignore) {
|
||||
super.dismiss();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.alivc.live.commonui.bean;
|
||||
|
||||
public class MusicInfo {
|
||||
private String mMusicName;
|
||||
private String mPlayTime;
|
||||
private String mTotalTime;
|
||||
private String mPath;
|
||||
|
||||
public MusicInfo() {
|
||||
|
||||
}
|
||||
|
||||
public MusicInfo(String musicName, String playTime, String totalTime, String path) {
|
||||
mPlayTime = playTime;
|
||||
mTotalTime = totalTime;
|
||||
mMusicName = musicName;
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
public String getPlayTime() {
|
||||
return mPlayTime;
|
||||
}
|
||||
|
||||
public void setPlayTime(String playTime) {
|
||||
mPlayTime = playTime;
|
||||
}
|
||||
|
||||
public String getTotalTime() {
|
||||
return mTotalTime;
|
||||
}
|
||||
|
||||
public void setTotalTime(String totalTime) {
|
||||
mTotalTime = totalTime;
|
||||
}
|
||||
|
||||
public String getMusicName() {
|
||||
return mMusicName;
|
||||
}
|
||||
|
||||
public void setMusicName(String musicName) {
|
||||
mMusicName = musicName;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return mPath;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
mPath = path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.alivc.live.commonui.configview;
|
||||
|
||||
public class LivePushProgressStep {
|
||||
public static final int PROGRESS_0 = 0;
|
||||
public static final int PROGRESS_16 = 16;
|
||||
public static final int PROGRESS_20 = 20;
|
||||
public static final int PROGRESS_33 = 33;
|
||||
public static final int PROGRESS_40 = 40;
|
||||
public static final int PROGRESS_50 = 50;
|
||||
public static final int PROGRESS_60 = 60;
|
||||
public static final int PROGRESS_66 = 66;
|
||||
public static final int PROGRESS_75 = 75;
|
||||
public static final int PROGRESS_80 = 80;
|
||||
public static final int PROGRESS_90 = 90;
|
||||
public static final int PROGRESS_100 = 100;
|
||||
|
||||
public static final int PROGRESS_AUDIO_160 = 20;
|
||||
public static final int PROGRESS_AUDIO_320 = 40;
|
||||
public static final int PROGRESS_AUDIO_441 = 60;
|
||||
public static final int PROGRESS_AUDIO_480 = 80;
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package com.alivc.live.commonui.configview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.pusher.AlivcResolutionEnum;
|
||||
|
||||
public class LivePushResolutionView extends LinearLayout {
|
||||
|
||||
private SeekBar mResolution;
|
||||
private TextView mResolutionText;
|
||||
private LinearLayout mCustomResolutionRootView;
|
||||
private AlivcResolutionEnum mDefinition = AlivcResolutionEnum.RESOLUTION_720P;
|
||||
private OnResolutionChangedListener mOnResolutionChangedListener;
|
||||
private EditText mWidth;
|
||||
private EditText mHeight;
|
||||
|
||||
public LivePushResolutionView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public LivePushResolutionView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, -1);
|
||||
}
|
||||
|
||||
public LivePushResolutionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
initListener();
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
View inflate = LayoutInflater.from(context).inflate(R.layout.push_resolution_view_layout, this, true);
|
||||
mResolution = inflate.findViewById(R.id.resolution_seekbar);
|
||||
mResolutionText = inflate.findViewById(R.id.resolution_text);
|
||||
mWidth = inflate.findViewById(R.id.et_width);
|
||||
mHeight = inflate.findViewById(R.id.et_height);
|
||||
mCustomResolutionRootView = inflate.findViewById(R.id.custom_resolution_root);
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
mResolution.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
|
||||
if (progress <= LivePushProgressStep.PROGRESS_0) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_180P;
|
||||
mResolutionText.setText(R.string.setting_resolution_180P);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_0 && progress <= LivePushProgressStep.PROGRESS_16) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_240P;
|
||||
mResolutionText.setText(R.string.setting_resolution_240P);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_16 && progress <= LivePushProgressStep.PROGRESS_33) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_360P;
|
||||
mResolutionText.setText(R.string.setting_resolution_360P);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_33 && progress <= LivePushProgressStep.PROGRESS_50) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_480P;
|
||||
mResolutionText.setText(R.string.setting_resolution_480P);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_50 && progress <= LivePushProgressStep.PROGRESS_66) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_540P;
|
||||
mResolutionText.setText(R.string.setting_resolution_540P);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_66 && progress <= LivePushProgressStep.PROGRESS_75) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_720P;
|
||||
mResolutionText.setText(R.string.setting_resolution_720P);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_75 && progress <= LivePushProgressStep.PROGRESS_90) {
|
||||
mCustomResolutionRootView.setVisibility(View.GONE);
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_1080P;
|
||||
mResolutionText.setText(R.string.setting_resolution_1080P);
|
||||
} else {
|
||||
mDefinition = AlivcResolutionEnum.RESOLUTION_SELF_DEFINE;
|
||||
mResolutionText.setText(R.string.setting_resolution_self_define);
|
||||
mCustomResolutionRootView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mOnResolutionChangedListener != null) {
|
||||
mOnResolutionChangedListener.onResolutionChanged(mDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
int progress = seekBar.getProgress();
|
||||
if (progress <= LivePushProgressStep.PROGRESS_0) {
|
||||
seekBar.setProgress(0);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_0 && progress <= LivePushProgressStep.PROGRESS_16) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_16);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_16 && progress <= LivePushProgressStep.PROGRESS_33) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_33);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_33 && progress <= LivePushProgressStep.PROGRESS_50) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_50);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_50 && progress <= LivePushProgressStep.PROGRESS_66) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_66);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_66 && progress <= LivePushProgressStep.PROGRESS_75) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_75);
|
||||
} else if (progress > LivePushProgressStep.PROGRESS_75 && progress <= LivePushProgressStep.PROGRESS_90) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_90);
|
||||
} else {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setResolution(AlivcResolutionEnum resolution) {
|
||||
if (resolution == AlivcResolutionEnum.RESOLUTION_180P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_0);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_180P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_240P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_16);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_240P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_360P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_33);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_360P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_480P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_50);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_480P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_540P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_66);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_540P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_720P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_75);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_720P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_1080P) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_90);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_1080P));
|
||||
} else if (resolution == AlivcResolutionEnum.RESOLUTION_SELF_DEFINE) {
|
||||
mResolution.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
mResolutionText.setText(getResources().getString(R.string.setting_resolution_self_define));
|
||||
int resolutionWidth = AlivcResolutionEnum.getResolutionWidth(resolution, null);
|
||||
int resolutionHeight = AlivcResolutionEnum.getResolutionHeight(resolution, null);
|
||||
mWidth.setText(String.valueOf(resolutionWidth));
|
||||
mHeight.setText(String.valueOf(resolutionHeight));
|
||||
}
|
||||
}
|
||||
|
||||
public int getSelfDefineWidth() {
|
||||
return Integer.parseInt(mWidth.getText().toString());
|
||||
}
|
||||
|
||||
public int getSelfDefineHeight() {
|
||||
return Integer.parseInt(mHeight.getText().toString());
|
||||
}
|
||||
|
||||
public void setOnResolutionChangedListener(OnResolutionChangedListener listener) {
|
||||
this.mOnResolutionChangedListener = listener;
|
||||
}
|
||||
|
||||
public interface OnResolutionChangedListener {
|
||||
void onResolutionChanged(AlivcResolutionEnum resolutionEnum);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,1220 @@
|
||||
package com.alivc.live.commonui.configview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.alivc.live.annotations.AlivcLiveCameraCaptureOutputPreference;
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.commonutils.TextFormatUtil;
|
||||
import com.alivc.live.pusher.AlivcAudioAACProfileEnum;
|
||||
import com.alivc.live.pusher.AlivcAudioChannelEnum;
|
||||
import com.alivc.live.pusher.AlivcAudioSampleRateEnum;
|
||||
import com.alivc.live.pusher.AlivcAudioSceneModeEnum;
|
||||
import com.alivc.live.pusher.AlivcEncodeModeEnum;
|
||||
import com.alivc.live.pusher.AlivcEncodeType;
|
||||
import com.alivc.live.pusher.AlivcFpsEnum;
|
||||
import com.alivc.live.pusher.AlivcLivePushCameraTypeEnum;
|
||||
import com.alivc.live.pusher.AlivcLivePushConfig;
|
||||
import com.alivc.live.pusher.AlivcLivePushConstants;
|
||||
import com.alivc.live.pusher.AlivcPreviewDisplayMode;
|
||||
import com.alivc.live.pusher.AlivcPreviewOrientationEnum;
|
||||
import com.alivc.live.pusher.AlivcQualityModeEnum;
|
||||
import com.alivc.live.pusher.AlivcResolutionEnum;
|
||||
import com.alivc.live.pusher.AlivcVideoEncodeGopEnum;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LivePushSettingView extends LinearLayout {
|
||||
|
||||
private com.alivc.live.commonui.databinding.PushSettingViewLayoutBinding mViewBinding;
|
||||
private PushConfigDialogImpl mPushConfigDialog = new PushConfigDialogImpl();
|
||||
|
||||
//码率控制
|
||||
private final MutableLiveData<Boolean> mBitrateControlLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> bitrateControl = mBitrateControlLiveData;
|
||||
|
||||
//可变分辨率
|
||||
private final MutableLiveData<Boolean> mVariableResolutionLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> variableResolution = mVariableResolutionLiveData;
|
||||
|
||||
//分辨率
|
||||
private final MutableLiveData<AlivcResolutionEnum> mResolutionLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcResolutionEnum> resolution = mResolutionLiveData;
|
||||
|
||||
//最小帧率
|
||||
private final MutableLiveData<AlivcFpsEnum> mMinFpsLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcFpsEnum> minFps = mMinFpsLiveData;
|
||||
|
||||
//音频采样率
|
||||
private final MutableLiveData<AlivcAudioSampleRateEnum> mAudioSampleRateLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcAudioSampleRateEnum> audioSampleRate = mAudioSampleRateLiveData;
|
||||
|
||||
//GOP
|
||||
private final MutableLiveData<AlivcVideoEncodeGopEnum> mGopLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcVideoEncodeGopEnum> gop = mGopLiveData;
|
||||
|
||||
//FPS
|
||||
private final MutableLiveData<AlivcFpsEnum> mFpsLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcFpsEnum> fps = mFpsLiveData;
|
||||
|
||||
//视频硬编码
|
||||
private final MutableLiveData<Boolean> mVideoHardwareDecodeLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> videoHardwareDecode = mVideoHardwareDecodeLiveData;
|
||||
//音频硬编码
|
||||
private final MutableLiveData<Boolean> mAudioHardwareDecodeLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> audioHardwareDecode = mAudioHardwareDecodeLiveData;
|
||||
|
||||
//推流镜像
|
||||
private final MutableLiveData<Boolean> mPushMirrorLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> pushMirror = mPushMirrorLiveData;
|
||||
|
||||
//预览镜像
|
||||
private final MutableLiveData<Boolean> mPreviewMirrorLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> previewMirror = mPreviewMirrorLiveData;
|
||||
|
||||
//前置摄像头
|
||||
private final MutableLiveData<Boolean> mEnableFrontCamera = new MutableLiveData<>();
|
||||
public LiveData<Boolean> enableFrontCamera = mEnableFrontCamera;
|
||||
|
||||
//美颜
|
||||
private final MutableLiveData<Boolean> mEnableBeauty = new MutableLiveData<>();
|
||||
public LiveData<Boolean> enableBeauty = mEnableBeauty;
|
||||
|
||||
//暂停图片
|
||||
private final MutableLiveData<Boolean> mPauseImageLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> pauseImage = mPauseImageLiveData;
|
||||
|
||||
//网络差图片
|
||||
private final MutableLiveData<Boolean> mNetWorkImageLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> netWorkImage = mNetWorkImageLiveData;
|
||||
|
||||
//自动对焦
|
||||
private final MutableLiveData<Boolean> mAutoFocusLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> autoFocus = mAutoFocusLiveData;
|
||||
|
||||
//异步接口
|
||||
private final MutableLiveData<Boolean> mAsyncLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> async = mAsyncLiveData;
|
||||
|
||||
//音乐模式
|
||||
private final MutableLiveData<Boolean> mMusicModeLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> musicMode = mMusicModeLiveData;
|
||||
|
||||
//外部音视频
|
||||
private final MutableLiveData<Boolean> mExternLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> extern = mExternLiveData;
|
||||
|
||||
//本地日志
|
||||
private final MutableLiveData<Boolean> mLocalLogLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> localLog = mLocalLogLiveData;
|
||||
|
||||
//仅视频
|
||||
private final MutableLiveData<Boolean> mVideoOnlyLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> videoOnly = mVideoOnlyLiveData;
|
||||
|
||||
//仅音频
|
||||
private final MutableLiveData<Boolean> mAudioOnlyLiveData = new MutableLiveData<>();
|
||||
public LiveData<Boolean> audioOnly = mAudioOnlyLiveData;
|
||||
|
||||
//预览显示模式
|
||||
private final MutableLiveData<AlivcPreviewDisplayMode> mPreviewDisplayModeLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcPreviewDisplayMode> previewDisplayMode = mPreviewDisplayModeLiveData;
|
||||
|
||||
//摄像头采集偏好
|
||||
private final MutableLiveData<AlivcLiveCameraCaptureOutputPreference> mCameraCaptureOutputPreferenceLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcLiveCameraCaptureOutputPreference> cameraCaptureOutputPreference = mCameraCaptureOutputPreferenceLiveData;
|
||||
|
||||
//声道
|
||||
private final MutableLiveData<AlivcAudioChannelEnum> mAudioChannelLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcAudioChannelEnum> audioChannel = mAudioChannelLiveData;
|
||||
|
||||
//音频编码
|
||||
private final MutableLiveData<AlivcAudioAACProfileEnum> mAudioProfileLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcAudioAACProfileEnum> audioProfile = mAudioProfileLiveData;
|
||||
|
||||
//音频编码
|
||||
private final MutableLiveData<AlivcEncodeType> mVideoEncodeTypeLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcEncodeType> videoEncodeType = mVideoEncodeTypeLiveData;
|
||||
|
||||
//B-Frame
|
||||
private final MutableLiveData<Integer> mBFrameLiveData = new MutableLiveData<>();
|
||||
public LiveData<Integer> bFrame = mBFrameLiveData;
|
||||
|
||||
// 视频目标码率
|
||||
private final MutableLiveData<Integer> mTargetVideoBitrate = new MutableLiveData<>();
|
||||
public LiveData<Integer> targetVideoBitrate = mTargetVideoBitrate;
|
||||
|
||||
// 视频最小码率
|
||||
private final MutableLiveData<Integer> mMinVideoBitrate = new MutableLiveData<>();
|
||||
public LiveData<Integer> minVideoBitrate = mMinVideoBitrate;
|
||||
|
||||
// 视频初始码率
|
||||
private final MutableLiveData<Integer> mInitialVideoBitrate = new MutableLiveData<>();
|
||||
public LiveData<Integer> initialVideoBitrate = mInitialVideoBitrate;
|
||||
|
||||
// 音频码率
|
||||
private final MutableLiveData<Integer> mAudioBitrate = new MutableLiveData<>();
|
||||
public LiveData<Integer> audioBitrate = mAudioBitrate;
|
||||
|
||||
//暂停图片路径
|
||||
private final MutableLiveData<String> mPauseImgPathLiveData = new MutableLiveData<>();
|
||||
public LiveData<String> pauseImagePath = mPauseImgPathLiveData;
|
||||
|
||||
//网络差图片路径
|
||||
private final MutableLiveData<String> mNetWorkImgPathLiveData = new MutableLiveData<>();
|
||||
public LiveData<String> netWorkImagePath = mNetWorkImgPathLiveData;
|
||||
|
||||
//屏幕方向
|
||||
private final MutableLiveData<AlivcPreviewOrientationEnum> mPreviewOrientationLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcPreviewOrientationEnum> previewOrientation = mPreviewOrientationLiveData;
|
||||
|
||||
//视频质量
|
||||
private final MutableLiveData<AlivcQualityModeEnum> mQualityModeLiveData = new MutableLiveData<>();
|
||||
public LiveData<AlivcQualityModeEnum> qualityMode = mQualityModeLiveData;
|
||||
|
||||
//水印 Dialog
|
||||
private final MutableLiveData<Boolean> mShowWaterMarkDialog = new MutableLiveData<>();
|
||||
public LiveData<Boolean> showWaterMark = mShowWaterMarkDialog;
|
||||
|
||||
private AlivcQualityModeEnum mCurrentQualityMode = AlivcQualityModeEnum.QM_RESOLUTION_FIRST;
|
||||
private AlivcResolutionEnum mCurrentResolution = AlivcResolutionEnum.RESOLUTION_540P;
|
||||
|
||||
private int mPushModeDefaultIndex = 0;
|
||||
private int mDisplayModeDefaultIndex = 0;
|
||||
private int mCameraCaptureOutputPreferenceDefaultIndex = 2;
|
||||
private int mAudioChannelDefaultIndex = 1;
|
||||
private int mAudioProfileDefaultIndex = 0;
|
||||
private int mQualityModeDefaultIndex = 0;
|
||||
private int mVideoEncoderTypeDefaultIndex = 0;
|
||||
private int mBFrameDefaultIndex = 0;
|
||||
private int mPreviewOrientationDefaultIndex = 0;
|
||||
|
||||
public LivePushSettingView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public LivePushSettingView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, -1);
|
||||
}
|
||||
|
||||
public LivePushSettingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mViewBinding = com.alivc.live.commonui.databinding.PushSettingViewLayoutBinding.inflate(LayoutInflater.from(context), this, true);
|
||||
initData();
|
||||
initListener();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setHint(String.valueOf(AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate()));
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
mTargetVideoBitrate.setValue(TextFormatUtil.convertString2Int(String.valueOf(s)));
|
||||
}
|
||||
});
|
||||
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setHint(String.valueOf(AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate()));
|
||||
mViewBinding.pushArgsSetting.minRateEdit.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
mMinVideoBitrate.setValue(TextFormatUtil.convertString2Int(String.valueOf(s)));
|
||||
}
|
||||
});
|
||||
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setHint(String.valueOf(AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate()));
|
||||
mViewBinding.pushArgsSetting.initRateEdit.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
mInitialVideoBitrate.setValue(TextFormatUtil.convertString2Int(String.valueOf(s)));
|
||||
}
|
||||
});
|
||||
turnOnBitRateFps(false);
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
//切换分辨率
|
||||
mViewBinding.pushArgsSetting.resolutionView.setOnResolutionChangedListener(resolutionEnum -> {
|
||||
mCurrentResolution = resolutionEnum;
|
||||
mResolutionLiveData.setValue(resolutionEnum);
|
||||
if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_180P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_180P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_180P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_180P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_240P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_240P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_240P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_240P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_360P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_360P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_360P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_360P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_480P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_480P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_480P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_480P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_540P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_540P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_540P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_720P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_720P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_720P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_720P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else if (resolutionEnum == AlivcResolutionEnum.RESOLUTION_1080P) {
|
||||
if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_RESOLUTION_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_1080P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_1080P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_1080P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else if (mCurrentQualityMode.equals(AlivcQualityModeEnum.QM_FLUENCY_FIRST)) {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_1080P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_1080P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_1080P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
} else {
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.BITRATE_1080P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_1080P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_1080P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate());
|
||||
}
|
||||
} else {
|
||||
//自定义
|
||||
changeVideoBitrateWithResolution(AlivcLivePushConstants.DEFAULT_VALUE_INT_TARGET_BITRATE,
|
||||
AlivcLivePushConstants.DEFAULT_VALUE_INT_MIN_BITRATE,
|
||||
AlivcLivePushConstants.DEFAULT_VALUE_INT_INIT_BITRATE);
|
||||
}
|
||||
});
|
||||
//最小帧率
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (progress <= LivePushProgressStep.PROGRESS_0) {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_8);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_8.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_16) {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_10);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_10.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_33) {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_12);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_12.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_50) {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_15);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_15.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_66) {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_20);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_20.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_80) {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_25);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_25.getFps()));
|
||||
} else {
|
||||
mMinFpsLiveData.setValue(AlivcFpsEnum.FPS_30);
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(AlivcFpsEnum.FPS_30.getFps()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
});
|
||||
|
||||
//fps
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (progress <= LivePushProgressStep.PROGRESS_0) {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_8);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_8.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_16) {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_10);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_10.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_33) {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_12);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_12.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_50) {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_15);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_15.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_66) {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_20);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_20.getFps()));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_80) {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_25);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_25.getFps()));
|
||||
} else {
|
||||
mFpsLiveData.setValue(AlivcFpsEnum.FPS_30);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_30.getFps()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
int progress = seekBar.getProgress();
|
||||
if (progress <= LivePushProgressStep.PROGRESS_0) {
|
||||
seekBar.setProgress(0);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_16) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_16);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_33) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_33);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_50) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_50);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_66) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_66);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_80) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_80);
|
||||
} else {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//音频采样率
|
||||
mViewBinding.pushArgsSetting.audioRateSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (progress <= LivePushProgressStep.PROGRESS_AUDIO_160) {
|
||||
mAudioSampleRateLiveData.setValue(AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_16000);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getContext().getString(R.string.setting_audio_160));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_AUDIO_320) {
|
||||
mAudioSampleRateLiveData.setValue(AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_32000);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getContext().getString(R.string.setting_audio_320));
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_AUDIO_441) {
|
||||
mAudioSampleRateLiveData.setValue(AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_44100);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getContext().getString(R.string.setting_audio_441));
|
||||
} else {
|
||||
mAudioSampleRateLiveData.setValue(AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_48000);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getContext().getString(R.string.setting_audio_480));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
int progress = seekBar.getProgress();
|
||||
if (progress <= LivePushProgressStep.PROGRESS_AUDIO_160) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_160);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_AUDIO_320) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_320);
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_AUDIO_441) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_441);
|
||||
} else {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_480);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//GOP
|
||||
mViewBinding.pushArgsSetting.gopSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (progress <= LivePushProgressStep.PROGRESS_20) {
|
||||
mGopLiveData.setValue(AlivcVideoEncodeGopEnum.GOP_ONE);
|
||||
mViewBinding.pushArgsSetting.gopText.setText("1/s");
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_40) {
|
||||
mGopLiveData.setValue(AlivcVideoEncodeGopEnum.GOP_TWO);
|
||||
mViewBinding.pushArgsSetting.gopText.setText("2/s");
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_60) {
|
||||
mGopLiveData.setValue(AlivcVideoEncodeGopEnum.GOP_THREE);
|
||||
mViewBinding.pushArgsSetting.gopText.setText("3/s");
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_80) {
|
||||
mGopLiveData.setValue(AlivcVideoEncodeGopEnum.GOP_FOUR);
|
||||
mViewBinding.pushArgsSetting.gopText.setText("4/s");
|
||||
} else if (progress <= LivePushProgressStep.PROGRESS_100) {
|
||||
mGopLiveData.setValue(AlivcVideoEncodeGopEnum.GOP_FIVE);
|
||||
mViewBinding.pushArgsSetting.gopText.setText("5/s");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
int progress = seekBar.getProgress();
|
||||
if (progress <= 20) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_20);
|
||||
} else if (progress <= 40) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_40);
|
||||
} else if (progress <= 60) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_60);
|
||||
} else if (progress <= 80) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_80);
|
||||
} else if (progress <= 100) {
|
||||
seekBar.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//码率控制
|
||||
mViewBinding.pushArgsSetting.bitrateControl.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mBitrateControlLiveData.setValue(isChecked);
|
||||
});
|
||||
//可变分辨率
|
||||
mViewBinding.pushArgsSetting.variableResolution.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mVariableResolutionLiveData.setValue(isChecked);
|
||||
});
|
||||
//高级设置
|
||||
mViewBinding.pushArgsSetting.advanceConfig.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mViewBinding.pushArgsSetting.advanceLayout.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
//显示模式
|
||||
mViewBinding.pushArgsSetting.qualityModes.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushArgsSetting.qualityModes, mQualityListener, mQualityModeDefaultIndex);
|
||||
});
|
||||
//音频编码
|
||||
mViewBinding.pushArgsSetting.audioProfiles.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushArgsSetting.audioProfiles, mAudioProfilesListener, mAudioProfileDefaultIndex);
|
||||
});
|
||||
//声道
|
||||
mViewBinding.pushArgsSetting.audioChannel.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushArgsSetting.audioChannel, mAudioChannelListener, mAudioChannelDefaultIndex);
|
||||
});
|
||||
//视频编码
|
||||
mViewBinding.pushArgsSetting.videoEncoderType.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushArgsSetting.videoEncoderType, mEncoderTypeListener, mVideoEncoderTypeDefaultIndex);
|
||||
});
|
||||
//B帧
|
||||
mViewBinding.pushArgsSetting.bFrameNum.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushArgsSetting.bFrameNum, mFrameNumListener, mBFrameDefaultIndex);
|
||||
});
|
||||
//视频硬编码
|
||||
mViewBinding.pushArgsSetting.hardSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mVideoHardwareDecodeLiveData.setValue(isChecked);
|
||||
});
|
||||
//音频硬编码
|
||||
mViewBinding.pushArgsSetting.audioHardenc.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mAudioHardwareDecodeLiveData.setValue(isChecked);
|
||||
});
|
||||
|
||||
//推流方向
|
||||
mViewBinding.pushFunctionSetting.mainOrientation.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushFunctionSetting.mainOrientation, mOrientationListener, mPreviewOrientationDefaultIndex);
|
||||
});
|
||||
//显示模式
|
||||
mViewBinding.pushFunctionSetting.settingDisplayMode.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushFunctionSetting.settingDisplayMode, mDisplayModeListener, mDisplayModeDefaultIndex);
|
||||
});
|
||||
//摄像头采集偏好
|
||||
mViewBinding.pushFunctionSetting.settingCameraCaptureOutputPreference.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushFunctionSetting.settingCameraCaptureOutputPreference, mCameraCaptureOutputPreferenceListener, mCameraCaptureOutputPreferenceDefaultIndex);
|
||||
});
|
||||
//水印
|
||||
mViewBinding.pushFunctionSetting.watermarkSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mViewBinding.pushFunctionSetting.waterPosition.setClickable(isChecked);
|
||||
mViewBinding.pushFunctionSetting.waterPosition.setTextColor(isChecked ? getResources().getColor(R.color.colourful_text_strong) : getResources().getColor(R.color.text_ultraweak));
|
||||
});
|
||||
//水印位置
|
||||
mViewBinding.pushFunctionSetting.waterPosition.setOnClickListener(view -> {
|
||||
mShowWaterMarkDialog.setValue(mViewBinding.pushFunctionSetting.watermarkSwitch.isChecked());
|
||||
});
|
||||
//推流镜像
|
||||
mViewBinding.pushFunctionSetting.pushMirrorSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mPushMirrorLiveData.setValue(isChecked);
|
||||
});
|
||||
//预览镜像
|
||||
mViewBinding.pushFunctionSetting.previewMirrorSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mPreviewMirrorLiveData.setValue(isChecked);
|
||||
});
|
||||
//摄像头
|
||||
mViewBinding.pushFunctionSetting.cameraSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mEnableFrontCamera.setValue(isChecked);
|
||||
});
|
||||
//自动对焦
|
||||
mViewBinding.pushFunctionSetting.autofocusSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mAutoFocusLiveData.setValue(isChecked);
|
||||
});
|
||||
//美颜
|
||||
mViewBinding.pushFunctionSetting.beautyOnSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mEnableBeauty.setValue(isChecked);
|
||||
});
|
||||
//暂停推图片
|
||||
mViewBinding.pushFunctionSetting.pauseImage.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mPauseImageLiveData.setValue(isChecked);
|
||||
});
|
||||
//网络差图片
|
||||
mViewBinding.pushFunctionSetting.networkImage.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mNetWorkImageLiveData.setValue(isChecked);
|
||||
});
|
||||
//推流模式
|
||||
mViewBinding.pushFunctionSetting.pushMode.setOnClickListener(view -> {
|
||||
mPushConfigDialog.showConfigDialog(mViewBinding.pushFunctionSetting.pushMode, mPushModeListener, mPushModeDefaultIndex);
|
||||
});
|
||||
//有效时长,鉴权 key
|
||||
//异步接口
|
||||
mViewBinding.pushFunctionSetting.asyncSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mAsyncLiveData.setValue(isChecked);
|
||||
});
|
||||
//音乐模式
|
||||
mViewBinding.pushFunctionSetting.musicModeSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mMusicModeLiveData.setValue(isChecked);
|
||||
});
|
||||
//外部音视频
|
||||
mViewBinding.pushFunctionSetting.externVideo.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mExternLiveData.setValue(isChecked);
|
||||
// 当前外部音视频的资源是720P,因此推流分辨率对应调整为720P
|
||||
mViewBinding.pushArgsSetting.resolutionView.setResolution(AlivcResolutionEnum.RESOLUTION_720P);
|
||||
});
|
||||
//本地日志
|
||||
mViewBinding.pushFunctionSetting.logSwitch.setOnCheckedChangeListener((compoundButton, isChecked) -> {
|
||||
mLocalLogLiveData.setValue(isChecked);
|
||||
});
|
||||
}
|
||||
|
||||
public void showArgsContent(boolean isShow) {
|
||||
mViewBinding.pushArgsSetting.getRoot().setVisibility(isShow ? View.VISIBLE : View.GONE);
|
||||
mViewBinding.pushFunctionSetting.getRoot().setVisibility(isShow ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mQualityListener = new PushConfigBottomSheetLive.OnPushConfigSelectorListener() {
|
||||
@Override
|
||||
public void confirm(String tips, int i) {
|
||||
mViewBinding.pushArgsSetting.qualityModes.setText(tips);
|
||||
if (AlivcQualityModeEnum.QM_CUSTOM.equals(mCurrentQualityMode)) {
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setText("");
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setText("");
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setText("");
|
||||
mViewBinding.pushArgsSetting.audioBitrate.setText("");
|
||||
}
|
||||
if (i == 0) {
|
||||
mCurrentQualityMode = AlivcQualityModeEnum.QM_RESOLUTION_FIRST;
|
||||
mQualityModeLiveData.setValue(AlivcQualityModeEnum.QM_RESOLUTION_FIRST);
|
||||
if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_180P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_180P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_240P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_240P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_360P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_360P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_480P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_480P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_540P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_720P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_720P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_RESOLUTION_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
}
|
||||
turnOnBitRateFps(false);
|
||||
} else if (i == 1) {
|
||||
mCurrentQualityMode = AlivcQualityModeEnum.QM_FLUENCY_FIRST;
|
||||
mQualityModeLiveData.setValue(AlivcQualityModeEnum.QM_FLUENCY_FIRST);
|
||||
if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_180P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_180P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_240P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_240P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_360P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_360P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_480P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_480P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_540P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_540P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_720P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_720P_FLUENCY_FIRST.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_FLUENCY_FIRST.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P_FLUENCY_FIRST.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
}
|
||||
turnOnBitRateFps(false);
|
||||
} else if (i == 2) {
|
||||
mCurrentQualityMode = AlivcQualityModeEnum.QM_CUSTOM;
|
||||
mQualityModeLiveData.setValue(AlivcQualityModeEnum.QM_CUSTOM);
|
||||
if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_180P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_180P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_180P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_240P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_240P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_240P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_360P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_360P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_360P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_480P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_480P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_480P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_540P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_540P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_540P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
} else if (mCurrentResolution.equals(AlivcResolutionEnum.RESOLUTION_720P)) {
|
||||
changeVideoBitrateWithResolution(
|
||||
AlivcLivePushConstants.BITRATE_720P.DEFAULT_VALUE_INT_TARGET_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P.DEFAULT_VALUE_INT_MIN_BITRATE.getBitrate(),
|
||||
AlivcLivePushConstants.BITRATE_720P.DEFAULT_VALUE_INT_INIT_BITRATE.getBitrate()
|
||||
);
|
||||
}
|
||||
turnOnBitRateFps(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mAudioProfilesListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mAudioProfileLiveData.setValue(AlivcAudioAACProfileEnum.AAC_LC);
|
||||
} else if (index == 1) {
|
||||
mAudioProfileLiveData.setValue(AlivcAudioAACProfileEnum.HE_AAC);
|
||||
} else if (index == 2) {
|
||||
mAudioProfileLiveData.setValue(AlivcAudioAACProfileEnum.HE_AAC_v2);
|
||||
} else if (index == 3) {
|
||||
mAudioProfileLiveData.setValue(AlivcAudioAACProfileEnum.AAC_LD);
|
||||
}
|
||||
};
|
||||
|
||||
private void turnOnBitRateFps(boolean on) {
|
||||
if (!on) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(83);
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(AlivcFpsEnum.FPS_25.getFps()));
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setFocusable(false);
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setFocusable(false);
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setFocusable(false);
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setFocusable(false);
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setFocusableInTouchMode(false);
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setFocusableInTouchMode(false);
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setFocusableInTouchMode(false);
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setFocusableInTouchMode(false);
|
||||
} else {
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setFocusable(true);
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setFocusable(true);
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setFocusable(true);
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setFocusableInTouchMode(true);
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setFocusableInTouchMode(true);
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setFocusableInTouchMode(true);
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.requestFocus();
|
||||
mViewBinding.pushArgsSetting.initRateEdit.requestFocus();
|
||||
mViewBinding.pushArgsSetting.minRateEdit.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private void changeVideoBitrateWithResolution(int targetBitrate, int minBitrate, int initBitrate) {
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setHint(String.valueOf(targetBitrate));
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setHint(String.valueOf(minBitrate));
|
||||
mViewBinding.pushArgsSetting.initRateEdit.setHint(String.valueOf(initBitrate));
|
||||
|
||||
mTargetVideoBitrate.setValue(targetBitrate);
|
||||
mMinVideoBitrate.setValue(minBitrate);
|
||||
mInitialVideoBitrate.setValue(initBitrate);
|
||||
}
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mAudioChannelListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mAudioChannelLiveData.setValue(AlivcAudioChannelEnum.AUDIO_CHANNEL_ONE);
|
||||
} else if (index == 1) {
|
||||
mAudioChannelLiveData.setValue(AlivcAudioChannelEnum.AUDIO_CHANNEL_TWO);
|
||||
}
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mEncoderTypeListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mVideoEncodeTypeLiveData.setValue(AlivcEncodeType.Encode_TYPE_H264);
|
||||
} else if (index == 1) {
|
||||
mVideoEncodeTypeLiveData.setValue(AlivcEncodeType.Encode_TYPE_H265);
|
||||
}
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mFrameNumListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mBFrameLiveData.setValue(0);
|
||||
} else if (index == 1) {
|
||||
mBFrameLiveData.setValue(1);
|
||||
} else if (index == 2) {
|
||||
mBFrameLiveData.setValue(3);
|
||||
}
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mOrientationListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mPreviewOrientationLiveData.setValue(AlivcPreviewOrientationEnum.ORIENTATION_PORTRAIT);
|
||||
} else if (index == 1) {
|
||||
mPreviewOrientationLiveData.setValue(AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_LEFT);
|
||||
} else if (index == 2) {
|
||||
mPreviewOrientationLiveData.setValue(AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT);
|
||||
}
|
||||
mPauseImgPathLiveData.setValue(getContext().getFilesDir().getPath() + File.separator + "alivc_resource/background_push.png");
|
||||
mNetWorkImgPathLiveData.setValue(getContext().getFilesDir().getPath() + File.separator + "alivc_resource/poor_network.png");
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mDisplayModeListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mPreviewDisplayModeLiveData.setValue(AlivcPreviewDisplayMode.ALIVC_LIVE_PUSHER_PREVIEW_SCALE_FILL);
|
||||
} else if (index == 1) {
|
||||
mPreviewDisplayModeLiveData.setValue(AlivcPreviewDisplayMode.ALIVC_LIVE_PUSHER_PREVIEW_ASPECT_FIT);
|
||||
} else if (index == 2) {
|
||||
mPreviewDisplayModeLiveData.setValue(AlivcPreviewDisplayMode.ALIVC_LIVE_PUSHER_PREVIEW_ASPECT_FILL);
|
||||
}
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mCameraCaptureOutputPreferenceListener = (data, index) -> {
|
||||
if (index == 0) {
|
||||
mCameraCaptureOutputPreferenceLiveData.setValue(AlivcLiveCameraCaptureOutputPreference.AUTO);
|
||||
} else if (index == 1) {
|
||||
mCameraCaptureOutputPreferenceLiveData.setValue(AlivcLiveCameraCaptureOutputPreference.PERFORMANCE);
|
||||
} else if (index == 2) {
|
||||
mCameraCaptureOutputPreferenceLiveData.setValue(AlivcLiveCameraCaptureOutputPreference.PREVIEW);
|
||||
}
|
||||
};
|
||||
|
||||
private final PushConfigBottomSheetLive.OnPushConfigSelectorListener mPushModeListener = (data, index) -> {
|
||||
boolean mAudioOnlyPush = (index == 1);
|
||||
boolean mVideoOnlyPush = (index == 2);
|
||||
mAudioOnlyLiveData.setValue(mAudioOnlyPush);
|
||||
mVideoOnlyLiveData.setValue(mVideoOnlyPush);
|
||||
};
|
||||
|
||||
public String getInitVideoBitrate() {
|
||||
String initVideoBitrate = mViewBinding.pushArgsSetting.initRateEdit.getText().toString();
|
||||
if (TextUtils.isEmpty(initVideoBitrate)) {
|
||||
return mViewBinding.pushArgsSetting.initRateEdit.getHint().toString();
|
||||
}
|
||||
return initVideoBitrate;
|
||||
}
|
||||
|
||||
public String getAudioBitrate() {
|
||||
String audioBitrate = mViewBinding.pushArgsSetting.audioBitrate.getText().toString();
|
||||
if (TextUtils.isEmpty(audioBitrate)) {
|
||||
return mViewBinding.pushArgsSetting.audioBitrate.getHint().toString();
|
||||
}
|
||||
return audioBitrate;
|
||||
}
|
||||
|
||||
public String getMinVideoBitrate() {
|
||||
String minVideoBitrate = mViewBinding.pushArgsSetting.minRateEdit.getText().toString();
|
||||
if (TextUtils.isEmpty(minVideoBitrate)) {
|
||||
return mViewBinding.pushArgsSetting.minRateEdit.getHint().toString();
|
||||
}
|
||||
return minVideoBitrate;
|
||||
}
|
||||
|
||||
public String getMinVideoBitrateOnlyEditText() {
|
||||
return mViewBinding.pushArgsSetting.minRateEdit.getText().toString();
|
||||
}
|
||||
|
||||
public String getMinVideoBitrateOnlyHint() {
|
||||
return mViewBinding.pushArgsSetting.minRateEdit.getHint().toString();
|
||||
}
|
||||
|
||||
public void setTargetVideoBitrateText(String bitrate) {
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setText(bitrate);
|
||||
}
|
||||
|
||||
public void setMinVideoBitrateText(String bitrate) {
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setText(bitrate);
|
||||
}
|
||||
|
||||
public String getTargetVideoBitrate() {
|
||||
String targetVideoBitrate = mViewBinding.pushArgsSetting.targetRateEdit.getText().toString();
|
||||
if (TextUtils.isEmpty(targetVideoBitrate)) {
|
||||
return mViewBinding.pushArgsSetting.targetRateEdit.getHint().toString();
|
||||
}
|
||||
return targetVideoBitrate;
|
||||
}
|
||||
|
||||
public String getTargetVideoBitrateOnlyEditText() {
|
||||
return mViewBinding.pushArgsSetting.targetRateEdit.getText().toString();
|
||||
}
|
||||
|
||||
public String getTargetVideoBitrateOnlyHint() {
|
||||
return mViewBinding.pushArgsSetting.targetRateEdit.getHint().toString();
|
||||
}
|
||||
|
||||
public int getRetryCount() {
|
||||
String retryCount = mViewBinding.pushFunctionSetting.retryCount.getText().toString();
|
||||
if (TextUtils.isEmpty(retryCount)) {
|
||||
return AlivcLivePushConstants.DEFAULT_VALUE_INT_AUDIO_RETRY_COUNT;
|
||||
}
|
||||
return Integer.parseInt(retryCount);
|
||||
}
|
||||
|
||||
public int getRetryInterval() {
|
||||
String retryInterval = mViewBinding.pushFunctionSetting.retryInterval.getText().toString();
|
||||
if (TextUtils.isEmpty(retryInterval)) {
|
||||
return AlivcLivePushConstants.DEFAULT_VALUE_INT_RETRY_INTERVAL;
|
||||
}
|
||||
return Integer.parseInt(retryInterval);
|
||||
}
|
||||
|
||||
public String getAuthTime() {
|
||||
return mViewBinding.pushFunctionSetting.authTime.getText().toString();
|
||||
}
|
||||
|
||||
public String getPrivacyKey() {
|
||||
return mViewBinding.pushFunctionSetting.privacyKey.getText().toString();
|
||||
}
|
||||
|
||||
public void externDownloadError() {
|
||||
mViewBinding.pushFunctionSetting.externVideo.setChecked(false);
|
||||
}
|
||||
|
||||
public boolean enableWaterMark() {
|
||||
return mViewBinding.pushFunctionSetting.watermarkSwitch.isChecked();
|
||||
}
|
||||
|
||||
public void setPushMirror(boolean isChecked) {
|
||||
mViewBinding.pushFunctionSetting.pushMirrorSwitch.setChecked(isChecked);
|
||||
}
|
||||
|
||||
public void setPreviewMirror(boolean isChecked) {
|
||||
mViewBinding.pushFunctionSetting.previewMirrorSwitch.setChecked(isChecked);
|
||||
}
|
||||
|
||||
public void setAutoFocus(boolean isChecked) {
|
||||
mViewBinding.pushFunctionSetting.autofocusSwitch.setChecked(isChecked);
|
||||
}
|
||||
|
||||
public void setBeautyOn(boolean isChecked) {
|
||||
mViewBinding.pushFunctionSetting.beautyOnSwitch.setChecked(isChecked);
|
||||
}
|
||||
|
||||
public boolean enableBeauty() {
|
||||
return mViewBinding.pushFunctionSetting.beautyOnSwitch.isChecked();
|
||||
}
|
||||
|
||||
public int getSelfDefineResolutionWidth() {
|
||||
return mViewBinding.pushArgsSetting.resolutionView.getSelfDefineWidth();
|
||||
}
|
||||
|
||||
public int getSelfDefineResolutionHeight() {
|
||||
return mViewBinding.pushArgsSetting.resolutionView.getSelfDefineHeight();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mPushConfigDialog.destroy();
|
||||
}
|
||||
|
||||
public void setDefaultConfig(AlivcLivePushConfig alivcLivePushConfig, boolean isEnableBeauty, boolean isEnableLocalLog, boolean isEnableWaterMark) {
|
||||
mViewBinding.pushArgsSetting.bitrateControl.setChecked(alivcLivePushConfig.isEnableBitrateControl());
|
||||
mViewBinding.pushArgsSetting.targetRateEdit.setText(String.valueOf(alivcLivePushConfig.getTargetVideoBitrate()));
|
||||
mViewBinding.pushArgsSetting.minRateEdit.setText(String.valueOf(alivcLivePushConfig.getMinVideoBitrate()));
|
||||
mViewBinding.pushArgsSetting.variableResolution.setChecked(alivcLivePushConfig.isEnableAutoResolution());
|
||||
AlivcResolutionEnum configResolution = alivcLivePushConfig.getResolution();
|
||||
mViewBinding.pushArgsSetting.resolutionView.setResolution(configResolution);
|
||||
int audioChannels = alivcLivePushConfig.getAudioChannels();
|
||||
if (audioChannels == AlivcAudioChannelEnum.AUDIO_CHANNEL_ONE.getChannelCount()) {
|
||||
mAudioChannelDefaultIndex = 0;
|
||||
mViewBinding.pushArgsSetting.audioChannel.setText(getResources().getString(R.string.single_track));
|
||||
} else if ((audioChannels == AlivcAudioChannelEnum.AUDIO_CHANNEL_TWO.getChannelCount())) {
|
||||
mAudioChannelDefaultIndex = 1;
|
||||
mViewBinding.pushArgsSetting.audioChannel.setText(getResources().getString(R.string.dual_track));
|
||||
}
|
||||
AlivcAudioAACProfileEnum configAudioProfile = alivcLivePushConfig.getAudioProfile();
|
||||
if (configAudioProfile == AlivcAudioAACProfileEnum.AAC_LC) {
|
||||
mAudioProfileDefaultIndex = 0;
|
||||
mViewBinding.pushArgsSetting.audioProfiles.setText(getResources().getString(R.string.setting_audio_aac_lc));
|
||||
} else if (configAudioProfile == AlivcAudioAACProfileEnum.HE_AAC) {
|
||||
mAudioProfileDefaultIndex = 1;
|
||||
mViewBinding.pushArgsSetting.audioProfiles.setText(getResources().getString(R.string.setting_audio_aac_he));
|
||||
} else if (configAudioProfile == AlivcAudioAACProfileEnum.HE_AAC_v2) {
|
||||
mAudioProfileDefaultIndex = 2;
|
||||
mViewBinding.pushArgsSetting.audioProfiles.setText(getResources().getString(R.string.setting_audio_aac_hev2));
|
||||
} else if (configAudioProfile == AlivcAudioAACProfileEnum.AAC_LD) {
|
||||
mAudioProfileDefaultIndex = 3;
|
||||
mViewBinding.pushArgsSetting.audioProfiles.setText(getResources().getString(R.string.setting_audio_aac_ld));
|
||||
}
|
||||
mViewBinding.pushArgsSetting.minFpsText.setText(String.valueOf(alivcLivePushConfig.getMinFps()));
|
||||
int configMinFps = alivcLivePushConfig.getMinFps();
|
||||
if (configMinFps == AlivcFpsEnum.FPS_8.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_0);
|
||||
} else if (configMinFps == AlivcFpsEnum.FPS_10.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_16);
|
||||
} else if (configMinFps == AlivcFpsEnum.FPS_12.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_33);
|
||||
} else if (configMinFps == AlivcFpsEnum.FPS_15.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_50);
|
||||
} else if (configMinFps == AlivcFpsEnum.FPS_20.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_66);
|
||||
} else if (configMinFps == AlivcFpsEnum.FPS_25.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_80);
|
||||
} else if (configMinFps == AlivcFpsEnum.FPS_30.getFps()) {
|
||||
mViewBinding.pushArgsSetting.minFpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
}
|
||||
AlivcAudioSampleRateEnum configAudioSampleRate = alivcLivePushConfig.getAudioSampleRate();
|
||||
if (configAudioSampleRate == AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_16000) {
|
||||
mViewBinding.pushArgsSetting.audioRateSeekbar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_160);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getResources().getString(R.string.setting_audio_160));
|
||||
} else if (configAudioSampleRate == AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_32000) {
|
||||
mViewBinding.pushArgsSetting.audioRateSeekbar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_320);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getResources().getString(R.string.setting_audio_320));
|
||||
} else if (configAudioSampleRate == AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_44100) {
|
||||
mViewBinding.pushArgsSetting.audioRateSeekbar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_441);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getResources().getString(R.string.setting_audio_441));
|
||||
} else if (configAudioSampleRate == AlivcAudioSampleRateEnum.AUDIO_SAMPLE_RATE_48000) {
|
||||
mViewBinding.pushArgsSetting.audioRateSeekbar.setProgress(LivePushProgressStep.PROGRESS_AUDIO_480);
|
||||
mViewBinding.pushArgsSetting.audioRateText.setText(getResources().getString(R.string.setting_audio_480));
|
||||
}
|
||||
mViewBinding.pushArgsSetting.gopText.setText(String.format(Locale.getDefault(), "%d/s", alivcLivePushConfig.getVideoEncodeGop()));
|
||||
int videoEncodeGop = alivcLivePushConfig.getVideoEncodeGop();
|
||||
if (videoEncodeGop == AlivcVideoEncodeGopEnum.GOP_ONE.getGop()) {
|
||||
mViewBinding.pushArgsSetting.gopSeekbar.setProgress(LivePushProgressStep.PROGRESS_20);
|
||||
} else if (videoEncodeGop == AlivcVideoEncodeGopEnum.GOP_TWO.getGop()) {
|
||||
mViewBinding.pushArgsSetting.gopSeekbar.setProgress(LivePushProgressStep.PROGRESS_40);
|
||||
} else if (videoEncodeGop == AlivcVideoEncodeGopEnum.GOP_THREE.getGop()) {
|
||||
mViewBinding.pushArgsSetting.gopSeekbar.setProgress(LivePushProgressStep.PROGRESS_60);
|
||||
} else if (videoEncodeGop == AlivcVideoEncodeGopEnum.GOP_FOUR.getGop()) {
|
||||
mViewBinding.pushArgsSetting.gopSeekbar.setProgress(LivePushProgressStep.PROGRESS_80);
|
||||
} else if (videoEncodeGop == AlivcVideoEncodeGopEnum.GOP_FIVE.getGop()) {
|
||||
mViewBinding.pushArgsSetting.gopSeekbar.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
}
|
||||
mViewBinding.pushArgsSetting.fpsText.setText(String.valueOf(alivcLivePushConfig.getFps()));
|
||||
int configFps = alivcLivePushConfig.getFps();
|
||||
if (configFps == AlivcFpsEnum.FPS_8.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_0);
|
||||
} else if (configFps == AlivcFpsEnum.FPS_10.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_16);
|
||||
} else if (configFps == AlivcFpsEnum.FPS_12.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_33);
|
||||
} else if (configFps == AlivcFpsEnum.FPS_15.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_50);
|
||||
} else if (configFps == AlivcFpsEnum.FPS_20.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_66);
|
||||
} else if (configFps == AlivcFpsEnum.FPS_25.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_80);
|
||||
} else if (configFps == AlivcFpsEnum.FPS_30.getFps()) {
|
||||
mViewBinding.pushArgsSetting.fpsSeekbar.setProgress(LivePushProgressStep.PROGRESS_100);
|
||||
}
|
||||
AlivcQualityModeEnum configQualityMode = alivcLivePushConfig.getQualityMode();
|
||||
if (configQualityMode == AlivcQualityModeEnum.QM_RESOLUTION_FIRST) {
|
||||
mQualityModeDefaultIndex = 0;
|
||||
mViewBinding.pushArgsSetting.qualityModes.setText(getResources().getString(R.string.quality_resolution_first));
|
||||
} else if (configQualityMode == AlivcQualityModeEnum.QM_FLUENCY_FIRST) {
|
||||
mQualityModeDefaultIndex = 1;
|
||||
mViewBinding.pushArgsSetting.qualityModes.setText(getResources().getString(R.string.quality_fluency_first));
|
||||
} else if (configQualityMode == AlivcQualityModeEnum.QM_CUSTOM) {
|
||||
mQualityModeDefaultIndex = 2;
|
||||
mViewBinding.pushArgsSetting.qualityModes.setText(getResources().getString(R.string.quality_custom));
|
||||
}
|
||||
AlivcEncodeType configVideoEncodeType = alivcLivePushConfig.getVideoEncodeType();
|
||||
if (configVideoEncodeType == AlivcEncodeType.Encode_TYPE_H264) {
|
||||
mVideoEncoderTypeDefaultIndex = 0;
|
||||
mViewBinding.pushArgsSetting.videoEncoderType.setText(getResources().getString(R.string.h264));
|
||||
} else if (configVideoEncodeType == AlivcEncodeType.Encode_TYPE_H265) {
|
||||
mVideoEncoderTypeDefaultIndex = 1;
|
||||
mViewBinding.pushArgsSetting.videoEncoderType.setText(getResources().getString(R.string.h265));
|
||||
}
|
||||
int bFrames = alivcLivePushConfig.getBFrames();
|
||||
if (bFrames == 0) {
|
||||
mBFrameDefaultIndex = 0;
|
||||
mViewBinding.pushArgsSetting.bFrameNum.setText("0");
|
||||
} else if (bFrames == 1) {
|
||||
mBFrameDefaultIndex = 1;
|
||||
mViewBinding.pushArgsSetting.bFrameNum.setText("1");
|
||||
} else if (bFrames == 3) {
|
||||
mBFrameDefaultIndex = 2;
|
||||
mViewBinding.pushArgsSetting.bFrameNum.setText("3");
|
||||
}
|
||||
mViewBinding.pushArgsSetting.hardSwitch.setChecked(alivcLivePushConfig.getVideoEncodeMode() == AlivcEncodeModeEnum.Encode_MODE_HARD);
|
||||
mViewBinding.pushArgsSetting.audioHardenc.setChecked(alivcLivePushConfig.getAudioEncodeMode() == AlivcEncodeModeEnum.Encode_MODE_HARD);
|
||||
|
||||
mViewBinding.pushFunctionSetting.beautyOnSwitch.setChecked(isEnableBeauty);
|
||||
mViewBinding.pushFunctionSetting.logSwitch.setChecked(isEnableLocalLog);
|
||||
mViewBinding.pushFunctionSetting.watermarkSwitch.setChecked(isEnableWaterMark);
|
||||
mViewBinding.pushFunctionSetting.pushMirrorSwitch.setChecked(alivcLivePushConfig.isPushMirror());
|
||||
mViewBinding.pushFunctionSetting.previewMirrorSwitch.setChecked(alivcLivePushConfig.isPreviewMirror());
|
||||
mViewBinding.pushFunctionSetting.cameraSwitch.setChecked(alivcLivePushConfig.getCameraType() == AlivcLivePushCameraTypeEnum.CAMERA_TYPE_FRONT.getCameraId());
|
||||
mViewBinding.pushFunctionSetting.autofocusSwitch.setChecked(alivcLivePushConfig.isAutoFocus());
|
||||
mViewBinding.pushFunctionSetting.pauseImage.setChecked(!TextUtils.isEmpty(alivcLivePushConfig.getPausePushImage()));
|
||||
mViewBinding.pushFunctionSetting.networkImage.setChecked(!TextUtils.isEmpty(alivcLivePushConfig.getNetworkPoorPushImage()));
|
||||
mViewBinding.pushFunctionSetting.musicModeSwitch.setChecked(alivcLivePushConfig.getAudioSceneMode() == AlivcAudioSceneModeEnum.AUDIO_SCENE_MUSIC_MODE);
|
||||
mViewBinding.pushFunctionSetting.externVideo.setChecked(alivcLivePushConfig.isExternMainStream());
|
||||
|
||||
boolean configAudioOnly = alivcLivePushConfig.isAudioOnly();
|
||||
boolean configVideoOnly = alivcLivePushConfig.isVideoOnly();
|
||||
if (configAudioOnly && configVideoOnly) {
|
||||
mPushModeDefaultIndex = 0;
|
||||
mViewBinding.pushFunctionSetting.pushMode.setText(getResources().getString(R.string.video_push_streaming));
|
||||
} else {
|
||||
if (configAudioOnly) {
|
||||
mPushModeDefaultIndex = 1;
|
||||
mViewBinding.pushFunctionSetting.pushMode.setText(getResources().getString(R.string.audio_only_push_streaming));
|
||||
} else {
|
||||
mPushModeDefaultIndex = 2;
|
||||
mViewBinding.pushFunctionSetting.pushMode.setText(getResources().getString(R.string.video_only_push_streaming));
|
||||
}
|
||||
}
|
||||
|
||||
AlivcPreviewDisplayMode configPreviewDisplayMode = alivcLivePushConfig.getPreviewDisplayMode();
|
||||
if (configPreviewDisplayMode == AlivcPreviewDisplayMode.ALIVC_LIVE_PUSHER_PREVIEW_SCALE_FILL) {
|
||||
mDisplayModeDefaultIndex = 0;
|
||||
mViewBinding.pushFunctionSetting.settingDisplayMode.setText(getResources().getString(R.string.display_mode_full));
|
||||
} else if (configPreviewDisplayMode == AlivcPreviewDisplayMode.ALIVC_LIVE_PUSHER_PREVIEW_ASPECT_FIT) {
|
||||
mDisplayModeDefaultIndex = 1;
|
||||
mViewBinding.pushFunctionSetting.settingDisplayMode.setText(getResources().getString(R.string.display_mode_fit));
|
||||
} else if (configPreviewDisplayMode == AlivcPreviewDisplayMode.ALIVC_LIVE_PUSHER_PREVIEW_ASPECT_FILL) {
|
||||
mDisplayModeDefaultIndex = 2;
|
||||
mViewBinding.pushFunctionSetting.settingDisplayMode.setText(getResources().getString(R.string.display_mode_cut));
|
||||
}
|
||||
|
||||
int configPreviewOrientation = alivcLivePushConfig.getPreviewOrientation();
|
||||
if (configPreviewOrientation == AlivcPreviewOrientationEnum.ORIENTATION_PORTRAIT.getOrientation()) {
|
||||
mPreviewOrientationDefaultIndex = 0;
|
||||
mViewBinding.pushFunctionSetting.mainOrientation.setText(getResources().getString(R.string.portrait));
|
||||
} else if (configPreviewOrientation == AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_LEFT.getOrientation()) {
|
||||
mPreviewOrientationDefaultIndex = 1;
|
||||
mViewBinding.pushFunctionSetting.mainOrientation.setText(getResources().getString(R.string.homeLeft));
|
||||
} else if (configPreviewOrientation == AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT.getOrientation()) {
|
||||
mPreviewOrientationDefaultIndex = 2;
|
||||
mViewBinding.pushFunctionSetting.mainOrientation.setText(getResources().getString(R.string.homeRight));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
package com.alivc.live.commonui.configview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.Scroller;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OptionSelectorView extends View implements Runnable {
|
||||
private static final String TAG = "OptionSelectorView";
|
||||
private final float DEFAULT_FRICTION = 0.02f;
|
||||
private final int DEFAULT_ITEM_HEIGHT = (int) dip2px(39);
|
||||
private final int DEFAULT_DIVIDER_COLOR = Color.parseColor("#3A3D48");
|
||||
private final int DEFAULT_VISIBLE_ITEM_NUM = 6;
|
||||
private final float mHalfShowHeight = DEFAULT_VISIBLE_ITEM_NUM * DEFAULT_ITEM_HEIGHT / 2.0f;
|
||||
private final int DEFAULT_START_ITEM_COLOR = Color.parseColor("#FCFCFD");
|
||||
private final int DEFAULT_END_TEXT_COLOR = Color.parseColor("#747A8C");
|
||||
private final float mMaxTextSize = sp2px(21);
|
||||
private final float mMinTextSize = sp2px(13);
|
||||
|
||||
private List<String> mData;
|
||||
private int mMinimumVelocity;
|
||||
private int mMaximumVelocity;
|
||||
private long mClickTimeout;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private Scroller mScroller;
|
||||
private int mMinScrollY;
|
||||
private int mMaxScrollY;
|
||||
private int mScrollOffsetY;
|
||||
private boolean mIsDragging = false;
|
||||
private boolean mIsFlingScroll = false;
|
||||
private float mTouchY;
|
||||
private long mTouchDownTime;
|
||||
private int mCurrentScrollPosition;
|
||||
private int mSelectedItemPosition = 0;
|
||||
private OnItemSelectedListener mOnItemSelectedListener;
|
||||
private Rect mContentRect;
|
||||
protected Rect mPanelRect;
|
||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public OptionSelectorView(Context context) {
|
||||
super(context);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public OptionSelectorView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public OptionSelectorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
|
||||
private void initView(Context context) {
|
||||
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
|
||||
mMinimumVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
|
||||
mMaximumVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
|
||||
mClickTimeout = ViewConfiguration.getTapTimeout();
|
||||
mContentRect = new Rect(0, 0, 0, 0);
|
||||
mPanelRect = new Rect(0, 0, 0, 0);
|
||||
mScroller = new Scroller(context);
|
||||
mScroller.setFriction(DEFAULT_FRICTION);
|
||||
mMinScrollY = 0;
|
||||
}
|
||||
|
||||
public void setData(List<String> data, int selectPosition) {
|
||||
mScroller.forceFinished(true);
|
||||
mData = data;
|
||||
mCurrentScrollPosition = mSelectedItemPosition = selectPosition;
|
||||
mScrollOffsetY = DEFAULT_ITEM_HEIGHT * selectPosition;
|
||||
mMaxScrollY = (mData.size() - 1) * DEFAULT_ITEM_HEIGHT;
|
||||
invalidateAndCheckItemChange();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
reSetRect();
|
||||
}
|
||||
|
||||
private void reSetRect() {
|
||||
mContentRect.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
|
||||
mPanelRect.set(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
initVelocityTracker(event);
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (getParent() != null) {
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
if (!mScroller.isFinished()) {
|
||||
mScroller.forceFinished(true);
|
||||
}
|
||||
mIsDragging = true;
|
||||
mTouchY = event.getY();
|
||||
mTouchDownTime = System.currentTimeMillis();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float currentY = event.getY();
|
||||
float dy = currentY - mTouchY;
|
||||
if (Math.abs(dy) < 1) {
|
||||
break;
|
||||
}
|
||||
scroll((int) -dy);
|
||||
mTouchY = currentY;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
mIsDragging = false;
|
||||
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||
float velocityY = mVelocityTracker.getYVelocity();
|
||||
if (Math.abs(velocityY) > mMinimumVelocity) {
|
||||
mScroller.forceFinished(true);
|
||||
mIsFlingScroll = true;
|
||||
mScroller.fling(0, mScrollOffsetY, 0, (int) -velocityY, 0, 0,
|
||||
mMinScrollY, mMaxScrollY);
|
||||
fixBounceEffect();
|
||||
} else {
|
||||
//点击位置和中心点的y轴距离
|
||||
int clickOffset = 0;
|
||||
if (System.currentTimeMillis() - mTouchDownTime <= mClickTimeout) {
|
||||
clickOffset = (int) (event.getY() - getHeight() / 2);
|
||||
}
|
||||
int scrollDistance = clickOffset + calculateDistanceNeedToScroll((mScrollOffsetY + clickOffset) % DEFAULT_ITEM_HEIGHT);
|
||||
|
||||
if (scrollDistance <= 0) {
|
||||
scrollDistance = Math.max(scrollDistance, -mScrollOffsetY);
|
||||
} else {
|
||||
scrollDistance = Math.min(scrollDistance, mMaxScrollY - mScrollOffsetY);
|
||||
}
|
||||
mScroller.startScroll(0, mScrollOffsetY, 0, scrollDistance);
|
||||
|
||||
}
|
||||
invalidateAndCheckItemChange();
|
||||
ViewCompat.postOnAnimation(this, this);
|
||||
recycleVelocityTracker();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
recycleVelocityTracker();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//停止滚动后更新状态
|
||||
if (mScroller.isFinished() && !mIsDragging && !mIsFlingScroll) {
|
||||
int currentItemPosition = getCurrentPosition();
|
||||
if (currentItemPosition == mSelectedItemPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentScrollPosition = mSelectedItemPosition = currentItemPosition;
|
||||
|
||||
//选中监听回调
|
||||
if (mOnItemSelectedListener != null && mData != null && mData.size() > mSelectedItemPosition) {
|
||||
mOnItemSelectedListener.onItemSelected(mData.get(mSelectedItemPosition), mSelectedItemPosition);
|
||||
}
|
||||
}
|
||||
|
||||
if (mScroller.computeScrollOffset()) {
|
||||
mScrollOffsetY = mScroller.getCurrY();
|
||||
invalidateAndCheckItemChange();
|
||||
ViewCompat.postOnAnimation(this, this);
|
||||
} else if (mIsFlingScroll) {
|
||||
//快速滚动后调整选中位置到中心
|
||||
mIsFlingScroll = false;
|
||||
mScroller.startScroll(0, mScrollOffsetY, 0, calculateDistanceNeedToScroll(mScrollOffsetY % DEFAULT_ITEM_HEIGHT));
|
||||
invalidateAndCheckItemChange();
|
||||
ViewCompat.postOnAnimation(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (mContentRect.width() == 0) {
|
||||
reSetRect();
|
||||
}
|
||||
drawDivider(canvas);
|
||||
//已滚动item数
|
||||
int scrolledItem;
|
||||
//没有滚动完的item偏移值
|
||||
int scrolledOffset;
|
||||
scrolledItem = mScrollOffsetY / DEFAULT_ITEM_HEIGHT;
|
||||
scrolledOffset = mScrollOffsetY % DEFAULT_ITEM_HEIGHT;
|
||||
|
||||
int half = (DEFAULT_VISIBLE_ITEM_NUM + 1) / 2;
|
||||
//绘制的第一个选项下标
|
||||
int firstItemIndex = scrolledItem - half + (mScrollOffsetY > 0 ? 1 : 0);
|
||||
//绘制的最后一个选项下标
|
||||
int lastItemIndex = scrolledItem + half;
|
||||
|
||||
for (int i = firstItemIndex; i <= lastItemIndex; i++) {
|
||||
drawItem(canvas, i, scrolledOffset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void drawItem(Canvas canvas, int index, int scrolledOffset) {
|
||||
String text = getTextByIndex(index);
|
||||
if (text == null) {
|
||||
return;
|
||||
}
|
||||
//item 与中间项的偏移
|
||||
int item2CenterOffsetY;
|
||||
item2CenterOffsetY = (index - mScrollOffsetY / DEFAULT_ITEM_HEIGHT) * DEFAULT_ITEM_HEIGHT - scrolledOffset;
|
||||
float textSize = mMaxTextSize - ((mMaxTextSize - mMinTextSize) / mHalfShowHeight * Math.abs(item2CenterOffsetY));
|
||||
mPaint.setTextSize((float) Math.floor(textSize));
|
||||
int textColor = evaluate(Math.abs(item2CenterOffsetY) * 1.0f / mHalfShowHeight, DEFAULT_START_ITEM_COLOR, DEFAULT_END_TEXT_COLOR);
|
||||
mPaint.setColor(textColor);
|
||||
int textHeightHalf = (int) ((mPaint.getFontMetrics().descent + mPaint.getFontMetrics().ascent) / 2);
|
||||
|
||||
mPaint.setTextAlign(Paint.Align.CENTER);
|
||||
canvas.clipRect(mContentRect);
|
||||
canvas.drawText(text, mContentRect.centerX(), mContentRect.centerY() + item2CenterOffsetY - textHeightHalf, mPaint);
|
||||
}
|
||||
|
||||
|
||||
private void drawDivider(Canvas canvas) {
|
||||
//没有设置分割线颜色时跳过绘制
|
||||
if (DEFAULT_DIVIDER_COLOR == Color.TRANSPARENT) {
|
||||
return;
|
||||
}
|
||||
mPaint.setColor(DEFAULT_DIVIDER_COLOR);
|
||||
mPaint.setStrokeWidth(1);
|
||||
canvas.drawLine(mContentRect.left, mContentRect.centerY() - (DEFAULT_ITEM_HEIGHT >> 1), mContentRect.right, mContentRect.centerY() - (DEFAULT_ITEM_HEIGHT >> 1), mPaint);
|
||||
canvas.drawLine(mContentRect.left, mContentRect.centerY() + (DEFAULT_ITEM_HEIGHT >> 1), mContentRect.right, mContentRect.centerY() + (DEFAULT_ITEM_HEIGHT >> 1), mPaint);
|
||||
}
|
||||
|
||||
public int evaluate(float fraction, int startValue, int endValue) {
|
||||
float startA = ((startValue >> 24) & 0xff) / 255.0f;
|
||||
float startR = ((startValue >> 16) & 0xff) / 255.0f;
|
||||
float startG = ((startValue >> 8) & 0xff) / 255.0f;
|
||||
float startB = (startValue & 0xff) / 255.0f;
|
||||
|
||||
float endA = ((endValue >> 24) & 0xff) / 255.0f;
|
||||
float endR = ((endValue >> 16) & 0xff) / 255.0f;
|
||||
float endG = ((endValue >> 8) & 0xff) / 255.0f;
|
||||
float endB = (endValue & 0xff) / 255.0f;
|
||||
|
||||
// convert from sRGB to linear
|
||||
startR = (float) Math.pow(startR, 2.2);
|
||||
startG = (float) Math.pow(startG, 2.2);
|
||||
startB = (float) Math.pow(startB, 2.2);
|
||||
|
||||
endR = (float) Math.pow(endR, 2.2);
|
||||
endG = (float) Math.pow(endG, 2.2);
|
||||
endB = (float) Math.pow(endB, 2.2);
|
||||
|
||||
// compute the interpolated color in linear space
|
||||
float a = startA + fraction * (endA - startA);
|
||||
float r = startR + fraction * (endR - startR);
|
||||
float g = startG + fraction * (endG - startG);
|
||||
float b = startB + fraction * (endB - startB);
|
||||
|
||||
// convert back to sRGB in the [0..255] range
|
||||
a = a * 255.0f;
|
||||
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
|
||||
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
|
||||
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;
|
||||
|
||||
return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
|
||||
}
|
||||
|
||||
private String getTextByIndex(int index) {
|
||||
|
||||
|
||||
if (mData != null && index >= 0 && index < mData.size()) {
|
||||
return mData.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void initVelocityTracker(MotionEvent event) {
|
||||
if (mVelocityTracker == null) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
}
|
||||
mVelocityTracker.addMovement(event);
|
||||
}
|
||||
|
||||
private void recycleVelocityTracker() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void scroll(int distance) {
|
||||
mScrollOffsetY += distance;
|
||||
mScrollOffsetY = Math.min(mMaxScrollY, Math.max(mMinScrollY, mScrollOffsetY));
|
||||
invalidateAndCheckItemChange();
|
||||
}
|
||||
|
||||
private void invalidateAndCheckItemChange() {
|
||||
invalidate();
|
||||
int currentPosition = getCurrentPosition();
|
||||
if (mCurrentScrollPosition != currentPosition) {
|
||||
mCurrentScrollPosition = currentPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private int getCurrentPosition() {
|
||||
int itemPosition;
|
||||
if (mScrollOffsetY < 0) {
|
||||
itemPosition = (mScrollOffsetY - DEFAULT_ITEM_HEIGHT / 2) / DEFAULT_ITEM_HEIGHT;
|
||||
} else {
|
||||
itemPosition = (mScrollOffsetY + DEFAULT_ITEM_HEIGHT / 2) / DEFAULT_ITEM_HEIGHT;
|
||||
}
|
||||
int currentPosition = itemPosition % mData.size();
|
||||
if (currentPosition < 0) {
|
||||
currentPosition += mData.size();
|
||||
}
|
||||
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
private int calculateDistanceNeedToScroll(int offset) {
|
||||
//超过item高度一半,需要滚动一个item
|
||||
if (Math.abs(offset) > DEFAULT_ITEM_HEIGHT / 2) {
|
||||
if (mScrollOffsetY < 0) {
|
||||
return -DEFAULT_ITEM_HEIGHT - offset;
|
||||
} else {
|
||||
return DEFAULT_ITEM_HEIGHT - offset;
|
||||
}
|
||||
}
|
||||
//当前item回到中心距离
|
||||
else {
|
||||
return -offset;
|
||||
}
|
||||
}
|
||||
|
||||
private void fixBounceEffect() {
|
||||
//修正快速滑动最后停止位置,没有回弹效果
|
||||
int stopOffset = mScroller.getFinalY();
|
||||
int itemScrollOffset = Math.abs(stopOffset % DEFAULT_ITEM_HEIGHT);
|
||||
|
||||
//如果滚动偏移超过半个item高度,停止位置加一item高度
|
||||
if (itemScrollOffset > DEFAULT_ITEM_HEIGHT >> 1) {
|
||||
if (stopOffset < 0) {
|
||||
stopOffset = stopOffset / DEFAULT_ITEM_HEIGHT * DEFAULT_ITEM_HEIGHT - DEFAULT_ITEM_HEIGHT;
|
||||
} else {
|
||||
stopOffset = stopOffset / DEFAULT_ITEM_HEIGHT * DEFAULT_ITEM_HEIGHT + DEFAULT_ITEM_HEIGHT;
|
||||
}
|
||||
} else {
|
||||
stopOffset = stopOffset / DEFAULT_ITEM_HEIGHT * DEFAULT_ITEM_HEIGHT;
|
||||
|
||||
}
|
||||
mScroller.setFinalY(stopOffset);
|
||||
}
|
||||
|
||||
private void draw3DItemText(Canvas canvas, String text, int item2CenterOffsetY, int textHeightHalf) {
|
||||
canvas.save();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
|
||||
mOnItemSelectedListener = onItemSelectedListener;
|
||||
}
|
||||
|
||||
public interface OnItemSelectedListener {
|
||||
void onItemSelected(String data, int position);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dp宽度转像素值
|
||||
*/
|
||||
public float dip2px(float dpValue) {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics());
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字大小转像素值
|
||||
*/
|
||||
public float sp2px(float spValue) {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, Resources.getSystem().getDisplayMetrics());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.alivc.live.commonui.configview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.commonui.avdialog.AVLiveBaseBottomSheetDialog;
|
||||
import com.alivc.live.commonutils.DensityUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PushConfigBottomSheetLive extends AVLiveBaseBottomSheetDialog {
|
||||
private OptionSelectorView mOptionSelectorView;
|
||||
private int mSelectIndex;
|
||||
private String mTips;
|
||||
|
||||
public PushConfigBottomSheetLive(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public PushConfigBottomSheetLive(Context context, int theme) {
|
||||
super(context, theme);
|
||||
}
|
||||
|
||||
protected PushConfigBottomSheetLive(Context context, boolean cancelable, DialogInterface.OnCancelListener cancelListener) {
|
||||
super(context, cancelable, cancelListener);
|
||||
}
|
||||
|
||||
public void setData(List<String> data, int defaultPosition) {
|
||||
mSelectIndex = defaultPosition;
|
||||
mTips = data.get(defaultPosition);
|
||||
mOptionSelectorView.setData(data, defaultPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getContentView() {
|
||||
View rootView = getLayoutInflater().inflate(R.layout.push_config_dialog, null, false);
|
||||
mOptionSelectorView = rootView.findViewById(R.id.optionSelectorView);
|
||||
mOptionSelectorView.setOnItemSelectedListener(new OptionSelectorView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(String data, int position) {
|
||||
mSelectIndex = position;
|
||||
mTips = data;
|
||||
}
|
||||
});
|
||||
rootView.findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
rootView.findViewById(R.id.confirm_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mOnPushConfigSelectorListener != null) {
|
||||
mOnPushConfigSelectorListener.confirm(mTips, mSelectIndex);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams getContentLayoutParams() {
|
||||
return new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DensityUtil.dip2px(getContext(), 304));
|
||||
}
|
||||
|
||||
private OnPushConfigSelectorListener mOnPushConfigSelectorListener;
|
||||
|
||||
public void setOnPushConfigSelectorListener(OnPushConfigSelectorListener onPushConfigSelectorListener) {
|
||||
mOnPushConfigSelectorListener = onPushConfigSelectorListener;
|
||||
}
|
||||
|
||||
public interface OnPushConfigSelectorListener {
|
||||
void confirm(String data, int index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.alivc.live.commonui.configview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PushConfigDialogImpl {
|
||||
private PushConfigBottomSheetLive mDialog;
|
||||
|
||||
@Nullable
|
||||
private List<String> getTips(Context context, int id) {
|
||||
if (id == R.id.quality_modes) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.quality_resolution_first),
|
||||
context.getResources().getString(R.string.quality_fluency_first),
|
||||
context.getResources().getString(R.string.quality_custom));
|
||||
} else if (id == R.id.audio_channel) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.single_track), context.getResources().getString(R.string.dual_track));
|
||||
} else if (id == R.id.audio_profiles) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.setting_audio_aac_lc),
|
||||
context.getResources().getString(R.string.setting_audio_aac_he),
|
||||
context.getResources().getString(R.string.setting_audio_aac_hev2),
|
||||
context.getResources().getString(R.string.setting_audio_aac_ld));
|
||||
} else if (id == R.id.video_encoder_type) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.h264),
|
||||
context.getResources().getString(R.string.h265));
|
||||
} else if (id == R.id.b_frame_num) {
|
||||
return Arrays.asList("0", "1", "3");
|
||||
} else if (id == R.id.main_orientation) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.portrait), context.getResources().getString(R.string.homeLeft), context.getResources().getString(R.string.homeRight));
|
||||
} else if (id == R.id.setting_display_mode) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.display_mode_full), context.getResources().getString(R.string.display_mode_fit), context.getResources().getString(R.string.display_mode_cut));
|
||||
} else if (id == R.id.push_mode) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.video_push_streaming), context.getResources().getString(R.string.audio_only_push_streaming), context.getResources().getString(R.string.video_only_push_streaming));
|
||||
} else if (id == R.id.setting_camera_capture_output_preference) {
|
||||
return Arrays.asList(context.getResources().getString(R.string.camera_capture_output_preference_auto), context.getResources().getString(R.string.camera_capture_output_preference_performance), context.getResources().getString(R.string.camera_capture_output_preference_preview));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void showConfigDialog(View view, PushConfigBottomSheetLive.OnPushConfigSelectorListener configSelectorListener, int defaultPosition) {
|
||||
int selectPosition = defaultPosition;
|
||||
List<String> tips = getTips(view.getContext(), view.getId());
|
||||
if (tips == null || defaultPosition >= tips.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (mDialog == null) {
|
||||
mDialog = new PushConfigBottomSheetLive(view.getContext(), R.style.Live_BottomSheetDialog);
|
||||
}
|
||||
Object lastIndex = view.getTag();
|
||||
if (lastIndex instanceof Integer) {
|
||||
selectPosition = (int) lastIndex;
|
||||
}
|
||||
mDialog.setData(tips, selectPosition);
|
||||
mDialog.setOnPushConfigSelectorListener(new PushConfigBottomSheetLive.OnPushConfigSelectorListener() {
|
||||
@Override
|
||||
public void confirm(String data, int index) {
|
||||
view.setTag(index);
|
||||
if (view instanceof TextView) {
|
||||
((TextView) view).setText(data);
|
||||
}
|
||||
if (configSelectorListener != null) {
|
||||
configSelectorListener.confirm(data, index);
|
||||
}
|
||||
}
|
||||
});
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mDialog != null && mDialog.isShowing()) {
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
package com.alivc.live.commonui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.commonutils.DensityUtil;
|
||||
import com.alivc.live.commonutils.TextFormatUtil;
|
||||
|
||||
public class CommonDialog extends Dialog {
|
||||
private TextView titleText;
|
||||
private TextView tipContent;
|
||||
private LinearLayout contentLayout;
|
||||
private FrameLayout contentContainer2;
|
||||
private ScrollView contentContainer;
|
||||
private FrameLayout expandContainer;
|
||||
private View btnTopLine;
|
||||
private TextView cancelButton;
|
||||
private View btnLine;
|
||||
private TextView confirmButton;
|
||||
private int buttonCount;
|
||||
|
||||
public CommonDialog(@NonNull Context context) {
|
||||
this(context, R.style.DialogStyle);
|
||||
}
|
||||
|
||||
public CommonDialog(@NonNull Context context, int themeResId) {
|
||||
super(context, themeResId);
|
||||
this.initView();
|
||||
}
|
||||
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Window window = this.getWindow();
|
||||
window.setGravity(17);
|
||||
LayoutParams params = window.getAttributes();
|
||||
params.width = -1;
|
||||
params.height = -2;
|
||||
window.setAttributes(params);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (!this.isShowing()) {
|
||||
if (this.buttonCount == 0) {
|
||||
this.btnLine.setVisibility(View.GONE);
|
||||
this.btnTopLine.setVisibility(View.GONE);
|
||||
this.setDialogCancelable(true);
|
||||
} else if (this.buttonCount == 1) {
|
||||
this.btnLine.setVisibility(View.GONE);
|
||||
this.btnTopLine.setVisibility(View.VISIBLE);
|
||||
} else if (this.buttonCount == 2) {
|
||||
this.btnLine.setVisibility(View.VISIBLE);
|
||||
this.btnTopLine.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
super.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (this.isShowing()) {
|
||||
super.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
View tipDialogView = this.getLayoutInflater().inflate(R.layout.common_dialog, null);
|
||||
this.titleText = (TextView) tipDialogView.findViewById(R.id.dialog_title);
|
||||
this.contentLayout = (LinearLayout) tipDialogView.findViewById(R.id.dialog_content_layout);
|
||||
this.contentContainer2 = (FrameLayout) tipDialogView.findViewById(R.id.dialog_content_container2);
|
||||
this.contentContainer = (ScrollView) tipDialogView.findViewById(R.id.dialog_content_container);
|
||||
this.tipContent = (TextView) tipDialogView.findViewById(R.id.dialog_tip_content);
|
||||
this.expandContainer = (FrameLayout) tipDialogView.findViewById(R.id.dialog_expand_content_container);
|
||||
this.btnTopLine = tipDialogView.findViewById(R.id.dialog_btn_top_line);
|
||||
this.cancelButton = (TextView) tipDialogView.findViewById(R.id.dialog_cancel_btn);
|
||||
this.btnLine = tipDialogView.findViewById(R.id.dialog_btn_line);
|
||||
this.confirmButton = (TextView) tipDialogView.findViewById(R.id.dialog_confirm_btn);
|
||||
View bottomSpace = tipDialogView.findViewById(R.id.dialog_bottom_space);
|
||||
int space = (int) ((double) DensityUtil.getDisplayMetrics(this.getContext()).heightPixels * 0.05D);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-1, space);
|
||||
bottomSpace.setLayoutParams(params);
|
||||
this.setContentView(tipDialogView);
|
||||
}
|
||||
|
||||
public CommonDialog setDialogCancelable(boolean cancelable) {
|
||||
this.setCancelable(cancelable);
|
||||
this.setCanceledOnTouchOutside(cancelable);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogTitle(int title) {
|
||||
CharSequence titleStr = title == 0 ? "" : TextFormatUtil.getTextFormat(this.getContext(), title);
|
||||
return this.setDialogTitle(titleStr);
|
||||
}
|
||||
|
||||
public CommonDialog setDialogTitle(CharSequence title) {
|
||||
if (this.titleText != null && !TextUtils.isEmpty(title)) {
|
||||
this.titleText.setText(title);
|
||||
this.titleText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogTitleGravity(int gravity) {
|
||||
if (this.titleText != null) {
|
||||
this.titleText.setGravity(gravity);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogTitleMaxLines(int lines) {
|
||||
if (this.titleText != null && lines > 0) {
|
||||
this.setDialogTitleLinesNoLimit();
|
||||
this.titleText.setMaxLines(lines);
|
||||
this.titleText.setEllipsize(TruncateAt.END);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogTitleLinesNoLimit() {
|
||||
if (this.titleText != null) {
|
||||
this.titleText.setSingleLine(false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogContentGravity(int gravity) {
|
||||
if (this.tipContent != null) {
|
||||
this.tipContent.setGravity(gravity);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogContent(int tip) {
|
||||
CharSequence tipStr = tip == 0 ? "" : TextFormatUtil.getTextFormat(this.getContext(), tip);
|
||||
return this.setDialogContent(tipStr);
|
||||
}
|
||||
|
||||
public CommonDialog setDialogContent(CharSequence tip) {
|
||||
if (this.tipContent != null && !TextUtils.isEmpty(tip)) {
|
||||
this.tipContent.setText(tip);
|
||||
this.contentLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogContentView(View contentView) {
|
||||
if (this.contentContainer != null && contentView != null) {
|
||||
this.contentContainer.removeAllViews();
|
||||
this.contentContainer.addView(contentView);
|
||||
this.contentLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setDialogContentView2(View contentView) {
|
||||
if (this.contentContainer2 != null && contentView != null) {
|
||||
this.contentContainer2.removeAllViews();
|
||||
this.contentContainer2.addView(contentView);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setExpandView(View expandView) {
|
||||
if (this.expandContainer != null && expandView != null) {
|
||||
this.expandContainer.removeAllViews();
|
||||
this.expandContainer.addView(expandView);
|
||||
this.expandContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setCancelButton(int cancel, OnClickListener listener) {
|
||||
return this.setCancelButton(cancel, 0, listener);
|
||||
}
|
||||
|
||||
public CommonDialog setCancelButton(int cancel, int color, OnClickListener listener) {
|
||||
CharSequence cancelStr = cancel == 0 ? "" : TextFormatUtil.getTextFormat(this.getContext(), cancel);
|
||||
return this.setCancelButton(cancelStr, color, listener);
|
||||
}
|
||||
|
||||
public CommonDialog setCancelButton(CharSequence cancel, OnClickListener listener) {
|
||||
this.setCancelButton(cancel, 0, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setCancelButton(CharSequence cancel, int color, final OnClickListener listener) {
|
||||
if (this.cancelButton != null && !TextUtils.isEmpty(cancel)) {
|
||||
this.cancelButton.setText(cancel);
|
||||
if (color != 0) {
|
||||
this.cancelButton.setTextColor(color);
|
||||
}
|
||||
|
||||
this.cancelButton.setVisibility(View.VISIBLE);
|
||||
++this.buttonCount;
|
||||
if (this.cancelButton != null) {
|
||||
this.cancelButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
CommonDialog.this.dismiss();
|
||||
if (listener != null) {
|
||||
listener.onClick(CommonDialog.this, -2);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setConfirmButton(int confirm, OnClickListener listener) {
|
||||
return this.setConfirmButton(confirm, 0, listener);
|
||||
}
|
||||
|
||||
public CommonDialog setConfirmButton(int confirm, int color, OnClickListener listener) {
|
||||
CharSequence confirmStr = confirm == 0 ? "" : TextFormatUtil.getTextFormat(this.getContext(), confirm);
|
||||
return this.setConfirmButton(confirmStr, color, listener);
|
||||
}
|
||||
|
||||
public CommonDialog setConfirmButton(CharSequence confirm, OnClickListener listener) {
|
||||
this.setConfirmButton(confirm, 0, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommonDialog setConfirmButton(CharSequence confirm, int color, final OnClickListener listener) {
|
||||
if (this.confirmButton != null && !TextUtils.isEmpty(confirm)) {
|
||||
this.confirmButton.setText(confirm);
|
||||
if (color != 0) {
|
||||
this.confirmButton.setTextColor(color);
|
||||
}
|
||||
|
||||
this.confirmButton.setVisibility(View.VISIBLE);
|
||||
++this.buttonCount;
|
||||
this.confirmButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
CommonDialog.this.dismiss();
|
||||
if (listener != null) {
|
||||
listener.onClick(CommonDialog.this, -1);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.alivc.live.commonui.dialog;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.commonutils.DensityUtil;
|
||||
|
||||
/**
|
||||
* 设置最大高度的Layout
|
||||
*/
|
||||
public class MaxHeightLayout extends LinearLayout {
|
||||
|
||||
private float mMaxRatio = 0.75f;
|
||||
private float mMaxHeight;
|
||||
private float mMinHeight;
|
||||
|
||||
public MaxHeightLayout(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public MaxHeightLayout(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initAtts(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public MaxHeightLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initAtts(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private void initAtts(Context context, AttributeSet attrs) {
|
||||
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.mMaxRatio);
|
||||
if (attributes != null) {
|
||||
mMaxRatio = attributes.getFloat(R.styleable.mMaxRatio_linear_max_ratio, 0.75f);
|
||||
attributes.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mMaxHeight = mMaxRatio * DensityUtil.getDisplayMetrics(getContext()).heightPixels;
|
||||
mMinHeight = DensityUtil.dip2px(getContext(), 125);
|
||||
mMaxHeight = mMaxHeight < mMinHeight ? mMinHeight : mMaxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
if (heightMode == MeasureSpec.EXACTLY) {
|
||||
heightSize = heightSize <= mMaxHeight ? heightSize : (int) mMaxHeight;
|
||||
}
|
||||
|
||||
if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
heightSize = heightSize <= mMaxHeight ? heightSize : (int) mMaxHeight;
|
||||
}
|
||||
|
||||
if (heightMode == MeasureSpec.AT_MOST) {
|
||||
heightSize = heightSize <= mMaxHeight ? heightSize : (int) mMaxHeight;
|
||||
}
|
||||
int maxHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
|
||||
super.onMeasure(widthMeasureSpec, maxHeightMeasureSpec);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.alivc.live.commonui.messageview;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 自动追加滚动消息视图适配器
|
||||
*/
|
||||
public class AutoScrollMessagesAdapter extends RecyclerView.Adapter<AutoScrollMessagesAdapter.RecyclerViewHolder> {
|
||||
private @NonNull
|
||||
ArrayList<String> msgList = new ArrayList<String>();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
View view = layoutInflater.inflate(R.layout.layout_callback_message, parent, false);
|
||||
return new RecyclerViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
|
||||
holder.applyTextMsg(msgList.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return msgList.size();
|
||||
}
|
||||
|
||||
public void applyDataMessage(String msg) {
|
||||
msgList.add(msg);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
static class RecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView mTextView;
|
||||
|
||||
RecyclerViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
mTextView = itemView.findViewById(R.id.text_msg);
|
||||
}
|
||||
|
||||
public void applyTextMsg(String msg) {
|
||||
if (mTextView != null) {
|
||||
mTextView.setText(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.alivc.live.commonui.messageview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* 自动追加滚动消息视图
|
||||
*/
|
||||
public class AutoScrollMessagesView extends RecyclerView {
|
||||
private final AutoScrollMessagesAdapter mAdapter = new AutoScrollMessagesAdapter();
|
||||
|
||||
public AutoScrollMessagesView(@NonNull Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public AutoScrollMessagesView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AutoScrollMessagesView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initData();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
setLayoutManager(linearLayoutManager);
|
||||
setAdapter(mAdapter);
|
||||
|
||||
setDrawingCacheEnabled(true);
|
||||
setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
|
||||
}
|
||||
|
||||
public void appendMessage(String msg) {
|
||||
mAdapter.applyDataMessage(msg);
|
||||
smoothScrollToPosition(mAdapter.getItemCount());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.alivc.live.commonui.seiview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class LivePusherSEIView extends LinearLayout {
|
||||
private static final int DEFAULT_PAYLOAD_TYPE = 5;
|
||||
private static final String DEFAULT_SEI_MESSAGE = "010203=-./,_adcd-&^%$~@";
|
||||
|
||||
private EditText mPayloadEditText;
|
||||
private EditText mSeiEditText;
|
||||
private Button mSendSEIButton;
|
||||
|
||||
private SendSeiViewListener mListener;
|
||||
|
||||
public LivePusherSEIView(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public LivePusherSEIView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public LivePusherSEIView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
View inflateView = LayoutInflater.from(context).inflate(R.layout.push_sei_view_layout, this, true);
|
||||
|
||||
mPayloadEditText = inflateView.findViewById(R.id.et_sei_payload_type);
|
||||
mPayloadEditText.setText(String.valueOf(DEFAULT_PAYLOAD_TYPE));
|
||||
|
||||
mSeiEditText = inflateView.findViewById(R.id.et_sei);
|
||||
mSeiEditText.setText(DEFAULT_SEI_MESSAGE);
|
||||
|
||||
mSendSEIButton = inflateView.findViewById(R.id.btn_send_sei);
|
||||
mSendSEIButton.setOnClickListener(view -> {
|
||||
if (mListener != null) {
|
||||
// 如果输入框为空,默认输出指定的json格式以供测试
|
||||
String text = mSeiEditText.getText().toString();
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
text = DEFAULT_SEI_MESSAGE;
|
||||
}
|
||||
|
||||
// 如果输入框为空,默认payload type=5以供测试
|
||||
String payloadEdit = mPayloadEditText.getText().toString();
|
||||
int payload = DEFAULT_PAYLOAD_TYPE;
|
||||
Pattern pattern = Pattern.compile("[0-9]*");
|
||||
if (pattern.matcher(payloadEdit).matches()) {
|
||||
payload = Integer.parseInt(payloadEdit);
|
||||
}
|
||||
|
||||
mListener.onSendSeiClick(payload, text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface SendSeiViewListener {
|
||||
void onSendSeiClick(int payload, String text);
|
||||
}
|
||||
|
||||
public void setSendSeiViewListener(SendSeiViewListener mListener) {
|
||||
this.mListener = mListener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class DensityUtil {
|
||||
private static final String TAG = DensityUtil.class.getSimpleName();
|
||||
/**
|
||||
* dp、sp 转换为 px 的工具类
|
||||
*
|
||||
* @author fxsky 2012.11.12
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* 将px值转换为dip或dp值,保证尺寸大小不变
|
||||
*
|
||||
* @param pxValue
|
||||
* @param scale (DisplayMetrics类中属性density)
|
||||
* @return
|
||||
*/
|
||||
public static int px2dip(Context context, float pxValue) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (pxValue / scale + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将dip或dp值转换为px值,保证尺寸大小不变
|
||||
*
|
||||
* @param dipValue
|
||||
* @param scale (DisplayMetrics类中属性density)
|
||||
* @return
|
||||
*/
|
||||
public static int dip2px(Context context, float dipValue) {
|
||||
if (context == null || context.getResources() == null)
|
||||
return 1;
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dipValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将px值转换为sp值,保证文字大小不变
|
||||
*
|
||||
* @param pxValue
|
||||
* @param fontScale (DisplayMetrics类中属性scaledDensity)
|
||||
* @return
|
||||
*/
|
||||
public static int px2sp(Context context, float pxValue) {
|
||||
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (pxValue / fontScale + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将sp值转换为px值,保证文字大小不变
|
||||
*
|
||||
* @param spValue
|
||||
* @param fontScale (DisplayMetrics类中属性scaledDensity)
|
||||
* @return
|
||||
*/
|
||||
public static int sp2px(Context context, float spValue) {
|
||||
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (spValue * fontScale + 0.5f);
|
||||
}
|
||||
|
||||
private static DisplayMetrics sDisplayMetrics;
|
||||
private static int sStatusBarHeight = -1;
|
||||
|
||||
public static DisplayMetrics getDisplayMetrics(Context context) {
|
||||
if (sDisplayMetrics == null) {
|
||||
sDisplayMetrics = context.getResources().getDisplayMetrics();
|
||||
}
|
||||
return sDisplayMetrics;
|
||||
}
|
||||
|
||||
public static int getStatusBarHeight(Context context) {
|
||||
if (sStatusBarHeight == -1) {
|
||||
try {
|
||||
Class<?> c = Class.forName("com.android.internal.R$dimen");
|
||||
Object o = c.newInstance();
|
||||
Field field = c.getField("status_bar_height");
|
||||
int x = (Integer) field.get(o);
|
||||
sStatusBarHeight = context.getResources().getDimensionPixelSize(x);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
} catch (InstantiationException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
} catch (NoSuchFieldException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
return sStatusBarHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取view的宽度
|
||||
*/
|
||||
public static int getViewWidth(View view) {
|
||||
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
|
||||
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
|
||||
return view.getMeasuredWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取view的高度
|
||||
*/
|
||||
public static int getViewHeight(View view) {
|
||||
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
|
||||
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
|
||||
return view.getMeasuredHeight();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取适配后的高度
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getScaleHeight(Context context, int srcHeight) {
|
||||
double realHeight = getScreenRealHeight(context);
|
||||
if (realHeight <= 0) {
|
||||
return srcHeight;
|
||||
}
|
||||
|
||||
if (realHeight >= 37) {// [37, +∞)
|
||||
srcHeight = (int) (srcHeight * 0.9 * 0.9 * 0.9);
|
||||
} else if (realHeight >= 33) {// [33, 37)
|
||||
srcHeight = (int) (srcHeight * 0.9 * 0.9);
|
||||
} else if (realHeight >= 27) {// [27, 33)
|
||||
srcHeight = (int) (srcHeight * 0.9);
|
||||
}
|
||||
// [0, 27]
|
||||
return srcHeight;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前手机屏幕的尺寸(单位:像素)
|
||||
*/
|
||||
public static double getScreenRealHeight(Context context) {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
|
||||
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Point point = new Point();
|
||||
manager.getDefaultDisplay().getRealSize(point);
|
||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
// dm.ydpi是屏幕y方向的真实密度值
|
||||
return new BigDecimal(Math.pow(point.y / dm.ydpi, 2)).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("DensityUtil", e.getMessage());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前手机屏幕的尺寸(单位:像素)
|
||||
*/
|
||||
public static double getScreenSize(Context context) {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
|
||||
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Point point = new Point();
|
||||
manager.getDefaultDisplay().getRealSize(point);
|
||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
// dm.xdpi是屏幕x方向的真实密度值
|
||||
double x = Math.pow(point.x / dm.xdpi, 2);
|
||||
// dm.ydpi是屏幕y方向的真实密度值
|
||||
double y = Math.pow(point.y / dm.ydpi, 2);
|
||||
return new BigDecimal(Math.sqrt(x + y)).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("DensityUtil", e.getMessage());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.alivc.live.commonui.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
public class StatusBarUtil {
|
||||
/**
|
||||
* 沉浸式状态栏。
|
||||
* 支持 4.4 以上版本的 MIUI 和 Flyme,以及 5.0 以上版本的其他 Android。
|
||||
*
|
||||
* @param activity 需要被设置沉浸式状态栏的 Activity。
|
||||
*/
|
||||
public static void translucent(Activity activity, @ColorInt int colorOn5x) {
|
||||
try {
|
||||
Window window = activity.getWindow();
|
||||
translucent(window, colorOn5x);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TargetApi(19)
|
||||
private static void translucent(Window window, @ColorInt int colorOn5x) {
|
||||
if (isNotchOfficialSupport()) {
|
||||
handleDisplayCutoutMode(window);
|
||||
}
|
||||
int systemUiVisibility = window.getDecorView().getSystemUiVisibility();
|
||||
systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
||||
window.getDecorView().setSystemUiVisibility(systemUiVisibility);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// android 6以后可以改状态栏字体颜色,因此可以自行设置为透明
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@TargetApi(28)
|
||||
private static void handleDisplayCutoutMode(final Window window) {
|
||||
View decorView = window.getDecorView();
|
||||
if (decorView != null) {
|
||||
if (ViewCompat.isAttachedToWindow(decorView)) {
|
||||
realHandleDisplayCutoutMode(window, decorView);
|
||||
} else {
|
||||
decorView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
v.removeOnAttachStateChangeListener(this);
|
||||
realHandleDisplayCutoutMode(window, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(28)
|
||||
private static void realHandleDisplayCutoutMode(Window window, View decorView) {
|
||||
if (decorView.getRootWindowInsets() != null &&
|
||||
decorView.getRootWindowInsets().getDisplayCutout() != null) {
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams
|
||||
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
window.setAttributes(params);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNotchOfficialSupport(){
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.alivc.live.commonui.widgets;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.view.animation.RotateAnimation;
|
||||
import android.view.animation.ScaleAnimation;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
|
||||
public class AVLiveLoadingDialog extends Dialog {
|
||||
private Context context;
|
||||
private ImageView mIconView;
|
||||
private TextView mTipView;
|
||||
private CharSequence mTipMsg;
|
||||
|
||||
public AVLiveLoadingDialog(Context context) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.av_live_loading_dialog_layout, null, false);
|
||||
mIconView = view.findViewById(R.id.av_loading_dialog_icon);
|
||||
mTipView = view.findViewById(R.id.av_loading_dialog_tip);
|
||||
if (mTipMsg != null) {
|
||||
mTipView.setVisibility(View.VISIBLE);
|
||||
mTipView.setText(mTipMsg);
|
||||
} else {
|
||||
mTipView.setVisibility(View.GONE);
|
||||
}
|
||||
setContentView(view);
|
||||
|
||||
Window dialogWindow = getWindow();
|
||||
dialogWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
dialogWindow.setBackgroundDrawableResource(android.R.color.transparent);
|
||||
|
||||
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
|
||||
lp.alpha = 1.0f;
|
||||
lp.dimAmount = 0.0f;
|
||||
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
|
||||
lp.verticalMargin = 0.3f;
|
||||
dialogWindow.setAttributes(lp);
|
||||
|
||||
setCancelable(false);
|
||||
setCanceledOnTouchOutside(false);
|
||||
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
private void startAnimation() {
|
||||
if (mIconView == null || mIconView.getAnimation() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, RotateAnimation.RELATIVE_TO_SELF,
|
||||
0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
|
||||
//设置动画持续时长
|
||||
rotateAnimation.setDuration(1000);
|
||||
rotateAnimation.setInterpolator(new LinearInterpolator());
|
||||
//设置动画的重复模式:反转REVERSE和重新开始RESTART
|
||||
rotateAnimation.setRepeatMode(ScaleAnimation.RESTART);
|
||||
//设置动画播放次数
|
||||
rotateAnimation.setRepeatCount(ScaleAnimation.INFINITE);
|
||||
|
||||
//开始动画
|
||||
mIconView.startAnimation(rotateAnimation);
|
||||
}
|
||||
|
||||
private void stopAnimation() {
|
||||
if (mIconView == null || mIconView.getAnimation() == null) {
|
||||
return;
|
||||
}
|
||||
mIconView.clearAnimation();
|
||||
}
|
||||
|
||||
public AVLiveLoadingDialog tip(CharSequence tip) {
|
||||
mTipMsg = tip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
super.show();
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
stopAnimation();
|
||||
super.dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.alivc.live.commonui.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2024/5/23
|
||||
* @brief 带文字的按钮开关
|
||||
*/
|
||||
public class LivePushTextSwitch extends LinearLayout {
|
||||
|
||||
private TextView textView;
|
||||
private Switch switchView;
|
||||
|
||||
/**
|
||||
* 定义回调接口,用于监听 Switch 状态变化
|
||||
*/
|
||||
public interface OnSwitchToggleListener {
|
||||
void onSwitchToggled(boolean isChecked);
|
||||
}
|
||||
|
||||
private OnSwitchToggleListener onSwitchToggleListener;
|
||||
|
||||
public LivePushTextSwitch(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public LivePushTextSwitch(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public LivePushTextSwitch(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
// 设置横向布局
|
||||
setOrientation(HORIZONTAL);
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
textView = new TextView(context);
|
||||
textView.setTextColor(Color.WHITE);
|
||||
textView.setLines(1);
|
||||
textView.setTextSize(12);
|
||||
textView.setPadding(0, 0, 12, 0);
|
||||
|
||||
switchView = new Switch(context);
|
||||
switchView.setChecked(false);
|
||||
|
||||
// 设置 TextView 的布局参数,使其宽度包裹内容并且靠左对齐
|
||||
LayoutParams textViewLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
textViewLayoutParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
|
||||
|
||||
// 设置 Switch 的布局参数,使其宽度包裹内容并且靠右对齐
|
||||
LayoutParams switchLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
switchLayoutParams.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
|
||||
|
||||
textView.setLayoutParams(textViewLayoutParams);
|
||||
switchView.setLayoutParams(switchLayoutParams);
|
||||
|
||||
// 将 TextView 和 Switch 添加到布局中
|
||||
addView(textView);
|
||||
addView(switchView);
|
||||
|
||||
// 设置 Switch 的监听事件
|
||||
switchView.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if (onSwitchToggleListener != null) {
|
||||
onSwitchToggleListener.onSwitchToggled(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
setPadding(0, 3, 3, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置 TextView 的文本
|
||||
*/
|
||||
public void setTextViewText(String text) {
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置 Switch 的初始状态
|
||||
*/
|
||||
public void setSwitchChecked(boolean checked) {
|
||||
switchView.setChecked(checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置回调监听器
|
||||
*/
|
||||
public void setOnSwitchToggleListener(OnSwitchToggleListener listener) {
|
||||
this.onSwitchToggleListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.alivc.live.commonui.widgets;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Switch;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.alivc.live.commonui.R;
|
||||
import com.alivc.live.commonutils.FileUtil;
|
||||
import com.alivc.live.pusher.WaterMarkInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PushWaterMarkDialog extends DialogFragment {
|
||||
|
||||
private Switch mSwitch;
|
||||
private EditText mX;
|
||||
private EditText mY;
|
||||
private EditText mW;
|
||||
private Switch mSwitch1;
|
||||
private EditText mX1;
|
||||
private EditText mY1;
|
||||
private EditText mW1;
|
||||
private Switch mSwitch2;
|
||||
private EditText mX2;
|
||||
private EditText mY2;
|
||||
private EditText mW2;
|
||||
private ArrayList<WaterMarkInfo> mWaterMarkInfos;
|
||||
private WaterMarkInfo mWaterMarkInfo = new WaterMarkInfo();
|
||||
private WaterMarkInfo mWaterMarkInfo1 = new WaterMarkInfo();
|
||||
private WaterMarkInfo mWaterMarkInfo2 = new WaterMarkInfo();
|
||||
private boolean mWater = false;
|
||||
private boolean mWater1 = false;
|
||||
private boolean mWater2 = false;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
getDialog().getWindow().getAttributes().windowAnimations = R.style.dialog_animation;
|
||||
getDialog().setCanceledOnTouchOutside(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
View view = inflater.inflate(R.layout.push_watermark, container);
|
||||
mX = (EditText) view.findViewById(R.id.x);
|
||||
mY = (EditText) view.findViewById(R.id.y);
|
||||
mW = (EditText) view.findViewById(R.id.w);
|
||||
mX1 = (EditText) view.findViewById(R.id.x1);
|
||||
mY1 = (EditText) view.findViewById(R.id.y1);
|
||||
mW1 = (EditText) view.findViewById(R.id.w1);
|
||||
mX2 = (EditText) view.findViewById(R.id.x2);
|
||||
mY2 = (EditText) view.findViewById(R.id.y2);
|
||||
mW2 = (EditText) view.findViewById(R.id.w2);
|
||||
mSwitch = (Switch) view.findViewById(R.id.watermark);
|
||||
mSwitch1 = (Switch) view.findViewById(R.id.watermark1);
|
||||
mSwitch2 = (Switch) view.findViewById(R.id.watermark2);
|
||||
mSwitch.setOnCheckedChangeListener(onCheckedChangeListener);
|
||||
mSwitch1.setOnCheckedChangeListener(onCheckedChangeListener);
|
||||
mSwitch2.setOnCheckedChangeListener(onCheckedChangeListener);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
getDialog().getWindow().setGravity(Gravity.BOTTOM);
|
||||
super.onResume();
|
||||
|
||||
DisplayMetrics dpMetrics = new DisplayMetrics();
|
||||
getActivity().getWindow().getWindowManager().getDefaultDisplay().getMetrics(dpMetrics);
|
||||
WindowManager.LayoutParams p = getDialog().getWindow().getAttributes();
|
||||
|
||||
p.width = dpMetrics.widthPixels;
|
||||
p.height = dpMetrics.heightPixels * 2 / 3;
|
||||
getDialog().getWindow().setAttributes(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
if (mWaterMarkInfos == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
if (!mX.getText().toString().isEmpty() && !mY.getText().toString().isEmpty() && !mW.getText().toString().isEmpty()) {
|
||||
mWaterMarkInfo.mWaterMarkCoordX = Float.valueOf(mX.getText().toString());
|
||||
mWaterMarkInfo.mWaterMarkCoordY = Float.valueOf(mY.getText().toString());
|
||||
mWaterMarkInfo.mWaterMarkWidth = Float.valueOf(mW.getText().toString());
|
||||
mWaterMarkInfo.mWaterMarkPath = FileUtil.combinePaths(FileUtil.getInternalFilesFolder(getContext()), "alivc_resource/watermark.png");
|
||||
mWater = true;
|
||||
}
|
||||
|
||||
if (!mX1.getText().toString().isEmpty() && !mY1.getText().toString().isEmpty() && !mW1.getText().toString().isEmpty()) {
|
||||
mWaterMarkInfo1.mWaterMarkCoordX = Float.valueOf(mX1.getText().toString());
|
||||
mWaterMarkInfo1.mWaterMarkCoordY = Float.valueOf(mY1.getText().toString());
|
||||
mWaterMarkInfo1.mWaterMarkWidth = Float.valueOf(mW1.getText().toString());
|
||||
mWaterMarkInfo1.mWaterMarkPath = FileUtil.combinePaths(FileUtil.getInternalFilesFolder(getContext()), "alivc_resource/watermark.png");
|
||||
mWater1 = true;
|
||||
}
|
||||
|
||||
if (!mX2.getText().toString().isEmpty() && !mY2.getText().toString().isEmpty() && !mW2.getText().toString().isEmpty()) {
|
||||
mWaterMarkInfo2.mWaterMarkCoordX = Float.valueOf(mX2.getText().toString());
|
||||
mWaterMarkInfo2.mWaterMarkCoordY = Float.valueOf(mY2.getText().toString());
|
||||
mWaterMarkInfo2.mWaterMarkWidth = Float.valueOf(mW2.getText().toString());
|
||||
mWaterMarkInfo2.mWaterMarkPath = FileUtil.combinePaths(FileUtil.getInternalFilesFolder(getContext()), "alivc_resource/watermark.png");
|
||||
mWater2 = true;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (mWaterMarkInfos.size() > 0) {
|
||||
mWaterMarkInfos.clear();
|
||||
}
|
||||
|
||||
if (mWater) {
|
||||
mWaterMarkInfos.add(mWaterMarkInfo);
|
||||
}
|
||||
if (mWater1) {
|
||||
mWaterMarkInfos.add(mWaterMarkInfo1);
|
||||
}
|
||||
if (mWater2) {
|
||||
mWaterMarkInfos.add(mWaterMarkInfo2);
|
||||
}
|
||||
}
|
||||
|
||||
public void setWaterMarkInfo(ArrayList<WaterMarkInfo> waterMarkInfos) {
|
||||
this.mWaterMarkInfos = waterMarkInfos;
|
||||
}
|
||||
|
||||
private final CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||
int id = compoundButton.getId();
|
||||
if (id == R.id.watermark) {
|
||||
mWater = b;
|
||||
} else if (id == R.id.watermark1) {
|
||||
mWater1 = b;
|
||||
} else if (id == R.id.watermark2) {
|
||||
mWater2 = b;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.alivc.live.commonui.widgets;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2024/7/9
|
||||
* @brief 可缩放的FrameLayout
|
||||
* @note 备注:该FrameLayout容器仅用于API测试,测试在不同FrameLayout切换策略下的表现及性能
|
||||
* @note 如果您对接直播连麦,可直接使用FrameLayout容器作为预览和拉流的渲染窗口
|
||||
*/
|
||||
public class ResizableFrameLayout extends FrameLayout {
|
||||
private static final int ANIMATION_DURATION = 200;
|
||||
|
||||
private int originalWidth;
|
||||
private int originalHeight;
|
||||
private boolean isResized = false;
|
||||
|
||||
private static final ResizeStrategy[] strategies = new ResizeStrategy[]{new HalveStrategy(), new EqualStrategy()};
|
||||
private ResizeStrategy currentStrategy;
|
||||
private final Random random = new Random();
|
||||
|
||||
public ResizableFrameLayout(Context context) {
|
||||
super(context);
|
||||
|
||||
initializeDefaultStrategy();
|
||||
}
|
||||
|
||||
public ResizableFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
initializeDefaultStrategy();
|
||||
}
|
||||
|
||||
public ResizableFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
initializeDefaultStrategy();
|
||||
}
|
||||
|
||||
private void initializeDefaultStrategy() {
|
||||
currentStrategy = new HalveStrategy(); // 默认为缩放策略
|
||||
}
|
||||
|
||||
public void resize() {
|
||||
useRandomStrategy();
|
||||
toggleSize();
|
||||
}
|
||||
|
||||
public void resize(ResizeStrategy strategy) {
|
||||
setResizeStrategy(strategy);
|
||||
toggleSize();
|
||||
}
|
||||
|
||||
private void toggleSize() {
|
||||
// 保存原始宽高
|
||||
if (originalWidth == 0 || originalHeight == 0) {
|
||||
originalWidth = getWidth();
|
||||
originalHeight = getHeight();
|
||||
}
|
||||
|
||||
// 根据策略计算目标宽高
|
||||
int targetWidth = isResized ? originalWidth : currentStrategy.getTargetWidth(originalWidth, originalHeight);
|
||||
int targetHeight = isResized ? originalHeight : currentStrategy.getTargetHeight(originalWidth, originalHeight);
|
||||
|
||||
// 创建动画
|
||||
animateResize(targetWidth, targetHeight);
|
||||
|
||||
// 切换标志位
|
||||
isResized = !isResized;
|
||||
}
|
||||
|
||||
private void animateResize(int targetWidth, int targetHeight) {
|
||||
ValueAnimator widthAnimator = ValueAnimator.ofInt(getWidth(), targetWidth);
|
||||
ValueAnimator heightAnimator = ValueAnimator.ofInt(getHeight(), targetHeight);
|
||||
|
||||
widthAnimator.addUpdateListener(animation -> {
|
||||
ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
layoutParams.width = (int) animation.getAnimatedValue();
|
||||
setLayoutParams(layoutParams);
|
||||
});
|
||||
|
||||
heightAnimator.addUpdateListener(animation -> {
|
||||
ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
layoutParams.height = (int) animation.getAnimatedValue();
|
||||
setLayoutParams(layoutParams);
|
||||
});
|
||||
|
||||
widthAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
heightAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
widthAnimator.setDuration(ANIMATION_DURATION);
|
||||
heightAnimator.setDuration(ANIMATION_DURATION);
|
||||
|
||||
widthAnimator.start();
|
||||
heightAnimator.start();
|
||||
}
|
||||
|
||||
public void setResizeStrategy(ResizeStrategy strategy) {
|
||||
this.currentStrategy = strategy;
|
||||
}
|
||||
|
||||
public void useRandomStrategy() {
|
||||
int randomIndex = random.nextInt(strategies.length);
|
||||
setResizeStrategy(strategies[randomIndex]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放策略(宽高除以2策略)
|
||||
*/
|
||||
public static class HalveStrategy implements ResizeStrategy {
|
||||
@Override
|
||||
public int getTargetWidth(int originalWidth, int originalHeight) {
|
||||
return originalWidth / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetHeight(int originalWidth, int originalHeight) {
|
||||
return originalHeight / 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 正方形策略(宽高相等)
|
||||
*/
|
||||
public static class EqualStrategy implements ResizeStrategy {
|
||||
@Override
|
||||
public int getTargetWidth(int originalWidth, int originalHeight) {
|
||||
return Math.min(originalWidth, originalHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetHeight(int originalWidth, int originalHeight) {
|
||||
return Math.min(originalWidth, originalHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ResizeStrategy {
|
||||
int getTargetWidth(int originalWidth, int originalHeight);
|
||||
|
||||
int getTargetHeight(int originalWidth, int originalHeight);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:duration="500"
|
||||
android:fillAfter="true"
|
||||
android:fromXDelta="0.0"
|
||||
android:fromYDelta="0.0"
|
||||
android:toXDelta="0.0"
|
||||
android:toYDelta="100.0%p" />
|
||||
</set>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="256"
|
||||
android:fillAfter="true"
|
||||
android:fromXDelta="0.0"
|
||||
android:fromYDelta="100.0%"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||
android:toXDelta="0.0"
|
||||
android:toYDelta="0.0" />
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 678 B |
|
After Width: | Height: | Size: 518 B |
|
After Width: | Height: | Size: 506 B |
|
After Width: | Height: | Size: 352 B |
|
After Width: | Height: | Size: 357 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_selected="true" android:drawable="@drawable/beauty_on"/>
|
||||
<item android:state_selected="false" android:drawable="@drawable/beauty_on"/>
|
||||
</selector>
|
||||
@@ -0,0 +1,7 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<corners android:radius="2dp" />
|
||||
|
||||
<solid android:color="#1C1D22" />
|
||||
|
||||
</shape>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<corners android:radius="12dp" />
|
||||
<solid android:color="@color/bg_weak" />
|
||||
<stroke android:width="1dp" android:color="#3A3D48" />
|
||||
</shape>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<corners android:radius="12dp" />
|
||||
<solid android:color="#23262F" />
|
||||
<stroke android:width="1dp" android:color="#3A3D48" />
|
||||
</shape>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/live_list_item_bg" android:state_pressed="true"/>
|
||||
<item android:drawable="@drawable/live_list_item_bg" android:state_hovered="true"/>
|
||||
<item android:drawable="@drawable/live_list_item_bg" android:state_selected="true"/>
|
||||
<item android:drawable="@drawable/live_list_item_fg" />
|
||||
</selector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="#1C1D22" />
|
||||
</shape>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<!-- 背景 gradient是渐变,corners定义的是圆角 -->
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<solid android:color="#3A3D48" />
|
||||
</shape>
|
||||
</item>
|
||||
<!-- 进度条 -->
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
|
||||
<solid android:color="#4DCFE1" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
|
||||
</layer-list>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- 背景 gradient是渐变,corners定义的是圆角 -->
|
||||
<item
|
||||
android:id="@android:id/background"
|
||||
android:gravity="center_vertical|fill_horizontal">
|
||||
<shape>
|
||||
<size android:height="2dp" />
|
||||
<solid android:color="#3A3D48" />
|
||||
</shape>
|
||||
</item>
|
||||
<!-- 进度条 -->
|
||||
<item
|
||||
android:id="@android:id/progress"
|
||||
android:gravity="center_vertical|fill_horizontal">
|
||||
<clip>
|
||||
<shape>
|
||||
<size android:height="2dp" />
|
||||
<solid android:color="#4DCFE1" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
|
||||
</layer-list>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="24dp"/>
|
||||
<solid android:color="@color/colourful_ic_strong"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke android:width="1dp" android:color="@color/darker_gray"/>
|
||||
<solid android:color="@android:color/white" />
|
||||
<corners android:radius="10dp" />
|
||||
</shape>
|
||||
6
LiveCommon/live_commonui/src/main/res/drawable/thumb.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 按钮的选择器,可以设置按钮在不同状态下的时候,按钮不同的颜色 -->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_checked="true" android:drawable="@drawable/thumb_on" />
|
||||
<item android:drawable="@drawable/thumb_off" />
|
||||
</selector>
|
||||
10
LiveCommon/live_commonui/src/main/res/drawable/thumb_off.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
|
||||
<size android:height="26dp" android:width="26dp"/>
|
||||
<corners android:radius="13dp"/>
|
||||
<solid android:color="@color/transparent"/>
|
||||
<stroke android:width="2dp"
|
||||
android:color="@color/des_txt_color"/>
|
||||
</shape>
|
||||
14
LiveCommon/live_commonui/src/main/res/drawable/thumb_on.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<!-- 高度40 -->
|
||||
<size
|
||||
android:width="26dp"
|
||||
android:height="26dp" />
|
||||
<!-- 圆角弧度 20 -->
|
||||
<corners android:radius="13dp" />
|
||||
<solid android:color="@color/transparent" />
|
||||
<stroke android:width="2dp"
|
||||
android:color="@color/text_true_color"/>
|
||||
</shape>
|
||||
7
LiveCommon/live_commonui/src/main/res/drawable/track.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 底层下滑条的样式选择器,可控制Switch在不同状态下,底下下滑条的颜色 -->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_checked="true" android:drawable="@drawable/track_on" />
|
||||
<item android:drawable="@drawable/track_off" />
|
||||
|
||||
</selector>
|
||||
13
LiveCommon/live_commonui/src/main/res/drawable/track_off.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
|
||||
<!-- 高度30 此处设置宽度无效-->
|
||||
<size android:height="26dp"/>
|
||||
<!-- 圆角弧度 15 -->
|
||||
<corners android:radius="13dp"/>
|
||||
<!-- 变化率 定义从左到右的颜色不变 -->
|
||||
<solid android:color="@color/des_txt_color"/>
|
||||
|
||||
|
||||
</shape>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
|
||||
<size android:height="26dp"
|
||||
android:width="50dp"/>
|
||||
<corners android:radius="13dp" />
|
||||
<solid android:height="26dp" android:color="@color/text_true_color" />
|
||||
</shape>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/aui_player_actionbar_left_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aui_player_actionbar_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textFontWeight="500"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/aui_player_actionbar_right_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="20dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#1C1D22"
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.alivc.live.commonui.activity.AUILiveActionBar
|
||||
android:id="@+id/aui_player_base_title"
|
||||
style="@style/LiveBaseActionBar_Style"
|
||||
tools:leftImageSrc="@drawable/ic_live_action_bar_back"
|
||||
tools:rightImageSrc="@drawable/ic_live_actionbar_more"
|
||||
tools:showLeftView="false"
|
||||
tools:showRightView="false"
|
||||
tools:showTitle="true" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/aui_player_base_main_recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:background="@drawable/live_list_item_selector">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/av_list_item_image"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_toRightOf="@+id/av_list_item_image"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/av_list_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lineHeight="24dp"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textFontWeight="500"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/av_list_item_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="30dp"
|
||||
android:ellipsize="end"
|
||||
android:lineHeight="18dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="#B2B7C4"
|
||||
android:textFontWeight="500"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/av_list_item_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="20dp"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<View
|
||||
android:id="@+id/touch_outside"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
android:soundEffectsEnabled="false"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottom_sheet_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottom_sheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|top" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#00000000">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/live_loading_dialog_bg"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="14dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingRight="14dp"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/av_loading_dialog_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@drawable/av_live_loading_dialog_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/av_loading_dialog_tip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:ellipsize="middle"
|
||||
android:gravity="center"
|
||||
android:maxWidth="198dp"
|
||||
android:maxLines="2"
|
||||
android:minWidth="112dp"
|
||||
android:textColor="@color/text_strong"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
158
LiveCommon/live_commonui/src/main/res/layout/common_dialog.xml
Normal file
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:background="#80000000">
|
||||
|
||||
<com.alivc.live.commonui.dialog.MaxHeightLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="50dp"
|
||||
android:layout_marginRight="50dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/live_dialog_bg"
|
||||
android:minHeight="125dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:includeFontPadding="false"
|
||||
android:singleLine="true"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone"
|
||||
tools:text="18dp大标题"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/dialog_content_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginTop="9dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/dialog_content_container2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/dialog_content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none">
|
||||
|
||||
<!-- 解决内部滑动问题 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_tip_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:includeFontPadding="false"
|
||||
android:lineSpacingExtra="3dp"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="14sp"
|
||||
tools:text="14dp提示内容" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/dialog_expand_content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/dialog_btn_top_line"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:background="#3A3D48"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_cancel_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:singleLine="true"
|
||||
android:text="取消"
|
||||
android:textColor="#4DCFE1"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dialog_btn_line"
|
||||
android:layout_width="0.5dp"
|
||||
android:layout_height="52dp"
|
||||
android:background="#3A3D48"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_confirm_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:singleLine="true"
|
||||
android:text="确定"
|
||||
android:textColor="#4DCFE1"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 解决弹窗中心点与屏幕高度45%的位置重合 -->
|
||||
<View
|
||||
android:id="@+id/dialog_bottom_space"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp" />
|
||||
</com.alivc.live.commonui.dialog.MaxHeightLayout>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_msg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/color_text_white"
|
||||
android:textSize="12dp" />
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,804 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/resolution_label"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<com.alivc.live.commonui.configview.LivePushResolutionView
|
||||
android:id="@+id/resolution_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/bitrate_control"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/bitrate_control"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="true"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/variable_resolution"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/variable_resolution"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/view_height_size_45"
|
||||
android:text="@string/resolution_label_desc"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/advance_config"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/advance_config"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/advance_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/push_mode"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quality_modes"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical|end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/quality_resolution_first"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_height="1px"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<TextView
|
||||
android:background="#141416"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:minHeight="@dimen/view_height_size_45"
|
||||
android:text="@string/video_label_desc"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/target_bitrate"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/target_rate_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="28dp"
|
||||
android:background="@null"
|
||||
android:hint="@string/target_rate_value"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:maxLength="9"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/kb_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="/kbps"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="11sp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/min_bitrate"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/min_rate_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="28dp"
|
||||
android:background="@null"
|
||||
android:hint="@string/min_rate_value"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:maxLength="9"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/min_kb_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="/kbps"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="11sp" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/initial_bitrate"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/init_rate_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="28dp"
|
||||
android:background="@null"
|
||||
android:hint="@string/initial_bit_value"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:maxLength="9"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/initial_kb_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="/kbps"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="11sp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/audio_bitrate"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/audio_bitrate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="28dp"
|
||||
android:background="@null"
|
||||
android:hint="@string/audio_bitrate_value"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:maxLength="9"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/audio_kb_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="/kbps"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/min_fps"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/min_fps_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:maxHeight="5dp"
|
||||
android:minHeight="5dp"
|
||||
android:progress="0"
|
||||
android:theme="@style/Push_SeekBar_Style" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/min_fps_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="8"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="/fps"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/captrue_fps"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/fps_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:maxHeight="5dp"
|
||||
android:minHeight="5dp"
|
||||
android:progress="80"
|
||||
android:theme="@style/Push_SeekBar_Style" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fps_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/init_fps"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="/fps"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/audio_sampling_rate"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/audio_rate_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:maxHeight="5dp"
|
||||
android:minHeight="5dp"
|
||||
android:progress="80"
|
||||
android:theme="@style/Push_SeekBar_Style" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/audio_rate_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="@string/setting_audio_480"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/GOP"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/gop_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:maxHeight="5dp"
|
||||
android:minHeight="5dp"
|
||||
android:progress="40"
|
||||
android:theme="@style/Push_SeekBar_Style" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gop_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="2/s"
|
||||
android:textColor="#E6E7EC"
|
||||
android:textSize="11sp" />
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/audio_profile"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/audio_profiles"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:gravity="center_vertical|end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/setting_audio_aac_lc"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/sound_track"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/audio_channel"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:gravity="center_vertical|end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/dual_track"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/video_encoder"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/video_encoder_type"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical|end"
|
||||
android:layout_gravity="end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/h264"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/b_frames"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/b_frame_num"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical|end"
|
||||
android:layout_gravity="end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="0"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/hardware_encode"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/hard_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="true"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/audio_hardware_encode"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/audio_hardenc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="304dp"
|
||||
android:background="#1C1D22"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<TextView
|
||||
android:id="@+id/cancel"
|
||||
android:gravity="center"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:text="@string/pull_cancel"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#4DCFE1"
|
||||
android:layout_width="62dp"
|
||||
android:layout_height="39dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/confirm_button"
|
||||
android:gravity="center"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:text="@string/btn_confirm"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#4DCFE1"
|
||||
android:layout_width="62dp"
|
||||
android:layout_height="39dp"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/div"
|
||||
app:layout_constraintTop_toBottomOf="@+id/cancel"
|
||||
android:layout_width="match_parent"
|
||||
android:background="#3A3D48"
|
||||
android:layout_height="1px"/>
|
||||
|
||||
<com.alivc.live.commonui.configview.OptionSelectorView
|
||||
android:id="@+id/optionSelectorView"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/div"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,838 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#141416"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/push_orientation"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_orientation"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:gravity="center_vertical|end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginEnd="23dp"
|
||||
android:text="@string/portrait"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/landscape_model"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/setting_display_mode"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:gravity="center_vertical|end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/display_mode_cut"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/auto_reconnect"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:paddingStart="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/reconnect_duration"
|
||||
android:textColor="#FCFCFD"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/retry_interval"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:background="@null"
|
||||
android:hint="@string/input_desc"
|
||||
android:inputType="number"
|
||||
android:maxLength="9"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="/ms"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:paddingStart="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/reconnect_times"
|
||||
android:textColor="#FCFCFD"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/retry_count"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:background="@null"
|
||||
android:hint="@string/input_desc"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/second_rate"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/watermark"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/watermark_open"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/watermark_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/watermark_setting"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/water_position"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="@string/watermark_setting"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="14sp" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/mirror_desc"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/setting_push_mirror"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/push_mirror_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/setting_pre_mirror"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/preview_mirror_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/camera_setting"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/front_camera"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/camera_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="true"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/auto_focus"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/autofocus_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/camera_capture_output_preference"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/setting_camera_capture_output_preference"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:gravity="center_vertical|end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/camera_capture_output_preference_preview"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/beauty_setting"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/beauty_enable"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/beautyOn_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/image_push"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/pause_image"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/pause_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="true"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/network_image"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/network_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="true"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/push_mode"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/push_mode"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:gravity="center_vertical|end"
|
||||
android:paddingEnd="23dp"
|
||||
android:text="@string/video_push_streaming"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_live_arrow_right" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/url_auth"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/auth_text"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/auth_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:background="@null"
|
||||
android:hint="@string/input_desc"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="/ms"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/privacy_text"
|
||||
android:textColor="#FCFCFD"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/privacy_key"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="end|center_vertical"
|
||||
android:background="@null"
|
||||
android:hint="@string/input_desc"
|
||||
android:inputType="number"
|
||||
android:textColor="#747A8C"
|
||||
android:textColorHint="#747A8C"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="39dp"
|
||||
android:background="#141416"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:text="@string/other_func"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_24px" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/asynchronous_interface"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/async_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/music_mode"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/music_mode_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/extern_stream_main"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/extern_video"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="#3A3D48" />
|
||||
|
||||
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/local_log"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="100dp"
|
||||
android:text="@string/local_log"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_30px" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/log_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:checked="false"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track" />
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/view_height_size_45"
|
||||
android:paddingEnd="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/resolution_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:maxHeight="5dp"
|
||||
android:minHeight="5dp"
|
||||
android:progress="66"
|
||||
android:theme="@style/Push_SeekBar_Style" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/resolution_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:text="@string/setting_resolution_540P"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="12sp" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/custom_resolution_root"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:visibility="gone"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:textColor="#FCFCFD"
|
||||
android:text="@string/resolution_width"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_width"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLength="10"
|
||||
android:maxLines="1"
|
||||
android:text="0"
|
||||
android:textColor="#FCFCFD"
|
||||
android:inputType="number"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:textColor="#FCFCFD"
|
||||
android:text="@string/resolution_height"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_height"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLength="10"
|
||||
android:maxLines="1"
|
||||
android:text="0"
|
||||
android:textColor="#FCFCFD"
|
||||
android:inputType="number"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/tv_sei_payload" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_sei_payload_type"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:inputType="number"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_text_white"
|
||||
android:textSize="@dimen/font_size_32px" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/tv_sei_message" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_sei"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_text_white"
|
||||
android:textSize="@dimen/font_size_32px" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_send_sei"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:background="@drawable/shape_pysh_btn_bg"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/sei_send_custom_message_tv"
|
||||
android:textColor="#FCFCFD"
|
||||
android:textSize="@dimen/font_size_24px"
|
||||
android:textStyle="normal" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/push_args_setting"
|
||||
layout="@layout/push_args_setting_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<include
|
||||
android:id="@+id/push_function_setting"
|
||||
layout="@layout/push_function_setting_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
412
LiveCommon/live_commonui/src/main/res/layout/push_watermark.xml
Normal file
@@ -0,0 +1,412 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/darker_gray"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingBottom="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/watermark_setting"
|
||||
android:textColor="#747A8C"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
<Switch
|
||||
android:id="@+id/watermark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track"
|
||||
android:checked="true"
|
||||
android:visibility="gone"/>
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="X"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/x"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.1"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Y"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/y"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.2"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="W"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/w"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.1"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/black" />
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
<Switch
|
||||
android:id="@+id/watermark1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track"
|
||||
android:checked="true"
|
||||
android:visibility="gone"/>
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="X"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/x1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.1"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Y"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/y1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.3"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="W"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/w1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.1"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/black" />
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
<Switch
|
||||
android:id="@+id/watermark2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:thumb="@drawable/thumb"
|
||||
android:track="@drawable/track"
|
||||
android:checked="true"
|
||||
android:visibility="gone"/>
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="X"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/x2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.1"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Y"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/y2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.5"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="W"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/w2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_rect_gray"
|
||||
android:hint="0.1"
|
||||
android:paddingLeft="10dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColorHint="@android:color/darker_gray"
|
||||
android:textSize="@dimen/font_size_28px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:text="%"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
116
LiveCommon/live_commonui/src/main/res/values-en/strings.xml
Normal file
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="system_error">System error:</string>
|
||||
<string name="sdk_error">SDK error:</string>
|
||||
<string name="connect_fail">Connection failed</string>
|
||||
<string name="view_string_hint_push_url">Enter the ingest URL.</string>
|
||||
<string name="url_empty">Please enter url</string>
|
||||
<string name="btn_confirm">Confirm</string>
|
||||
<string name="pull_cancel">Cancel</string>
|
||||
<string name="stop_button">Stop pushing</string>
|
||||
<string name="start_push">Start pushing</string>
|
||||
<string name="resolution_label">Resolution</string>
|
||||
<string name="setting_resolution_180P">180P</string>
|
||||
<string name="setting_resolution_240P">240P</string>
|
||||
<string name="setting_resolution_360P">360P</string>
|
||||
<string name="setting_resolution_480P">480P</string>
|
||||
<string name="setting_resolution_540P">540P</string>
|
||||
<string name="setting_resolution_720P">720P</string>
|
||||
<string name="setting_resolution_1080P">1080P</string>
|
||||
<string name="setting_resolution_self_define">Self Define</string>
|
||||
<string name="bitrate_control">Bitrate Control</string>
|
||||
<string name="variable_resolution">Variable Resolution</string>
|
||||
<string name="resolution_width">width:</string>
|
||||
<string name="resolution_height">height:</string>
|
||||
<string name="resolution_label_desc">To enable the system to automatically switch to the most suitable resolution, you must enable adaptive bitrate streaming. For more information, see the API reference.</string>
|
||||
<string name="advance_config">Advanced Settings</string>
|
||||
<string name="display_mode">DisplayMode</string>
|
||||
<string name="display_mode_full">scaleToFill</string>
|
||||
<string name="display_mode_fit">aspectFit</string>
|
||||
<string name="display_mode_cut">aspectFill</string>
|
||||
<string name="quality_resolution_first">High quality priority</string>
|
||||
<string name="quality_fluency_first">fluency priority</string>
|
||||
<string name="video_label_desc">You can adjust the video bitrate and frame rate only in custom mode.</string>
|
||||
<string name="quality_custom">custom</string>
|
||||
<string name="target_bitrate">Target bitrate</string>
|
||||
<string name="target_rate_value">1200</string>
|
||||
<string name="min_bitrate">Min bitrate</string>
|
||||
<string name="min_rate_value">300</string>
|
||||
<string name="initial_bitrate">Initial bitrate</string>
|
||||
<string name="audio_bitrate">Audio bitrate</string>
|
||||
<string name="initial_bit_value">1000</string>
|
||||
<string name="audio_bitrate_value">64</string>
|
||||
<string name="min_fps">Min fps</string>
|
||||
<string name="captrue_fps">Captrue fps</string>
|
||||
<string name="init_fps">20</string>
|
||||
<string name="audio_sampling_rate">Audio sampling rate</string>
|
||||
<string name="setting_audio_480">48KHz</string>
|
||||
<string name="setting_audio_441">44.1KHz</string>
|
||||
<string name="setting_audio_320">32KHz</string>
|
||||
<string name="setting_audio_160">16KHz</string>
|
||||
<string name="GOP">Gop</string>
|
||||
<string name="audio_profile">Audio profile</string>
|
||||
<string name="sound_track">Sound track</string>
|
||||
<string name="video_encoder">Video Encoder</string>
|
||||
<string name="b_frames">B Frames</string>
|
||||
<string name="hardware_encode">Hardware encoder</string>
|
||||
<string name="audio_hardware_encode">Audio Hardware encoder</string>
|
||||
<string name="setting_audio_aac_lc">LC</string>
|
||||
<string name="setting_audio_aac_he">HE-AAC</string>
|
||||
<string name="setting_audio_aac_hev2">HEv2-AAC</string>
|
||||
<string name="setting_audio_aac_ld">AAC-LD</string>
|
||||
<string name="single_track">Single track</string>
|
||||
<string name="dual_track">Dual track</string>
|
||||
<string name="h264">H264</string>
|
||||
<string name="h265">H265</string>
|
||||
<string name="portrait">Portrait</string>
|
||||
<string name="homeLeft">HomeLeft</string>
|
||||
<string name="homeRight">HomeRight</string>
|
||||
<string name="video_push_streaming">Default</string>
|
||||
<string name="audio_only_push_streaming">Audio only</string>
|
||||
<string name="video_only_push_streaming">Video only</string>
|
||||
<string name="push_orientation">Ingest To</string>
|
||||
<string name="landscape_model">Orientation</string>
|
||||
<string name="auto_reconnect">Auto Reconnection</string>
|
||||
<string name="reconnect_duration">Reconnection duration</string>
|
||||
<string name="input_desc">Enter</string>
|
||||
<string name="reconnect_times">Reconnection times</string>
|
||||
<string name="watermark">Watermark</string>
|
||||
<string name="watermark_open">Watermark</string>
|
||||
<string name="watermark_setting">Setting</string>
|
||||
<string name="mirror_desc">Mirroring</string>
|
||||
<string name="setting_pre_mirror">Preview mirror</string>
|
||||
<string name="setting_push_mirror">Push mirror</string>
|
||||
<string name="camera_setting">Camera Control</string>
|
||||
<string name="front_camera">Front camera</string>
|
||||
<string name="auto_focus">Auto focus</string>
|
||||
<string name="camera_capture_output_preference">Camera Capture Output Preference</string>
|
||||
<string name="camera_capture_output_preference_auto">Auto</string>
|
||||
<string name="camera_capture_output_preference_performance">Performance</string>
|
||||
<string name="camera_capture_output_preference_preview">Preview</string>
|
||||
<string name="beauty_setting">Retouching Switch</string>
|
||||
<string name="beauty_enable">Beauty</string>
|
||||
<string name="image_push">Ingest Standby Stream</string>
|
||||
<string name="pause_image">Pause Image</string>
|
||||
<string name="network_image">NetworkPoor Image</string>
|
||||
<string name="push_mode">Push Mode</string>
|
||||
<string name="url_auth">Url Auth Setting</string>
|
||||
<string name="auth_text">Auth Time</string>
|
||||
<string name="privacy_text">Privacy Key</string>
|
||||
<string name="other_func">Other Features</string>
|
||||
<string name="asynchronous_interface">Asynchronous interface</string>
|
||||
<string name="music_mode">Music Mode</string>
|
||||
<string name="extern_stream_main">Main Extern Stream</string>
|
||||
<string name="local_log">Local log</string>
|
||||
|
||||
<string name="push_args">Stream Ingest Parameters</string>
|
||||
<string name="stream_pusher_tip">Stream Ingest Features</string>
|
||||
|
||||
<string name="tv_sei_message">message</string>
|
||||
<string name="tv_sei_payload">payload</string>
|
||||
|
||||
<string name="local_record_tv">Local Record</string>
|
||||
<string name="manual_create_egl_context_tv">Manual Create EGLContext</string>
|
||||
<string name="sei_send_custom_message_tv">Send Custom Message</string>
|
||||
|
||||
</resources>
|
||||
128
LiveCommon/live_commonui/src/main/res/values-zh-rCN/strings.xml
Normal file
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="system_error">系统错误:</string>
|
||||
<string name="sdk_error">SDK错误:</string>
|
||||
<string name="connect_fail">连接失败</string>
|
||||
|
||||
<string name="view_string_hint_push_url">请输入推流url</string>
|
||||
<string name="url_empty">请输入推流地址</string>
|
||||
|
||||
<string name="btn_confirm">确认</string>
|
||||
<string name="pull_cancel">取消</string>
|
||||
<string name="stop_button">停止推流</string>
|
||||
<string name="start_push">开始推流</string>
|
||||
|
||||
|
||||
<string name="resolution_label">分辨率</string>
|
||||
<string name="setting_resolution_180P">180P</string>
|
||||
<string name="setting_resolution_240P">240P</string>
|
||||
<string name="setting_resolution_360P">360P</string>
|
||||
<string name="setting_resolution_480P">480P</string>
|
||||
<string name="setting_resolution_540P">540P</string>
|
||||
<string name="setting_resolution_720P">720P</string>
|
||||
<string name="setting_resolution_1080P">1080P</string>
|
||||
<string name="setting_resolution_self_define">自定义</string>
|
||||
|
||||
<string name="bitrate_control">码率自适应</string>
|
||||
<string name="resolution_width">宽:</string>
|
||||
<string name="resolution_height">高:</string>
|
||||
<string name="variable_resolution">可变分辨率</string>
|
||||
<string name="resolution_label_desc">分辨率自适应需开启码率自适应,详细请参考api文档</string>
|
||||
<string name="advance_config">高级设置</string>
|
||||
<string name="display_mode">显示模式</string>
|
||||
<string name="display_mode_full">拉伸</string>
|
||||
<string name="display_mode_fit">适合</string>
|
||||
<string name="display_mode_cut">剪裁</string>
|
||||
<string name="quality_resolution_first">清晰度优先</string>
|
||||
<string name="quality_fluency_first">流畅度优先</string>
|
||||
<string name="video_label_desc">视频码率和帧率仅在自定义模式下可以调整</string>
|
||||
<string name="quality_custom">自定义</string>
|
||||
<string name="target_bitrate">视频目标码率</string>
|
||||
<string name="target_rate_value">1200</string>
|
||||
<string name="min_bitrate">视频最小码率</string>
|
||||
<string name="min_rate_value">300</string>
|
||||
<string name="initial_bitrate">视频初始码率</string>
|
||||
<string name="initial_bit_value">1000</string>
|
||||
<string name="audio_bitrate">音频码率</string>
|
||||
<string name="audio_bitrate_value">64</string>
|
||||
<string name="min_fps">最小帧率</string>
|
||||
<string name="captrue_fps">采集帧率</string>
|
||||
<string name="init_fps">20</string>
|
||||
<string name="audio_sampling_rate">音频采样率</string>
|
||||
<string name="setting_audio_480">48KHz</string>
|
||||
<string name="setting_audio_441">44.1KHz</string>
|
||||
<string name="setting_audio_320">32KHz</string>
|
||||
<string name="setting_audio_160">16KHz</string>
|
||||
<string name="GOP">关键帧间隔</string>
|
||||
<string name="audio_profile">音频编码</string>
|
||||
<string name="sound_track">声道</string>
|
||||
<string name="video_encoder">视频编码器</string>
|
||||
<string name="b_frames">B帧个数</string>
|
||||
<string name="hardware_encode">视频硬编码</string>
|
||||
<string name="audio_hardware_encode">音频硬编码</string>
|
||||
<string name="setting_audio_aac_lc">LC</string>
|
||||
<string name="setting_audio_aac_he">HE-AAC</string>
|
||||
<string name="setting_audio_aac_hev2">HEv2-AAC</string>
|
||||
<string name="setting_audio_aac_ld">AAC-LD</string>
|
||||
<string name="single_track">单声道</string>
|
||||
<string name="dual_track">双声道</string>
|
||||
<string name="h264">H264</string>
|
||||
<string name="h265">H265</string>
|
||||
<string name="portrait">Portrait</string>
|
||||
<string name="homeLeft">HomeLeft</string>
|
||||
<string name="homeRight">HomeRight</string>
|
||||
<string name="video_push_streaming">音视频</string>
|
||||
<string name="audio_only_push_streaming">纯音频</string>
|
||||
<string name="video_only_push_streaming">纯视频</string>
|
||||
|
||||
|
||||
<string name="push_orientation">推流方向</string>
|
||||
<string name="landscape_model">显示模式</string>
|
||||
<string name="auto_reconnect">自动重连</string>
|
||||
<string name="reconnect_duration">重连时长</string>
|
||||
<string name="input_desc">请输入</string>
|
||||
<string name="reconnect_times">重连次数</string>
|
||||
<string name="watermark">水印</string>
|
||||
<string name="watermark_open">开启水印</string>
|
||||
<string name="watermark_setting">水印位置</string>
|
||||
<string name="mirror_desc">镜像</string>
|
||||
<string name="setting_pre_mirror">预览镜像</string>
|
||||
<string name="setting_push_mirror">推流镜像</string>
|
||||
<string name="camera_setting">相机控制</string>
|
||||
<string name="front_camera">前置摄像头</string>
|
||||
<string name="auto_focus">自动对焦</string>
|
||||
<string name="camera_capture_output_preference">摄像头采集偏好</string>
|
||||
<string name="camera_capture_output_preference_auto">自动</string>
|
||||
<string name="camera_capture_output_preference_performance">性能</string>
|
||||
<string name="camera_capture_output_preference_preview">高清预览</string>
|
||||
<string name="beauty_setting">美颜开关</string>
|
||||
<string name="beauty_enable">开启美颜</string>
|
||||
<string name="image_push">图片推流</string>
|
||||
<string name="pause_image">暂停图片</string>
|
||||
<string name="network_image">网络差图片</string>
|
||||
<string name="push_mode">推流模式</string>
|
||||
<string name="url_auth">推流鉴权</string>
|
||||
<string name="auth_text">有效时长</string>
|
||||
<string name="privacy_text">鉴权key</string>
|
||||
<string name="other_func">其他功能</string>
|
||||
<string name="asynchronous_interface">异步接口</string>
|
||||
<string name="music_mode">音乐模式</string>
|
||||
<string name="extern_stream_main">外部音视频</string>
|
||||
<string name="local_log">本地日志</string>
|
||||
|
||||
<string name="push_args">推流参数</string>
|
||||
<string name="stream_pusher_tip">推流功能</string>
|
||||
|
||||
<string name="second_rate">/次</string>
|
||||
<string name="tv_sei_message">message</string>
|
||||
<string name="tv_sei_payload">payload</string>
|
||||
|
||||
<string name="local_record_tv">本地录制</string>
|
||||
<string name="manual_create_egl_context_tv">手动创建EGLContext</string>
|
||||
<string name="sei_send_custom_message_tv">发送自定义消息</string>
|
||||
|
||||
<string name="backdoor_title">Live Push Demo配置页面</string>
|
||||
<string name="backdoor_tip">用于手动配置demo相应功能</string>
|
||||
<string name="backdoor_multi_pk_16in">16方多人PK</string>
|
||||
|
||||
</resources>
|
||||
18
LiveCommon/live_commonui/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!--MaxHeightLayout 使用-->
|
||||
<declare-styleable name="mMaxRatio">
|
||||
<attr name="linear_max_ratio" format="float"></attr>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="av_actionbar">
|
||||
<attr name="showTitle" format="boolean" />
|
||||
<attr name="showLeftView" format="boolean" />
|
||||
<attr name="showRightView" format="boolean" />
|
||||
<attr name="title" format="string" />
|
||||
<attr name="leftImageBackground" format="reference" />
|
||||
<attr name="leftImageSrc" format="reference" />
|
||||
<attr name="rightImageBackground" format="reference" />
|
||||
<attr name="rightImageSrc" format="reference" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
117
LiveCommon/live_commonui/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="system_error">System error:</string>
|
||||
<string name="sdk_error">SDK error:</string>
|
||||
<string name="connect_fail">Connection failed</string>
|
||||
<string name="view_string_hint_push_url">Enter the ingest URL.</string>
|
||||
<string name="url_empty">Please enter url</string>
|
||||
<string name="btn_confirm">Confirm</string>
|
||||
<string name="pull_cancel">Cancel</string>
|
||||
<string name="stop_button">Stop pushing</string>
|
||||
<string name="start_push">Start pushing</string>
|
||||
<string name="resolution_label">Resolution</string>
|
||||
<string name="setting_resolution_180P">180P</string>
|
||||
<string name="setting_resolution_240P">240P</string>
|
||||
<string name="setting_resolution_360P">360P</string>
|
||||
<string name="setting_resolution_480P">480P</string>
|
||||
<string name="setting_resolution_540P">540P</string>
|
||||
<string name="setting_resolution_720P">720P</string>
|
||||
<string name="setting_resolution_1080P">1080P</string>
|
||||
<string name="setting_resolution_self_define">Self Define</string>
|
||||
<string name="bitrate_control">Bitrate Control</string>
|
||||
<string name="variable_resolution">Variable Resolution</string>
|
||||
<string name="resolution_width">width:</string>
|
||||
<string name="resolution_height">height:</string>
|
||||
<string name="resolution_label_desc">To enable the system to automatically switch to the most suitable resolution, you must enable adaptive bitrate streaming. For more information, see the API reference.</string>
|
||||
<string name="advance_config">Advanced Settings</string>
|
||||
<string name="display_mode">DisplayMode</string>
|
||||
<string name="display_mode_full">scaleToFill</string>
|
||||
<string name="display_mode_fit">aspectFit</string>
|
||||
<string name="display_mode_cut">aspectFill</string>
|
||||
<string name="quality_resolution_first">High quality priority</string>
|
||||
<string name="quality_fluency_first">fluency priority</string>
|
||||
<string name="video_label_desc">You can adjust the video bitrate and frame rate only in custom mode.</string>
|
||||
<string name="quality_custom">custom</string>
|
||||
<string name="target_bitrate">Target bitrate</string>
|
||||
<string name="target_rate_value">1200</string>
|
||||
<string name="min_bitrate">Min bitrate</string>
|
||||
<string name="min_rate_value">300</string>
|
||||
<string name="initial_bitrate">Initial bitrate</string>
|
||||
<string name="audio_bitrate">Audio bitrate</string>
|
||||
<string name="initial_bit_value">1000</string>
|
||||
<string name="audio_bitrate_value">64</string>
|
||||
<string name="min_fps">Min fps</string>
|
||||
<string name="captrue_fps">Captrue fps</string>
|
||||
<string name="init_fps">20</string>
|
||||
<string name="audio_sampling_rate">Audio sampling rate</string>
|
||||
<string name="setting_audio_480">48KHz</string>
|
||||
<string name="setting_audio_441">44.1KHz</string>
|
||||
<string name="setting_audio_320">32KHz</string>
|
||||
<string name="setting_audio_160">16KHz</string>
|
||||
<string name="GOP">Gop</string>
|
||||
<string name="audio_profile">Audio profile</string>
|
||||
<string name="sound_track">Sound track</string>
|
||||
<string name="video_encoder">Video Encoder</string>
|
||||
<string name="b_frames">B Frames</string>
|
||||
<string name="hardware_encode">Hardware encoder</string>
|
||||
<string name="audio_hardware_encode">Audio Hardware encoder</string>
|
||||
<string name="setting_audio_aac_lc">LC</string>
|
||||
<string name="setting_audio_aac_he">HE-AAC</string>
|
||||
<string name="setting_audio_aac_hev2">HEv2-AAC</string>
|
||||
<string name="setting_audio_aac_ld">AAC-LD</string>
|
||||
<string name="single_track">Single track</string>
|
||||
<string name="dual_track">Dual track</string>
|
||||
<string name="h264">H264</string>
|
||||
<string name="h265">H265</string>
|
||||
<string name="portrait">Portrait</string>
|
||||
<string name="homeLeft">HomeLeft</string>
|
||||
<string name="homeRight">HomeRight</string>
|
||||
<string name="video_push_streaming">Default</string>
|
||||
<string name="audio_only_push_streaming">Audio only</string>
|
||||
<string name="video_only_push_streaming">Video only</string>
|
||||
<string name="push_orientation">Ingest To</string>
|
||||
<string name="landscape_model">Orientation</string>
|
||||
<string name="auto_reconnect">Auto Reconnection</string>
|
||||
<string name="reconnect_duration">Reconnection duration</string>
|
||||
<string name="input_desc">Enter</string>
|
||||
<string name="reconnect_times">Reconnection times</string>
|
||||
<string name="watermark">Watermark</string>
|
||||
<string name="watermark_open">Watermark</string>
|
||||
<string name="watermark_setting">Setting</string>
|
||||
<string name="mirror_desc">Mirroring</string>
|
||||
<string name="setting_pre_mirror">Preview mirror</string>
|
||||
<string name="setting_push_mirror">Push mirror</string>
|
||||
<string name="camera_setting">Camera Control</string>
|
||||
<string name="front_camera">Front camera</string>
|
||||
<string name="auto_focus">Auto focus</string>
|
||||
<string name="camera_capture_output_preference">Camera Capture Output Preference</string>
|
||||
<string name="camera_capture_output_preference_auto">Auto</string>
|
||||
<string name="camera_capture_output_preference_performance">Performance</string>
|
||||
<string name="camera_capture_output_preference_preview">Preview</string>
|
||||
<string name="beauty_setting">Retouching Switch</string>
|
||||
<string name="beauty_enable">Beauty</string>
|
||||
<string name="image_push">Ingest Standby Stream</string>
|
||||
<string name="pause_image">Pause Image</string>
|
||||
<string name="network_image">NetworkPoor Image</string>
|
||||
<string name="push_mode">Push Mode</string>
|
||||
<string name="url_auth">Url Auth Setting</string>
|
||||
<string name="auth_text">Auth Time</string>
|
||||
<string name="privacy_text">Privacy Key</string>
|
||||
<string name="other_func">Other Features</string>
|
||||
<string name="asynchronous_interface">Asynchronous interface</string>
|
||||
<string name="music_mode">Music Mode</string>
|
||||
<string name="extern_stream_main">Main Extern Stream</string>
|
||||
<string name="local_log">Local log</string>
|
||||
|
||||
<string name="push_args">Stream Ingest Parameters</string>
|
||||
<string name="stream_pusher_tip">Stream Ingest Features</string>
|
||||
|
||||
<string name="second_rate">/Times</string>
|
||||
<string name="tv_sei_message">message</string>
|
||||
<string name="tv_sei_payload">payload</string>
|
||||
|
||||
<string name="local_record_tv">Local Record</string>
|
||||
<string name="manual_create_egl_context_tv">Manual Create EGLContext</string>
|
||||
<string name="sei_send_custom_message_tv">Send Custom Message</string>
|
||||
|
||||
</resources>
|
||||
66
LiveCommon/live_commonui/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,66 @@
|
||||
<resources>
|
||||
<style name="AVLiveBaseTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AVLiveAppTheme" parent="AVLiveBaseTheme">
|
||||
</style>
|
||||
|
||||
<style name="AVLive_ProgressBar_Horizontal_Style" parent="Widget.AppCompat.ProgressBar.Horizontal">
|
||||
<item name="colorAccent">#4DCFE1</item>
|
||||
</style>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AVLiveTheme" parent="AVLiveBaseTheme">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="dialog_animation">
|
||||
<item name="android:windowEnterAnimation">@anim/anim_trans_from_bottom</item>
|
||||
<item name="android:windowExitAnimation">@anim/anim_layout_bottom_out</item>
|
||||
</style>
|
||||
|
||||
<style name="DialogStyle">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:cacheColorHint">@android:color/transparent</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
|
||||
<style name="AUILiveDialog" parent="android:Theme.Dialog">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<!-- 为了避免在有 NavigationBar 的手机上 Dialog 从 NavigationBar 底部上来。去掉 Dialog 的动画,使用 View 的动画。-->
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:padding">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="LogText">
|
||||
<item name="android:textColor">@color/colorAccent</item>
|
||||
<item name="android:textSize">@dimen/font_size_28px</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:padding">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Push_SeekBar_Style" parent="Widget.AppCompat.SeekBar">
|
||||
<item name="colorAccent">#4DCFE1</item>
|
||||
</style>
|
||||
|
||||
<style name="AUIEditText">
|
||||
<item name="colorControlNormal">#3A3D48</item>
|
||||
<item name="colorControlActivated">#3A3D48</item>
|
||||
</style>
|
||||
|
||||
<style name="Live.BaseDialog" parent="Theme.AppCompat.Dialog">
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Live.BottomSheetDialog" parent="Live.BaseDialog">
|
||||
<item name="android:backgroundDimAmount">0</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
</resources>
|
||||
10
LiveCommon/live_commonui/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<style name="LiveBaseActionBar_Style">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">44dp</item>
|
||||
</style>
|
||||
<color name="text_true_color">#FF6500</color>
|
||||
<color name="des_txt_color">#8016243C</color>
|
||||
|
||||
</resources>
|
||||
1
LiveCommon/live_commonutils/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
33
LiveCommon/live_commonutils/build.gradle
Normal file
@@ -0,0 +1,33 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdkVersion
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion androidMinSdkVersion
|
||||
targetSdkVersion androidTargetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api externalOKHTTP
|
||||
implementation externalAndroidAnnotation
|
||||
}
|
||||
0
LiveCommon/live_commonutils/consumer-rules.pro
Normal file
4
LiveCommon/live_commonutils/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.alivc.live.commonutils">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,353 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2021/7/27
|
||||
*/
|
||||
public class AppUtil {
|
||||
|
||||
private static final String BUILD_TYPE_DEBUG = "DEBUG";
|
||||
private static final String BUILD_TYPE_RELEASE = "RELEASE";
|
||||
|
||||
private static final String CPU_INFO_FILE_PATH = "/proc/cpuinfo";
|
||||
|
||||
// read from cpu info file only once to reduce method cost.
|
||||
private static final ArrayList<String> mCpuInfo = new ArrayList<>();
|
||||
|
||||
private AppUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get app name
|
||||
*
|
||||
* @param context android context
|
||||
* @return app name, not null
|
||||
*/
|
||||
@NonNull
|
||||
public static String getAppName(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
ApplicationInfo ai = context.getApplicationInfo();
|
||||
PackageManager pm = context.getPackageManager();
|
||||
return ai.loadLabel(pm).toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get app id
|
||||
*
|
||||
* @param context android context
|
||||
* @return app id, not null
|
||||
*/
|
||||
@NonNull
|
||||
public static String getAppId(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return "";
|
||||
}
|
||||
String pn = context.getPackageName();
|
||||
return (pn != null) ? pn : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get app build type
|
||||
*
|
||||
* @param context android context
|
||||
* @return app build type, debug or release
|
||||
*/
|
||||
@NonNull
|
||||
public static String getApkBuildType(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return "";
|
||||
}
|
||||
boolean isDebug = false;
|
||||
try {
|
||||
ApplicationInfo ai = context.getApplicationInfo();
|
||||
isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return isDebug ? BUILD_TYPE_DEBUG : BUILD_TYPE_RELEASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package version name
|
||||
*
|
||||
* @param context android context
|
||||
* @return package version name
|
||||
*/
|
||||
@NonNull
|
||||
public static String getPackageVersionName(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return "";
|
||||
}
|
||||
PackageManager manager = context.getPackageManager();
|
||||
|
||||
String name = null;
|
||||
try {
|
||||
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
|
||||
name = info.versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return name != null ? name : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package version code
|
||||
*
|
||||
* @param context android context
|
||||
* @return package version code
|
||||
*/
|
||||
public static int getPackageVersionCode(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return 0;
|
||||
}
|
||||
PackageManager manager = context.getPackageManager();
|
||||
|
||||
int code = 0;
|
||||
try {
|
||||
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
|
||||
code = info.versionCode;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get android device unique id
|
||||
*
|
||||
* @param context android context
|
||||
* @return android device unique id, not null
|
||||
* @link {https://developer.android.com/training/articles/user-data-ids}
|
||||
*/
|
||||
@SuppressLint("HardwareIds")
|
||||
@NonNull
|
||||
public static String getDeviceId(@Nullable Context context) {
|
||||
if (context != null) {
|
||||
try {
|
||||
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return "uuid-" + UUID.randomUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full cpu info
|
||||
*
|
||||
* @return full cpu info
|
||||
*/
|
||||
@NonNull
|
||||
public static String getFullCPUInfo() {
|
||||
if (mCpuInfo.isEmpty()) {
|
||||
mCpuInfo.addAll(readFromCpuInfo());
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line : mCpuInfo) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get brief cpu info
|
||||
*
|
||||
* @return brief cpu info
|
||||
*/
|
||||
@NonNull
|
||||
public static String getBriefCPUInfo() {
|
||||
return getCPUHardwareInfo() + "\n" + getCPUProcessorArchInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cpu processor name
|
||||
*
|
||||
* @return cpu processor name
|
||||
*/
|
||||
@NonNull
|
||||
public static String getCPUProcessorArchInfo() {
|
||||
return getSpecificCpuInfoByKey("Processor");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CPU hardware name
|
||||
*
|
||||
* @return cpu hardware name, not null
|
||||
*/
|
||||
@NonNull
|
||||
public static String getCPUHardwareInfo() {
|
||||
return getSpecificCpuInfoByKey("Hardware");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specific cpu info by key.
|
||||
*
|
||||
* @param key cpu info key
|
||||
* @return cpu info value
|
||||
*/
|
||||
@NonNull
|
||||
public static String getSpecificCpuInfoByKey(@NonNull String key) {
|
||||
if (mCpuInfo.isEmpty()) {
|
||||
mCpuInfo.addAll(readFromCpuInfo());
|
||||
}
|
||||
|
||||
String value = "";
|
||||
for (String str : mCpuInfo) {
|
||||
if (str.startsWith(key)) {
|
||||
String[] data = str.split(":");
|
||||
if (data.length > 1) {
|
||||
value = data[1].trim();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from cpuinfo file
|
||||
*
|
||||
* @return file lines
|
||||
*/
|
||||
@NonNull
|
||||
public static ArrayList<String> readFromCpuInfo() {
|
||||
ArrayList<String> cpuInfo = new ArrayList<>();
|
||||
try {
|
||||
FileReader fr = new FileReader(CPU_INFO_FILE_PATH);
|
||||
BufferedReader br = new BufferedReader(fr, 8192);
|
||||
String str;
|
||||
while ((str = br.readLine()) != null) {
|
||||
cpuInfo.add(str.trim());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return cpuInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get brief device info
|
||||
*
|
||||
* @return brief device info, not null
|
||||
*/
|
||||
@NonNull
|
||||
public static String getBriefDeviceInfo() {
|
||||
return DeviceUtil.getDeviceBrand()
|
||||
+ " " + DeviceUtil.getDeviceModel()
|
||||
+ ", Android " + DeviceUtil.getDeviceVersion()
|
||||
+ ", " + DeviceUtil.getDeviceCPUArch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed device info
|
||||
*
|
||||
* @return detailed device info, not null
|
||||
*/
|
||||
@SuppressLint("HardwareIds")
|
||||
@NonNull
|
||||
public static String getDeviceInfo() {
|
||||
String s = "主板: " + Build.BOARD +
|
||||
"\n系统启动程序版本号: " + Build.BOOTLOADER +
|
||||
"\n系统定制商: " + Build.BRAND +
|
||||
"\ncpu指令集: " + Build.CPU_ABI +
|
||||
"\ncpu指令集2: " + Build.CPU_ABI2 +
|
||||
"\n设置参数: " + Build.DEVICE +
|
||||
"\n显示屏参数: " + Build.DISPLAY +
|
||||
"\n无线电固件版本: " + Build.getRadioVersion() +
|
||||
"\n硬件识别码: " + Build.FINGERPRINT +
|
||||
"\n硬件名称: " + Build.HARDWARE +
|
||||
"\nHOST: " + Build.HOST +
|
||||
"\n修订版本列表: " + Build.ID +
|
||||
"\n硬件制造商: " + Build.MANUFACTURER +
|
||||
"\n版本: " + Build.MODEL +
|
||||
"\n硬件序列号: " + Build.SERIAL +
|
||||
"\n手机制造商: " + Build.PRODUCT +
|
||||
"\n描述Build的标签: " + Build.TAGS +
|
||||
"\nTIME: " + Build.TIME +
|
||||
"\nbuilder类型: " + Build.TYPE +
|
||||
"\nUSER: " + Build.USER;
|
||||
return s.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenGL ES info
|
||||
*
|
||||
* @param context android context, nullable
|
||||
* @return OpenGL ES info, not null
|
||||
*/
|
||||
@NonNull
|
||||
public static String getOpenGLESInfo(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (am == null) {
|
||||
return "";
|
||||
}
|
||||
ConfigurationInfo ci = am.getDeviceConfigurationInfo();
|
||||
if (ci == null) {
|
||||
return "";
|
||||
}
|
||||
return "OpenGL ES " + ci.getGlEsVersion() + " " + ci.reqGlEsVersion;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get android device network status
|
||||
*
|
||||
* @param context android context
|
||||
* @return network connected, true or false
|
||||
*/
|
||||
public static boolean isNetworkAvailable(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (cm == null) {
|
||||
return false;
|
||||
}
|
||||
NetworkInfo ni = cm.getActiveNetworkInfo();
|
||||
if (ni == null) {
|
||||
return false;
|
||||
}
|
||||
return ni.isConnected();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by baorunchen on 2021/4/29.
|
||||
* <p>
|
||||
* Android asset file util
|
||||
*/
|
||||
public class AssetUtil {
|
||||
/**
|
||||
* Copy asset file or folder to sdcard
|
||||
*
|
||||
* @param context android context
|
||||
* @param srcFilePath src asset path, file or folder
|
||||
* @param destFilePath dest sdcard path
|
||||
* @return true->success, false->failed.
|
||||
* <p>
|
||||
* Such as:
|
||||
* srcFilePath: ai.bundle/face.model
|
||||
* destFilePath: /data/xxx/yyy/zzz/ai.bundle/face.model
|
||||
* result: /data/xxx/yyy/zzz/ai.bundle/face.model
|
||||
*/
|
||||
public static boolean copyAssetToSdCard(@Nullable Context context, @Nullable String srcFilePath, @Nullable String destFilePath) {
|
||||
if (context == null || srcFilePath == null || destFilePath == null || srcFilePath.isEmpty() || destFilePath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayList<String> assetFileList = getAssetFilePathList(context, srcFilePath);
|
||||
boolean isFolder = !assetFileList.isEmpty();
|
||||
|
||||
// Check whether target file exists
|
||||
File targetFile = new File(destFilePath);
|
||||
|
||||
// If file already exists, return.
|
||||
// Only when target is a file and exists can return.
|
||||
if (targetFile.exists() && targetFile.isFile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isFolder) {
|
||||
return copyAssetFileToSdCard(context, srcFilePath, destFilePath);
|
||||
} else {
|
||||
// If file exists but not expected file type, remove it.
|
||||
if (targetFile.isFile()) {
|
||||
targetFile.delete();
|
||||
}
|
||||
targetFile.mkdirs();
|
||||
|
||||
boolean result = true;
|
||||
for (String file : assetFileList) {
|
||||
String src = srcFilePath + File.separator + file;
|
||||
String dest = destFilePath + File.separator + file;
|
||||
result = result && copyAssetToSdCard(context, src, dest);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy single asset file to sdcard
|
||||
*
|
||||
* @param context android context
|
||||
* @param srcFilePath src asset file path
|
||||
* @param destFilePath dest sdcard file path
|
||||
* @return true->success, false->failed.
|
||||
*/
|
||||
private static boolean copyAssetFileToSdCard(@Nullable Context context, @Nullable String srcFilePath, @Nullable String destFilePath) {
|
||||
if (context == null || srcFilePath == null || destFilePath == null || srcFilePath.isEmpty() || destFilePath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File targetFile = new File(destFilePath);
|
||||
if (targetFile.exists()) return true;
|
||||
|
||||
AssetManager am = context.getAssets();
|
||||
if (am == null) return false;
|
||||
|
||||
InputStream inputStream = null;
|
||||
FileOutputStream outputStream = null;
|
||||
|
||||
try {
|
||||
inputStream = am.open(srcFilePath);
|
||||
outputStream = new FileOutputStream(destFilePath);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int length = inputStream.read(buffer);
|
||||
while (length > 0) {
|
||||
outputStream.write(buffer, 0, length);
|
||||
length = inputStream.read(buffer);
|
||||
}
|
||||
|
||||
outputStream.flush();
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
targetFile.delete();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
outputStream.getChannel().close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get asset file by assets folder name
|
||||
*
|
||||
* @param context android context
|
||||
* @param assetFolder assets folder name
|
||||
* @return asset file list with full path
|
||||
*/
|
||||
@NonNull
|
||||
public static ArrayList<String> getAssetFilePathList(@Nullable Context context, @Nullable String assetFolder) {
|
||||
ArrayList<String> fileList = new ArrayList<>();
|
||||
|
||||
if (context == null) return fileList;
|
||||
|
||||
AssetManager am = context.getAssets();
|
||||
if (am == null) return fileList;
|
||||
|
||||
try {
|
||||
String[] assetList = am.list(assetFolder);
|
||||
fileList.addAll(Arrays.asList(assetList));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return fileList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2023/9/15
|
||||
* @brief
|
||||
*/
|
||||
public class BitmapUtil {
|
||||
private BitmapUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字生成bitmap
|
||||
*
|
||||
* @param context android context
|
||||
* @param contents 文字内容
|
||||
* @return bitmap图像
|
||||
*/
|
||||
public static Bitmap createTextBitmap(Context context, String contents) {
|
||||
if (context == null || TextUtils.isEmpty(contents)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
float scale = context.getResources().getDisplayMetrics().scaledDensity;
|
||||
|
||||
TextView tv = new TextView(context);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
tv.setLayoutParams(layoutParams);
|
||||
tv.setText(contents);
|
||||
tv.setTextSize(scale * 12);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setDrawingCacheEnabled(true);
|
||||
tv.setTextColor(Color.WHITE);
|
||||
tv.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
|
||||
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
|
||||
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
|
||||
|
||||
tv.setBackgroundColor(Color.TRANSPARENT);
|
||||
|
||||
tv.buildDrawingCache();
|
||||
return tv.getDrawingCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻转bitmap
|
||||
*
|
||||
* @param bitmap bitmap图像
|
||||
* @param isFlipX X轴flip
|
||||
* @param isFlipY Y轴flip
|
||||
* @return 翻转后的bitmap
|
||||
*/
|
||||
public static Bitmap flipBitmap(Bitmap bitmap, boolean isFlipX, boolean isFlipY) {
|
||||
if (bitmap == null || bitmap.isRecycled()) {
|
||||
return null;
|
||||
}
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setScale(isFlipX ? -1 : 1, isFlipY ? -1 : 1);
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by keria on 2022/4/6.
|
||||
*/
|
||||
public class ContextUtils {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static Context sContext = null;
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static Context sSafeContext = null;
|
||||
|
||||
public static void setContext(@NonNull Context context) {
|
||||
sContext = context;
|
||||
sSafeContext = new SafeToastContext(context);
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return sContext;
|
||||
}
|
||||
|
||||
public static Context getApplicationContext() {
|
||||
return sContext;
|
||||
}
|
||||
|
||||
public static Context getSafeToastContext() {
|
||||
return sSafeContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2022/4/19
|
||||
*/
|
||||
public class DeviceUtil {
|
||||
|
||||
private DeviceUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device brand
|
||||
*
|
||||
* @return brand name
|
||||
*/
|
||||
@NonNull
|
||||
public static String getDeviceBrand() {
|
||||
return Build.BRAND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device os version
|
||||
*
|
||||
* @return device os version
|
||||
*/
|
||||
@NonNull
|
||||
public static String getDeviceVersion() {
|
||||
return Build.VERSION.RELEASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device os version code
|
||||
*
|
||||
* @return device os version code
|
||||
*/
|
||||
public static int getDeviceVersionCode() {
|
||||
return Build.VERSION.SDK_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device model
|
||||
*
|
||||
* @return device model name
|
||||
*/
|
||||
@NonNull
|
||||
public static String getDeviceModel() {
|
||||
return Build.MODEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device cpu arch
|
||||
*
|
||||
* @return device cpu arch name
|
||||
*/
|
||||
@SuppressLint("ObsoleteSdkInt")
|
||||
@NonNull
|
||||
public static String getDeviceCPUArch() {
|
||||
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) ? Build.CPU_ABI : Build.SUPPORTED_ABIS[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device orientation
|
||||
*
|
||||
* @param context android context, nullable
|
||||
* @return device orientation
|
||||
*/
|
||||
public static int getDisplayOrientation(@Nullable Context context) {
|
||||
int displayOrientation = 0;
|
||||
|
||||
if (context == null) {
|
||||
return displayOrientation;
|
||||
}
|
||||
|
||||
int angle = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
|
||||
switch (angle) {
|
||||
case Surface.ROTATION_0:
|
||||
displayOrientation = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
displayOrientation = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
displayOrientation = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
displayOrientation = 270;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return displayOrientation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
|
||||
/**
|
||||
* 下载类
|
||||
* 使用 DownloadManager 实现下载功能
|
||||
*/
|
||||
public class DownloadUtil {
|
||||
|
||||
private static DownloadManager mDownloadManager;
|
||||
private OnDownloadListener mOnDownloadListener;
|
||||
|
||||
public DownloadUtil(Context context) {
|
||||
if (mDownloadManager == null) {
|
||||
mDownloadManager = (DownloadManager) context.getApplicationContext().getSystemService(DOWNLOAD_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
public long startDownload(String url, File file) {
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setDestinationUri(Uri.fromFile(file));
|
||||
long downloadId = mDownloadManager.enqueue(request);
|
||||
Timer timer = new Timer();
|
||||
//检测下载进度和下载完成事件
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
DownloadManager.Query query = new DownloadManager.Query();
|
||||
Cursor cursor = mDownloadManager.query(query.setFilterById(downloadId));
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
//获取当前下载状态
|
||||
int columnIndexForStatus = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
|
||||
switch (cursor.getInt(columnIndexForStatus)) {
|
||||
case DownloadManager.STATUS_SUCCESSFUL:
|
||||
if (mOnDownloadListener != null) {
|
||||
mOnDownloadListener.onDownloadSuccess(downloadId);
|
||||
}
|
||||
cancel();
|
||||
break;
|
||||
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
|
||||
if (mOnDownloadListener != null) {
|
||||
mOnDownloadListener.onDownloadError(downloadId, DownloadManager.ERROR_FILE_ALREADY_EXISTS, "File already exists");
|
||||
}
|
||||
cancel();
|
||||
break;
|
||||
case DownloadManager.ERROR_HTTP_DATA_ERROR:
|
||||
case DownloadManager.ERROR_FILE_ERROR:
|
||||
if (mOnDownloadListener != null) {
|
||||
mOnDownloadListener.onDownloadError(downloadId, DownloadManager.ERROR_HTTP_DATA_ERROR, "other error");
|
||||
}
|
||||
cancel();
|
||||
break;
|
||||
case DownloadManager.STATUS_RUNNING:
|
||||
int columnIndexForDownloadBytes = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
|
||||
int columnIndexForTotalSize = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
|
||||
//已下载大小
|
||||
int downloadedBytes = cursor.getInt(columnIndexForDownloadBytes);
|
||||
//总大小
|
||||
int totalBytes = cursor.getInt(columnIndexForTotalSize);
|
||||
double percent = (downloadedBytes * 100.00) / totalBytes;
|
||||
if (mOnDownloadListener != null) {
|
||||
mOnDownloadListener.onDownloadProgress(downloadId, Math.round(percent));
|
||||
}
|
||||
break;
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
timer.schedule(timerTask, 0, 2000);
|
||||
|
||||
return downloadId;
|
||||
}
|
||||
|
||||
public void cancelDownload(long id) {
|
||||
mDownloadManager.remove(id);
|
||||
}
|
||||
|
||||
public void setDownloadListener(OnDownloadListener downloadListener) {
|
||||
this.mOnDownloadListener = downloadListener;
|
||||
}
|
||||
|
||||
public interface OnDownloadListener {
|
||||
void onDownloadSuccess(long downloadId);
|
||||
|
||||
void onDownloadProgress(long downloadId, double percent);
|
||||
|
||||
void onDownloadError(long downloadId, int errorCode, String errorMsg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
/**
|
||||
* 快速点击判断
|
||||
*
|
||||
* @author ragnar
|
||||
* @date 2019-08-14
|
||||
*/
|
||||
public class FastClickUtil {
|
||||
private static final long PROCESS_MIN_DURATION = 300;
|
||||
private static final long PROCESS_MIDDLE_DURATION = 450;
|
||||
private static final long PROCESS_LONG_DURATION = 600;
|
||||
private static long mLastProcessTime = 0;
|
||||
|
||||
/**
|
||||
* 点击间隔时间是否在[PROCESS_MIN_DURATION]ms内
|
||||
*/
|
||||
public static boolean isProcessing() {
|
||||
return isProcessing(PROCESS_MIN_DURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击间隔时间是否在[PROCESS_MIDDLE_DURATION]ms内
|
||||
*/
|
||||
public static boolean isMiddleProcessing() {
|
||||
return isProcessing(PROCESS_MIDDLE_DURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击间隔时间是否在[PROCESS_LONG_DURATION]ms内
|
||||
*/
|
||||
public static boolean isLongProcessing() {
|
||||
return isProcessing(PROCESS_LONG_DURATION);
|
||||
}
|
||||
|
||||
private static boolean isProcessing(long pass) {
|
||||
if (mLastProcessTime == 0L) {
|
||||
mLastProcessTime = System.currentTimeMillis();
|
||||
return false;
|
||||
}
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long passTime = currentTime - mLastProcessTime;
|
||||
if (passTime < 0 || passTime > pass) {
|
||||
mLastProcessTime = currentTime;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author keria
|
||||
* @date 2021/7/11
|
||||
*/
|
||||
public class FileUtil {
|
||||
|
||||
private FileUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if file exists
|
||||
*
|
||||
* @param path file path
|
||||
* @return true->exists, false->not exist
|
||||
*/
|
||||
public static boolean fileExists(@Nullable String path) {
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
File file = new File(path);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if folder exists
|
||||
*
|
||||
* @param path folder path
|
||||
* @return true->exists, false->not exist
|
||||
*/
|
||||
public static boolean folderExists(@Nullable String path) {
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
File file = new File(path);
|
||||
return file.exists() && file.isDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent folder absolute path
|
||||
*
|
||||
* @param path file path
|
||||
* @return parent folder absolute path
|
||||
*/
|
||||
@NonNull
|
||||
public static String getFolderPath(@Nullable String path) {
|
||||
if (path == null) {
|
||||
return "";
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
File file = new File(path);
|
||||
String parent = file.getAbsoluteFile().getParent();
|
||||
return parent != null ? parent : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create folder if not exists
|
||||
* <p>
|
||||
* If the target is a file, remove it and then create folder.
|
||||
*
|
||||
* @param path folder path
|
||||
*/
|
||||
public static void safeCreateFolder(@Nullable String path) {
|
||||
if (path == null || path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
File file = new File(path);
|
||||
if (file.isFile()) {
|
||||
file.delete();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file if exists
|
||||
* <p>
|
||||
* If the target exists, remove it
|
||||
*
|
||||
* @param path file path
|
||||
*/
|
||||
public static void safeDeleteFile(@Nullable String path) {
|
||||
if (path == null || path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file if exists
|
||||
* <p>
|
||||
* If the target exists, remove it
|
||||
*
|
||||
* @param file file
|
||||
*/
|
||||
public static void safeDeleteFile(@Nullable File file) {
|
||||
if (file == null || !file.exists()) {
|
||||
return;
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get internal cache folder from sd card
|
||||
*
|
||||
* @param context android context
|
||||
* @return internal cache folder from sdcard
|
||||
*/
|
||||
@NonNull
|
||||
public static String getInternalCacheFolder(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
return "";
|
||||
}
|
||||
return context.getCacheDir().getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get internal files folder from sd card
|
||||
*
|
||||
* @param context android context
|
||||
* @return internal files folder from sdcard
|
||||
*/
|
||||
public static String getInternalFilesFolder(@Nullable Context context) {
|
||||
if (context == null) return "";
|
||||
return context.getFilesDir().getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get external cache folder from sd card
|
||||
*
|
||||
* @param context android context
|
||||
* @return external cache folder from sdcard
|
||||
*/
|
||||
@NonNull
|
||||
public static String getExternalCacheFolder(@Nullable Context context) {
|
||||
if (context == null) return "";
|
||||
return context.getExternalCacheDir().getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get external files folder from sd card
|
||||
*
|
||||
* @param context android context
|
||||
* @return external files folder from sdcard
|
||||
*/
|
||||
public static String getExternalFilesFolder(@Nullable Context context) {
|
||||
if (context == null) return "";
|
||||
return context.getExternalFilesDir(null).getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine paths
|
||||
*
|
||||
* @param varargs path list
|
||||
* @return combined absolute path
|
||||
*/
|
||||
@NonNull
|
||||
public static String combinePaths(String... varargs) {
|
||||
if (varargs.length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
File parent = new File(varargs[0]);
|
||||
int i = 1;
|
||||
while (i < varargs.length) {
|
||||
parent = new File(parent, varargs[i++]);
|
||||
}
|
||||
return parent.getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* see this How-to for a faster way to convert
|
||||
* a byte array to a HEX string
|
||||
*
|
||||
* @param filename file name
|
||||
* @return md5 byte buffer
|
||||
*/
|
||||
@Nullable
|
||||
public static byte[] createChecksum(@Nullable String filename) throws Exception {
|
||||
if (!fileExists(filename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream fis = new FileInputStream(filename);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
MessageDigest complete = MessageDigest.getInstance("MD5");
|
||||
int numRead;
|
||||
|
||||
do {
|
||||
numRead = fis.read(buffer);
|
||||
if (numRead > 0) {
|
||||
complete.update(buffer, 0, numRead);
|
||||
}
|
||||
} while (numRead != -1);
|
||||
|
||||
fis.close();
|
||||
return complete.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* see this How-to for a faster way to convert
|
||||
* a byte array to a HEX string
|
||||
*
|
||||
* @param filename file name
|
||||
* @return md5 string
|
||||
*/
|
||||
@NonNull
|
||||
public static String getMD5Checksum(@NonNull String filename) {
|
||||
if (!fileExists(filename)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] b = createChecksum(filename);
|
||||
if (b == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (byte value : b) {
|
||||
result.append(Integer.toString((value & 0xff) + 0x100, 16).substring(1));
|
||||
}
|
||||
return result.toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list all files
|
||||
*
|
||||
* @param file file folder
|
||||
* @param includeFolder includeFolder
|
||||
* @return all files
|
||||
*/
|
||||
@Nullable
|
||||
public static ArrayList<File> listAllFiles(@Nullable File file, boolean includeFolder) {
|
||||
if (file == null || !file.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<File> files = new ArrayList<>();
|
||||
|
||||
if (file.isFile()) {
|
||||
files.add(file);
|
||||
} else if (file.isDirectory()) {
|
||||
if (includeFolder) {
|
||||
files.add(file);
|
||||
}
|
||||
|
||||
File[] filesArray = file.listFiles();
|
||||
if (filesArray == null || file.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (File fileFolder : filesArray) {
|
||||
ArrayList<File> subFiles = listAllFiles(fileFolder, includeFolder);
|
||||
if (subFiles == null || subFiles.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
files.addAll(subFiles);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* read lines from file
|
||||
*
|
||||
* @param file file
|
||||
* @return file lines
|
||||
*/
|
||||
@Nullable
|
||||
public static ArrayList<String> readLinesFromFile(@Nullable File file) {
|
||||
if (file == null || !file.exists() || !file.canRead()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FileReader fileReader = null;
|
||||
try {
|
||||
fileReader = new FileReader(file.getAbsolutePath());
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (fileReader == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> lines = new ArrayList<>();
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader, 1000 * 8192);
|
||||
try {
|
||||
String st;
|
||||
while ((st = bufferedReader.readLine()) != null) {
|
||||
lines.add(st);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String readTextFromFile(@Nullable File file) {
|
||||
if (file == null || !file.exists() || !file.canRead()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FileReader fileReader = null;
|
||||
try {
|
||||
fileReader = new FileReader(file.getAbsolutePath());
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (fileReader == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader, 1000 * 8192);
|
||||
try {
|
||||
String st;
|
||||
while ((st = bufferedReader.readLine()) != null) {
|
||||
sb.append(st).append('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getFileMD5(File file) {
|
||||
if (file == null) {
|
||||
return "";
|
||||
}
|
||||
String value = null;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0,
|
||||
file.length());
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.update(byteBuffer);
|
||||
BigInteger bi = new BigInteger(1, md5.digest());
|
||||
value = bi.toString(16);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class HttpUtils {
|
||||
|
||||
private static final OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(50000, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(50000, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
|
||||
public static void get(String url, OnNetWorkListener listener) {
|
||||
Request okHttpRequest = new Request.Builder()
|
||||
.url(url)
|
||||
.head()
|
||||
.build();
|
||||
|
||||
mOkHttpClient.newCall(okHttpRequest).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||
if (listener != null) {
|
||||
listener.onError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NotNull Call call, @NotNull Response response) {
|
||||
if (listener != null) {
|
||||
if (response.isSuccessful()) {
|
||||
listener.onSuccess(response);
|
||||
} else {
|
||||
listener.onFailure(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface OnNetWorkListener {
|
||||
void onSuccess(Object obj);
|
||||
|
||||
void onFailure(int code, String msg);
|
||||
|
||||
void onError();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class LogcatHelper {
|
||||
|
||||
private static LogcatHelper INSTANCE = null;
|
||||
private static String PATH_LOGCAT;
|
||||
private static String PATH_DIR = "LivePush";
|
||||
private LogDumper mLogDumper = null;
|
||||
private int mPId;
|
||||
|
||||
private void init(Context context) {
|
||||
|
||||
PATH_LOGCAT = context.getFilesDir().getAbsolutePath()
|
||||
+ File.separator + PATH_DIR;
|
||||
|
||||
File file = new File(PATH_LOGCAT);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public static LogcatHelper getInstance(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new LogcatHelper(context);
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private LogcatHelper(Context context) {
|
||||
init(context);
|
||||
mPId = android.os.Process.myPid();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
autoClear(PATH_LOGCAT);
|
||||
if (mLogDumper == null)
|
||||
mLogDumper = new LogDumper(String.valueOf(mPId), PATH_LOGCAT);
|
||||
|
||||
Log.d("LogcatHelper", "logcat thread " + mLogDumper.isAlive());
|
||||
if(!mLogDumper.isAlive()) {
|
||||
try {
|
||||
mLogDumper.start();
|
||||
} catch (IllegalThreadStateException e) {
|
||||
Log.e("LogcatHelper", "thread already started");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (mLogDumper != null) {
|
||||
mLogDumper.stopLogs();
|
||||
mLogDumper = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class LogDumper extends Thread {
|
||||
|
||||
private Process logcatProc;
|
||||
private BufferedReader mReader = null;
|
||||
private boolean mRunning = true;
|
||||
String cmds = null;
|
||||
private String mPID;
|
||||
private FileOutputStream out = null;
|
||||
|
||||
public LogDumper(String pid, String dir) {
|
||||
mPID = pid;
|
||||
try {
|
||||
out = new FileOutputStream(new File(dir, PATH_DIR + "-"
|
||||
+ LogcatDate.getFileName()+ ".log"), true);
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// cmds = "logcat *:e *:w | grep \"(" + mPID + ")\"";
|
||||
cmds = "logcat | grep \"(" + mPID + ")\"";//打印所有日志信息
|
||||
//cmds = "logcat";//打印所有日志信息
|
||||
// cmds = "logcat -s way";//打印标签过滤信息
|
||||
//cmds = "logcat *:e *:i | grep \"(" + mPID + ")\"";
|
||||
|
||||
}
|
||||
|
||||
public void stopLogs() {
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logcatProc = Runtime.getRuntime().exec(cmds);
|
||||
mReader = new BufferedReader(new InputStreamReader(
|
||||
logcatProc.getInputStream()), 1024);
|
||||
String line = null;
|
||||
while (mRunning && (line = mReader.readLine()) != null) {
|
||||
if (!mRunning) {
|
||||
break;
|
||||
}
|
||||
if (line.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isCreatNewFile(new File(PATH_LOGCAT, PATH_DIR + "-"
|
||||
+ LogcatDate.getFileName()+ ".log"))) {
|
||||
new File(PATH_LOGCAT, PATH_DIR + "-"
|
||||
+ LogcatDate.getFileName()+ ".log").renameTo(new File(PATH_LOGCAT, PATH_DIR + "-"
|
||||
+ LogcatDate.getDateEN()+ ".log"));
|
||||
try {
|
||||
out = new FileOutputStream(new File(PATH_LOGCAT, PATH_DIR + "-"
|
||||
+ LogcatDate.getFileName()+ ".log"), true);
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (out != null && line.contains(mPID)) {
|
||||
out.write((LogcatDate.getDateEN() + " " + line + "\n")
|
||||
.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (logcatProc != null) {
|
||||
logcatProc.destroy();
|
||||
logcatProc = null;
|
||||
}
|
||||
if (mReader != null) {
|
||||
try {
|
||||
mReader.close();
|
||||
mReader = null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
out = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isCreatNewFile(File file) {
|
||||
boolean bool = false;
|
||||
FileInputStream inputStream = null;
|
||||
if(file.exists()) {
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
//e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(inputStream != null) {
|
||||
try {
|
||||
if(inputStream.available()/1024.f/1024.f > 10) {
|
||||
bool = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return bool;
|
||||
}
|
||||
|
||||
private void autoClear(String dir) {
|
||||
|
||||
if(new File(dir).exists() && new File(dir).isDirectory()) {
|
||||
File[] files = new File(dir).listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
//大于2天
|
||||
if((System.currentTimeMillis() - file.lastModified()) / 1000 > 24 * 60 * 60 * 2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if(files != null && files.length > 0) {
|
||||
for(File file : files) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LogcatDate {
|
||||
public static String getFileName() {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String date = format.format(new Date(System.currentTimeMillis()));
|
||||
return date;
|
||||
}
|
||||
|
||||
public static String getDateEN() {
|
||||
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
|
||||
String date1 = format1.format(new Date(System.currentTimeMillis()));
|
||||
return date1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.LocationManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
public class NetWorkUtils {
|
||||
|
||||
/**
|
||||
* 判断是否有网络连接
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNetworkConnected(Context context) {
|
||||
if (context != null) {
|
||||
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
|
||||
if (networkInfo != null)
|
||||
return networkInfo.isAvailable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 判断WIFI网络是否可用
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static boolean isWifiConnected(Context context) {
|
||||
if (context != null) {
|
||||
// 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
|
||||
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
// 获取NetworkInfo对象
|
||||
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
|
||||
//判断NetworkInfo对象是否为空 并且类型是否为WIFI
|
||||
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI)
|
||||
return networkInfo.isAvailable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断MOBILE网络是否可用
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMobileConnected(Context context) {
|
||||
if (context != null) {
|
||||
//获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
|
||||
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
//获取NetworkInfo对象
|
||||
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
|
||||
//判断NetworkInfo对象是否为空 并且类型是否为MOBILE
|
||||
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE)
|
||||
return networkInfo.isAvailable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getConnectedType(Context context) {
|
||||
if (context != null) {
|
||||
//获取手机所有连接管理对象
|
||||
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
//获取NetworkInfo对象
|
||||
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
|
||||
if (networkInfo != null && networkInfo.isAvailable()) {
|
||||
//返回NetworkInfo的类型
|
||||
return networkInfo.getType();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* 获取当前的网络状态 :没有网络-0:WIFI网络1:4G网络-4:3G网络-3:2G网络-2
|
||||
* 自定义
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static int getAPNType(Context context) {
|
||||
int netType = 0;
|
||||
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
|
||||
//NetworkInfo对象为空 则代表没有网络
|
||||
if (networkInfo == null) {
|
||||
return netType;
|
||||
}
|
||||
int nType = networkInfo.getType();
|
||||
if (nType == ConnectivityManager.TYPE_WIFI) {
|
||||
//WIFI
|
||||
netType = 1;
|
||||
} else if (nType == ConnectivityManager.TYPE_MOBILE) {
|
||||
int nSubType = networkInfo.getSubtype();
|
||||
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
//3G 联通的3G为UMTS或HSDPA 电信的3G为EVDO
|
||||
if (nSubType == TelephonyManager.NETWORK_TYPE_LTE
|
||||
&& !telephonyManager.isNetworkRoaming()) {
|
||||
netType = 4;
|
||||
} else if (nSubType == TelephonyManager.NETWORK_TYPE_UMTS
|
||||
|| nSubType == TelephonyManager.NETWORK_TYPE_HSDPA
|
||||
|| nSubType == TelephonyManager.NETWORK_TYPE_EVDO_0
|
||||
&& !telephonyManager.isNetworkRoaming()) {
|
||||
netType = 3;
|
||||
//2G 移动和联通的2G为GPRS或EGDE,电信的2G为CDMA
|
||||
} else if (nSubType == TelephonyManager.NETWORK_TYPE_GPRS
|
||||
|| nSubType == TelephonyManager.NETWORK_TYPE_EDGE
|
||||
|| nSubType == TelephonyManager.NETWORK_TYPE_CDMA
|
||||
&& !telephonyManager.isNetworkRoaming()) {
|
||||
netType = 2;
|
||||
} else {
|
||||
netType = 2;
|
||||
}
|
||||
}
|
||||
return netType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by keria on 2022/4/6.
|
||||
*/
|
||||
final class SafeToastContext extends ContextWrapper {
|
||||
SafeToastContext(@NonNull Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getApplicationContext() {
|
||||
return new ApplicationContextWrapper(getBaseContext().getApplicationContext());
|
||||
}
|
||||
|
||||
private static final class ApplicationContextWrapper extends ContextWrapper {
|
||||
|
||||
private ApplicationContextWrapper(@NonNull Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSystemService(@NonNull String name) {
|
||||
if (Context.WINDOW_SERVICE.equals(name)) {
|
||||
return new WindowManagerWrapper((WindowManager) getBaseContext().getSystemService(name));
|
||||
}
|
||||
return super.getSystemService(name);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class WindowManagerWrapper implements WindowManager {
|
||||
|
||||
private static final String TAG = "WindowManagerWrapper";
|
||||
@NonNull
|
||||
private final WindowManager base;
|
||||
|
||||
private WindowManagerWrapper(@NonNull WindowManager base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Display getDefaultDisplay() {
|
||||
return base.getDefaultDisplay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewImmediate(View view) {
|
||||
base.removeViewImmediate(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View view, ViewGroup.LayoutParams params) {
|
||||
try {
|
||||
Log.d(TAG, "WindowManager's addView(view, params) has been hooked.");
|
||||
base.addView(view, params);
|
||||
} catch (BadTokenException e) {
|
||||
Log.i(TAG, e.getMessage());
|
||||
} catch (Throwable throwable) {
|
||||
Log.e(TAG, throwable.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
|
||||
base.updateViewLayout(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeView(View view) {
|
||||
base.removeView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by keria on 2022/10/12.
|
||||
* <p>
|
||||
* Android数据持久化
|
||||
*/
|
||||
public class SharedPrefUtils {
|
||||
|
||||
private static final String PREF_APP = "livepush";
|
||||
|
||||
private SharedPrefUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets boolean data.
|
||||
*
|
||||
* @param context the context
|
||||
* @param key the key
|
||||
* @param val default value
|
||||
* @return the boolean data
|
||||
*/
|
||||
public static boolean getBooleanData(@NonNull Context context, String key, boolean val) {
|
||||
return getSharedPref(context).getBoolean(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets int data.
|
||||
*
|
||||
* @param context the context
|
||||
* @param key the key
|
||||
* @param val default value
|
||||
* @return the int data
|
||||
*/
|
||||
public static int getIntData(@NonNull Context context, String key, int val) {
|
||||
return getSharedPref(context).getInt(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets string data.
|
||||
*
|
||||
* @param context the context
|
||||
* @param key the key
|
||||
* @param val default value
|
||||
* @return the string data
|
||||
*/
|
||||
public static String getStringData(@NonNull Context context, String key, String val) {
|
||||
return getSharedPref(context).getString(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data.
|
||||
*
|
||||
* @param context the context
|
||||
* @param key the key
|
||||
* @param val default value
|
||||
*/
|
||||
public static void saveData(@NonNull Context context, String key, String val) {
|
||||
getSharedPrefEditor(context).putString(key, val).apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data.
|
||||
*
|
||||
* @param context the context
|
||||
* @param key the key
|
||||
* @param val default value
|
||||
*/
|
||||
public static void saveData(@NonNull Context context, String key, int val) {
|
||||
getSharedPrefEditor(context).putInt(key, val).apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data.
|
||||
*
|
||||
* @param context the context
|
||||
* @param key the key
|
||||
* @param val default value
|
||||
*/
|
||||
public static void saveData(@NonNull Context context, String key, boolean val) {
|
||||
getSharedPrefEditor(context).putBoolean(key, val).apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data
|
||||
*
|
||||
* @param context the context
|
||||
*/
|
||||
public static void clear(@NonNull Context context) {
|
||||
getSharedPrefEditor(context).clear();
|
||||
}
|
||||
|
||||
private static SharedPreferences getSharedPref(@NonNull Context context) {
|
||||
return context.getSharedPreferences(PREF_APP, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
private static SharedPreferences.Editor getSharedPrefEditor(@NonNull Context context) {
|
||||
return getSharedPref(context).edit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class TextFormatUtil {
|
||||
|
||||
public static final String REGULAR = "[0-9a-zA-Z]{1,20}";
|
||||
|
||||
public static String getTextFormat(Context context, int id, Object... o) {
|
||||
String s = context.getResources().getString(id);
|
||||
return String.format(s, o);
|
||||
}
|
||||
|
||||
public static String getTextFormat(Context context, String paramString, Object... o) {
|
||||
int id = context.getResources().getIdentifier(paramString, "string", context.getPackageName());
|
||||
String s = context.getResources().getString(id);
|
||||
return String.format(s, o);
|
||||
}
|
||||
|
||||
public static String getTextFormat(Context context, int id) {
|
||||
return context.getResources().getString(id);
|
||||
}
|
||||
|
||||
public static String[] getTextArray(Context context, int id) {
|
||||
return context.getResources().getStringArray(id);
|
||||
}
|
||||
|
||||
public static int[] getIntArray(Context context, int id) {
|
||||
return context.getResources().getIntArray(id);
|
||||
}
|
||||
|
||||
public static int convertString2Int(String str) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return -1;
|
||||
}
|
||||
int number = -1;
|
||||
try {
|
||||
number = Integer.parseInt(str.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return number;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.alivc.live.commonutils;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class ToastUtils {
|
||||
|
||||
public static void show(final String content) {
|
||||
if (!TextUtils.isEmpty(content)) {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(ContextUtils.getSafeToastContext(), content, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
package com.alivc.live.commonutils.testexecutor;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author baorunchen
|
||||
* @date 2019/7/10
|
||||
* @brief 通过调度和执行任务来测试 API 在多线程、高并发场景下的可靠性
|
||||
* @note 每秒指定次数地切换线程执行任务,并随机在主线程上执行任务
|
||||
*/
|
||||
public class TestScheduledExecutor {
|
||||
private static final String TAG = "TestScheduledExecutor";
|
||||
|
||||
private static final int TASK_RETRY_COUNT = 3; // 可配置重试次数
|
||||
private static final int THREAD_POOL_SIZE = 8; // 线程池大小
|
||||
private static final long SHUTDOWN_TIMEOUT = 1000; // 线程池关闭等待时间,毫秒
|
||||
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private final ExecutorService[] threadPools = new ExecutorService[THREAD_POOL_SIZE];
|
||||
private final AtomicInteger currentPoolIndex = new AtomicInteger(0);
|
||||
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
private final Random random = new Random();
|
||||
|
||||
private final int taskInterval;
|
||||
private final Strategy strategy;
|
||||
private final PriorityBlockingQueue<PriorityTask> priorityQueue = new PriorityBlockingQueue<>();
|
||||
|
||||
public enum Strategy {
|
||||
DEFAULT,
|
||||
PRIORITY,
|
||||
RETRY,
|
||||
TIMEOUT,
|
||||
DELAY
|
||||
}
|
||||
|
||||
/**
|
||||
* 公共构造函数,初始化并启动任务调度
|
||||
*
|
||||
* @param tasks 要执行的任务列表
|
||||
* @param taskInterval 执行时间间隔(毫秒)
|
||||
* @param strategy 启用的策略
|
||||
*/
|
||||
public TestScheduledExecutor(final List<Runnable> tasks, int taskInterval, Strategy strategy) {
|
||||
this.taskInterval = taskInterval;
|
||||
this.strategy = strategy;
|
||||
|
||||
// 初始化多个线程池
|
||||
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
|
||||
threadPools[i] = Executors.newFixedThreadPool(1, new CustomThreadFactory("ThreadPool-" + (i + 1) + "-Thread-"));
|
||||
}
|
||||
|
||||
// 调度任务:按照指定时间间隔执行
|
||||
scheduler.scheduleAtFixedRate(() -> {
|
||||
int index = currentPoolIndex.getAndIncrement() % THREAD_POOL_SIZE;
|
||||
Runnable selectedTask = tasks.get(random.nextInt(tasks.size())); // 随机选择一个任务
|
||||
Runnable wrappedTask = wrapWithStrategy(selectedTask);
|
||||
|
||||
RunnableTask task = new RunnableTask(wrappedTask);
|
||||
if (strategy == Strategy.PRIORITY) {
|
||||
int priority = random.nextInt(100); // 设置任务的优先级
|
||||
priorityQueue.add(new PriorityTask(priority, task));
|
||||
executePriorityTask();
|
||||
} else {
|
||||
executeTask(index, task, random.nextBoolean());
|
||||
}
|
||||
}, 0, taskInterval, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公共构造函数,初始化并启动任务调度
|
||||
*
|
||||
* @param tasks 要执行的任务列表
|
||||
* @param taskInterval 执行时间间隔(毫秒)
|
||||
*/
|
||||
public TestScheduledExecutor(final List<Runnable> tasks, int taskInterval) {
|
||||
this(tasks, taskInterval, Strategy.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 只接受单个Runnable的构造函数
|
||||
*
|
||||
* @param runnable 要执行的任务
|
||||
* @param taskInterval 执行时间间隔(毫秒)
|
||||
*/
|
||||
public TestScheduledExecutor(Runnable runnable, int taskInterval) {
|
||||
this(Collections.singletonList(runnable), taskInterval, Strategy.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 只接受单个Runnable的构造函数
|
||||
*
|
||||
* @param runnable 要执行的任务
|
||||
* @param taskInterval 执行时间间隔(毫秒)
|
||||
* @param strategy 启用的策略
|
||||
*/
|
||||
public TestScheduledExecutor(Runnable runnable, int taskInterval, Strategy strategy) {
|
||||
this(Collections.singletonList(runnable), taskInterval, strategy);
|
||||
}
|
||||
|
||||
private Runnable wrapWithStrategy(Runnable task) {
|
||||
switch (strategy) {
|
||||
case DELAY:
|
||||
int delay = random.nextInt(taskInterval * 2);
|
||||
return new DelayTask(task, delay);
|
||||
case RETRY:
|
||||
return new RetryTask(task, TASK_RETRY_COUNT);
|
||||
case TIMEOUT:
|
||||
return new TimeoutTask(task, taskInterval * 2L);
|
||||
case PRIORITY:
|
||||
// 优先级调度在调度线程处理中
|
||||
return task;
|
||||
default:
|
||||
return task;
|
||||
}
|
||||
}
|
||||
|
||||
private void executePriorityTask() {
|
||||
if (!priorityQueue.isEmpty()) {
|
||||
PriorityTask priorityTask = priorityQueue.poll();
|
||||
if (priorityTask != null) {
|
||||
int index = currentPoolIndex.getAndIncrement() % THREAD_POOL_SIZE;
|
||||
executeTask(index, priorityTask, priorityTask.isMainThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void executeTask(int index, Runnable task, boolean isMainThread) {
|
||||
if (isMainThread) {
|
||||
mainHandler.post(task);
|
||||
} else {
|
||||
threadPools[index].execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁并清理资源
|
||||
*/
|
||||
public void destroy() {
|
||||
shutdownExecutor(scheduler, "Scheduler");
|
||||
for (ExecutorService threadPool : threadPools) {
|
||||
shutdownExecutor(threadPool, "ThreadPool");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装的关闭 Executor 服务的方法
|
||||
*
|
||||
* @param executor 要关闭的 Executor 服务
|
||||
* @param name Executor 服务的名称(用于日志)
|
||||
*/
|
||||
private static void shutdownExecutor(ExecutorService executor, String name) {
|
||||
if (executor == null) return;
|
||||
|
||||
executor.shutdown(); // 禁止提交新任务
|
||||
try {
|
||||
// 首先试图优雅地关闭
|
||||
if (!executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS)) {
|
||||
executor.shutdownNow(); // 如果优雅关闭超时,则强制关闭
|
||||
if (!executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS)) {
|
||||
Log.e(TAG, name + " did not terminate");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
executor.shutdownNow(); // 响应中断以强制关闭
|
||||
Thread.currentThread().interrupt(); // 恢复中断状态
|
||||
Log.e(TAG, "Interrupted while shutting down " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义线程工厂,用于设置线程的名称和属性
|
||||
*/
|
||||
private static class CustomThreadFactory implements ThreadFactory {
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
private final String namePrefix;
|
||||
|
||||
CustomThreadFactory(String namePrefix) {
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setName(namePrefix + threadNumber.getAndIncrement());
|
||||
t.setDaemon(false);
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义Runnable任务类
|
||||
*/
|
||||
private static class RunnableTask implements Runnable {
|
||||
private final Runnable runnable;
|
||||
|
||||
RunnableTask(Runnable runnable) {
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Executing task in " + Thread.currentThread().getName());
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务延迟策略
|
||||
*/
|
||||
private static class DelayTask implements Runnable {
|
||||
private final Runnable task;
|
||||
private final int delay;
|
||||
|
||||
public DelayTask(Runnable task, int delay) {
|
||||
this.task = task;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
Log.e(TAG, "Task interrupted in delay", e);
|
||||
}
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务重试策略
|
||||
*/
|
||||
private static class RetryTask implements Runnable {
|
||||
private final Runnable task;
|
||||
private final int maxRetries;
|
||||
|
||||
public RetryTask(Runnable task, int maxRetries) {
|
||||
this.task = task;
|
||||
this.maxRetries = maxRetries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int retryCount = 0;
|
||||
while (retryCount < maxRetries) {
|
||||
try {
|
||||
task.run();
|
||||
break; // 成功执行后退出循环
|
||||
} catch (Exception e) {
|
||||
retryCount++;
|
||||
if (retryCount >= maxRetries) {
|
||||
Log.e(TAG, "Task failed after " + maxRetries + " retries", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务超时策略
|
||||
*/
|
||||
private static class TimeoutTask implements Runnable {
|
||||
private final Runnable task;
|
||||
private final long timeout;
|
||||
|
||||
public TimeoutTask(Runnable task, long timeout) {
|
||||
this.task = task;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
Future<?> future = executor.submit(task);
|
||||
try {
|
||||
future.get(timeout, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
future.cancel(true);
|
||||
Log.e(TAG, "Task timed out", e);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Task execution failed", e);
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务优先级策略
|
||||
*/
|
||||
private static class PriorityTask implements Runnable, Comparable<PriorityTask> {
|
||||
private final int priority;
|
||||
private final Runnable task;
|
||||
private final boolean isMainThread;
|
||||
|
||||
public PriorityTask(int priority, Runnable task) {
|
||||
this(priority, task, false);
|
||||
}
|
||||
|
||||
public PriorityTask(int priority, Runnable task, boolean isMainThread) {
|
||||
this.priority = priority;
|
||||
this.task = task;
|
||||
this.isMainThread = isMainThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
task.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PriorityTask other) {
|
||||
return Integer.compare(other.priority, this.priority); // 高优先级任务优先
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package com.alivc.live.commonutils.viewhierarchy;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author baorunchen
|
||||
* @date 2024/5/16
|
||||
* @brief Monitor changes in view hierarchy and regularly print view hierarchy and overlaps
|
||||
*/
|
||||
|
||||
/****
|
||||
* @par Call Example
|
||||
* @code
|
||||
* private ViewHierarchyInspector mViewHierarchyInspector;
|
||||
*
|
||||
* @Override protected void onCreate(Bundle savedInstanceState) {
|
||||
* super.onCreate(savedInstanceState);
|
||||
*
|
||||
* // xxx;
|
||||
*
|
||||
* mViewHierarchyInspector = new ViewHierarchyInspector();
|
||||
* mViewHierarchyInspector.setTargetView(mOwnerFrameLayout);
|
||||
* mViewHierarchyInspector.setDecorView(getWindow().getDecorView());
|
||||
* }
|
||||
*
|
||||
* @Override protected void onDestroy() {
|
||||
* super.onDestroy();
|
||||
*
|
||||
* // xxx;
|
||||
*
|
||||
* if (mViewHierarchyInspector != null) {
|
||||
* mViewHierarchyInspector.destroy();
|
||||
* mViewHierarchyInspector = null;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
public class ViewHierarchyInspector {
|
||||
private static final String TAG = "ViewHierarchyInspector";
|
||||
|
||||
private static final long SCHEDULED_EXECUTOR_SERVICE_PERIOD = 2 * 1000L;
|
||||
private ScheduledExecutorService mScheduledExecutorService = null;
|
||||
|
||||
private View mTargetView = null;
|
||||
private View mDecorView = null;
|
||||
|
||||
/**
|
||||
* Sets the target view to inspect and starts the periodic inspection timer.
|
||||
* It logs the reference of the view assigned.
|
||||
*
|
||||
* @param targetView The target view to be inspected.
|
||||
*/
|
||||
public void setTargetView(View targetView) {
|
||||
Log.w(TAG, "[UI] setTargetView: [" + targetView + "]");
|
||||
mTargetView = targetView;
|
||||
startTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root view (decorView) from which the view hierarchy will be inspected.
|
||||
* It logs the reference of the view assigned.
|
||||
*
|
||||
* @param decorView The decorView (root view) of the Activity or Window.
|
||||
*/
|
||||
public void setDecorView(View decorView) {
|
||||
Log.w(TAG, "[UI] setDecorView: [" + decorView + "]");
|
||||
mDecorView = decorView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the inspection timer and releases the references to the view and decorView.
|
||||
* This should be called to clean up when the inspector is no longer needed.
|
||||
*/
|
||||
public void destroy() {
|
||||
stopTimer();
|
||||
mTargetView = null;
|
||||
mDecorView = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the traversal of the view tree to print the view hierarchy and check for overlaps.
|
||||
*/
|
||||
private void startInspector(View targetView) {
|
||||
if (mTargetView != null) {
|
||||
Log.i(TAG, "[UI][INSPECTOR][TRAVERSE]: ---------- " + targetView + " ----------");
|
||||
traverseViewTree(targetView);
|
||||
}
|
||||
|
||||
if (mTargetView != null && mDecorView != null) {
|
||||
Log.i(TAG, "[UI][INSPECTOR][OVERLAP]: ---------- " + mDecorView + " ----------");
|
||||
printViewHierarchyWithOverlap(mDecorView, mTargetView);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverses a view tree, Logging information about each child view.
|
||||
* This method should be used for debugging to understand the structure of a view tree.
|
||||
*
|
||||
* @param targetView The root of the view tree to traverse.
|
||||
*/
|
||||
private static void traverseViewTree(View targetView) {
|
||||
if (targetView instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup) targetView;
|
||||
Log.i(TAG, "[UI][TRAVERSE][VIEW_GROUP]: [" + viewGroup
|
||||
+ "], Children: [" + viewGroup.getChildCount() + "]");
|
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
||||
View childView = viewGroup.getChildAt(i);
|
||||
traverseViewTree(childView);
|
||||
Log.i(TAG, "[UI][TRAVERSE][CHILD]: [" + childView + "]");
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "[UI][TRAVERSE][VIEW]: [" + targetView + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a single-line representation of the view hierarchy starting from the root view,
|
||||
* marking the target view and any overlapping views.
|
||||
*
|
||||
* @param rootView The root view from which to start the traversal.
|
||||
* @param targetView The view to mark and check for overlaps.
|
||||
*/
|
||||
private static void printViewHierarchyWithOverlap(View rootView, View targetView) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Rect targetRect = new Rect();
|
||||
targetView.getGlobalVisibleRect(targetRect); // Get the global position of the target view.
|
||||
|
||||
buildViewHierarchyStringWithOverlap(rootView, targetView, targetRect, 0, builder);
|
||||
|
||||
// Print the built hierarchy string
|
||||
Log.i(TAG, "[UI][HIERARCHY][ " + builder + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverses the view hierarchy, checking for overlap with the target view
|
||||
* and appending to the StringBuilder instance.
|
||||
*
|
||||
* @param rootView The current view being inspected.
|
||||
* @param targetView The target view to mark and check for overlaps.
|
||||
* @param targetRect The global visible rectangle of the target view for overlap testing.
|
||||
* @param depth The depth in the view hierarchy.
|
||||
* @param builder The StringBuilder used to build the output string.
|
||||
*/
|
||||
private static void buildViewHierarchyStringWithOverlap(View rootView, View targetView, Rect targetRect, int depth, StringBuilder builder) {
|
||||
builder.append("\n|");
|
||||
// Append dashes to indicate the depth of the view in the hierarchy
|
||||
for (int i = 0; i < depth; i++) {
|
||||
builder.append("-");
|
||||
}
|
||||
builder.append("[").append(depth).append("]");
|
||||
|
||||
// Append visibility status of the view.
|
||||
String visibilityStatus = getVisibilityStatus(rootView);
|
||||
builder.append("[").append(visibilityStatus).append("]");
|
||||
|
||||
if (rootView == targetView) {
|
||||
builder.append("[!TARGET]");
|
||||
}
|
||||
|
||||
// Check for overlap and append the overlap marker if needed
|
||||
Rect viewRect = new Rect();
|
||||
rootView.getGlobalVisibleRect(viewRect);
|
||||
if (Rect.intersects(viewRect, targetRect) && rootView != targetView) {
|
||||
builder.append("[!OVERLAP]");
|
||||
}
|
||||
|
||||
builder.append(rootView);
|
||||
|
||||
// If the view is a ViewGroup, recursively process its children
|
||||
if (rootView instanceof ViewGroup) {
|
||||
ViewGroup viewGroup = (ViewGroup) rootView;
|
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
||||
buildViewHierarchyStringWithOverlap(viewGroup.getChildAt(i), targetView, targetRect, depth + 1, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the visibility status of a view as a string.
|
||||
*
|
||||
* @param view The view whose visibility status is to be determined.
|
||||
* @return A string representing the visibility status of the view.
|
||||
*/
|
||||
private static String getVisibilityStatus(View view) {
|
||||
switch (view.getVisibility()) {
|
||||
case View.VISIBLE:
|
||||
return "VISIBLE";
|
||||
case View.INVISIBLE:
|
||||
return "INVISIBLE";
|
||||
case View.GONE:
|
||||
return "GONE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a scheduled executor service with a fixed delay to periodically inspect the view hierarchy.
|
||||
* The inspection looks for overlapping views in the hierarchy and logs them.
|
||||
*/
|
||||
private void startTimer() {
|
||||
stopTimer();
|
||||
mScheduledExecutorService = Executors.newScheduledThreadPool(8);
|
||||
mScheduledExecutorService.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startInspector(mTargetView);
|
||||
}
|
||||
}, 0, SCHEDULED_EXECUTOR_SERVICE_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the scheduled executor service and waits for its termination.
|
||||
* If the service doesn't terminate within the specified timeout, it's shut down immediately.
|
||||
*/
|
||||
private void stopTimer() {
|
||||
try {
|
||||
if (mScheduledExecutorService != null) {
|
||||
mScheduledExecutorService.shutdown();
|
||||
if (!mScheduledExecutorService.awaitTermination(1000, TimeUnit.MICROSECONDS)) {
|
||||
mScheduledExecutorService.shutdownNow();
|
||||
}
|
||||
mScheduledExecutorService = null;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
if (mScheduledExecutorService != null) {
|
||||
mScheduledExecutorService.shutdownNow();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
LiveCommon/live_commonutils/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
<color name="thumbGradient">#eeeeee</color>
|
||||
<color name="trackGradient">#888888</color>
|
||||
|
||||
<color name="red">#ffff0000</color>
|
||||
<color name="darker_gray">#aaa</color>
|
||||
<color name="text_blue">#2d44f4</color>
|
||||
|
||||
<color name="yellow">#ffff00</color>
|
||||
<color name="transparent">#50000000</color>
|
||||
|
||||
<color name="text_green">#00c0fb</color>
|
||||
<color name="text_black">#333333</color>
|
||||
<color name="wheel_white">#FFFFFF</color>
|
||||
<color name="alivc_version_color">#8C8C8C</color>
|
||||
<color name="wheel_text_color_2">#666666</color>
|
||||
<color name="alivc_color_gry">#e0e0e0</color>
|
||||
<color name="wheel_text_color_1">#333333</color>
|
||||
<color name="alivc_color_black">#000</color>
|
||||
<color name="color_bg_model">#F9F9F9</color>
|
||||
<color name="text_color_model_name">#161A23</color>
|
||||
<color name="color_bg_border_model">#dde0e5</color>
|
||||
<color name="color_background_green">#1AED99</color>
|
||||
<color name="color_background_black_alpha_30">#3323262F</color>
|
||||
<color name="color_title_text_black">#111111</color>
|
||||
<color name="color_background_white">#ffffffff</color>
|
||||
<color name="wheel_black">#000000</color>
|
||||
<color name="color_text_white">#fff</color>
|
||||
<color name="color_text_grey">#A1A1A1</color>
|
||||
<color name="grey_bg_color">#F4F4F4</color>
|
||||
<color name="title_bg_grey_color">#FAFAFA</color>
|
||||
<color name="switch_bar_on_color">#365AFF</color>
|
||||
<color name="tips_color">#D93026</color>
|
||||
<color name="title_color">#555555</color>
|
||||
<color name="color_07C2DE">#07C2DE</color>
|
||||
<color name="shape_red_rectangle">#F53F3F</color>
|
||||
<color name="border_medium">#3A3D48</color>
|
||||
<color name="text_strong">#FCFCFD</color>
|
||||
<color name="fill_weak">#23262F</color>
|
||||
<color name="colourful_border_weak">#B2EBF2</color>
|
||||
<color name="bg_weak">#1C1D22</color>
|
||||
<color name="text_medium">#E6E7EC</color>
|
||||
<color name="text_ultraweak">#747A8C</color>
|
||||
<color name="colourful_ic_strong">#4DCFE1</color>
|
||||
<color name="border_infrared">#23262F</color>
|
||||
<color name="ic_ultraweak">#3A3D48</color>
|
||||
<color name="text_weak">#B2B7C4</color>
|
||||
<color name="colourful_text_strong">#4DCFE1</color>
|
||||
<color name="push_btn_border_color">#EDEDED</color>
|
||||
<color name="body_txt_color">#ff16243c</color>
|
||||
<color name="text_true_color">#FF6500</color>
|
||||
<color name="main_color">#FFFFFF</color>
|
||||
|
||||
<color name="sound_effect_background">#DDDDDD</color>
|
||||
</resources>
|
||||
42
LiveCommon/live_commonutils/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="font_size_40px">20.0sp</dimen>
|
||||
<dimen name="font_size_36px">18.0sp</dimen>
|
||||
<dimen name="font_size_32px">16.0sp</dimen>
|
||||
<dimen name="font_size_30px">15.0sp</dimen>
|
||||
<dimen name="font_size_28px">14.0sp</dimen>
|
||||
<dimen name="font_size_24px">12.0sp</dimen>
|
||||
<dimen name="view_line_width">0.1dp</dimen>
|
||||
<dimen name="view_size_text_14">14dp</dimen>
|
||||
<dimen name="view_size_text_16">16dp</dimen>
|
||||
<dimen name="view_size_text_17">17dp</dimen>
|
||||
<dimen name="view_margin_36">36dp</dimen>
|
||||
<dimen name="view_margin_2">2dp</dimen>
|
||||
<dimen name="view_margin_8">8dp</dimen>
|
||||
<dimen name="view_margin_9">9dp</dimen>
|
||||
<dimen name="view_margin_10">10dp</dimen>
|
||||
<dimen name="view_margin_12">12dp</dimen>
|
||||
<dimen name="view_margin_15">15dp</dimen>
|
||||
<dimen name="view_margin_18">18dp</dimen>
|
||||
<dimen name="view_margin_20">20dp</dimen>
|
||||
<dimen name="view_margin_22">22dp</dimen>
|
||||
<dimen name="view_margin_24">24dp</dimen>
|
||||
<dimen name="view_margin_25">25dp</dimen>
|
||||
<dimen name="view_margin_30">30dp</dimen>
|
||||
<dimen name="view_margin_40">40dp</dimen>
|
||||
<dimen name="view_margin_65">65dp</dimen>
|
||||
<dimen name="view_margin_75">75dp</dimen>
|
||||
<dimen name="view_margin_85">85dp</dimen>
|
||||
<dimen name="view_margin_110">110dp</dimen>
|
||||
<dimen name="view_margin_140">140dp</dimen>
|
||||
<dimen name="view_margin_261">261dp</dimen>
|
||||
<dimen name="view_margin_310">310dp</dimen>
|
||||
<dimen name="view_margin_330">330dp</dimen>
|
||||
<dimen name="view_width_size_64">64dp</dimen>
|
||||
<dimen name="view_height_size_32">32dp</dimen>
|
||||
<dimen name="view_height_size_36">36dp</dimen>
|
||||
<dimen name="view_height_size_44">44dp</dimen>
|
||||
<dimen name="view_height_size_45">45dp</dimen>
|
||||
<dimen name="view_version_size_text_12">12dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
</resources>
|
||||