集成完直播后提交代码

This commit is contained in:
xuhuixiang
2026-02-06 14:55:21 +08:00
commit ea9ffa06ff
960 changed files with 75063 additions and 0 deletions

1
LiveBasic/live_screencap/.gitignore vendored Normal file
View File

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

View File

@@ -0,0 +1,35 @@
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 {
implementation externalAndroidDesign
implementation externalSimpleZXing
implementation project(':LiveCommon:live_commonbiz')
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alivc.live.baselive_recording">
<uses-permission android:name="android.permission.REORDER_TASKS" />
<application>
<!-- 请务必添加service否则会因系统权限不足导致推流黑屏 -->
<service
android:name=".service.ForegroundService"
android:enabled="true"
android:foregroundServiceType="mediaProjection|camera" />
<activity
android:name=".ui.VideoRecordConfigActivity"
android:alwaysRetainTaskState="true"
android:configChanges="uiMode"
android:screenOrientation="portrait"
android:theme="@style/AVLiveTheme" />
</application>
</manifest>

View File

@@ -0,0 +1,182 @@
package com.alivc.live.baselive_recording;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.view.Gravity;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import com.alivc.live.baselive_recording.ui.widget.VideoRecordSmallView;
import com.alivc.live.baselive_recording.ui.widget.VideoRecordCameraPreviewView;
import com.alivc.live.pusher.AlivcLivePusher;
import java.lang.reflect.Field;
public class VideoRecordViewManager {
private static VideoRecordSmallView mVideoRecordSmallWindow;
private static LayoutParams mVideoRecordWindowParams;
private static VideoRecordCameraPreviewView mVideoRecordCameraPreviewWindow;
private static LayoutParams mVideoRecordCameraWindowParams;
private static WindowManager mWindowManager;
public static void createViewoRecordWindow(Activity activity, Context context, AlivcLivePusher pusher, CameraOn listener) {
WindowManager windowManager = getWindowManager(context);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
if (mVideoRecordSmallWindow == null) {
mVideoRecordSmallWindow = new VideoRecordSmallView(context, activity.getTaskId());
if (mVideoRecordWindowParams == null) {
mVideoRecordWindowParams = new LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mVideoRecordWindowParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mVideoRecordWindowParams.type = LayoutParams.TYPE_PHONE;
}
mVideoRecordWindowParams.format = PixelFormat.RGBA_8888;
mVideoRecordWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL |
LayoutParams.FLAG_NOT_FOCUSABLE |
LayoutParams.FLAG_HARDWARE_ACCELERATED;
mVideoRecordWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
mVideoRecordWindowParams.width = LayoutParams.WRAP_CONTENT;
mVideoRecordWindowParams.height = LayoutParams.WRAP_CONTENT;
mVideoRecordWindowParams.x = screenWidth;
mVideoRecordWindowParams.y = screenHeight * 4 / 5;
}
mVideoRecordSmallWindow.setParams(pusher, mVideoRecordWindowParams);
mVideoRecordSmallWindow.setCameraOnListern(listener);
windowManager.addView(mVideoRecordSmallWindow, mVideoRecordWindowParams);
}
}
public interface CameraOn {
public void onCameraOn(boolean on);
}
public static void hideViewRecordWindow() {
if (mVideoRecordSmallWindow != null) {
mVideoRecordSmallWindow.setVisible(false);
}
}
public static void showViewRecordWindow() {
if (mVideoRecordSmallWindow != null) {
mVideoRecordSmallWindow.setVisible(true);
}
}
public static void removeVideoRecordWindow(Context context) {
if (mVideoRecordSmallWindow != null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(mVideoRecordSmallWindow);
mVideoRecordSmallWindow = null;
}
}
public static void createViewoRecordCameraWindow(Activity activity, Context context, AlivcLivePusher pusher) {
WindowManager windowManager = getWindowManager(context);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
if (mVideoRecordCameraPreviewWindow == null) {
mVideoRecordCameraPreviewWindow = new VideoRecordCameraPreviewView(activity, context);
if (mVideoRecordCameraWindowParams == null) {
mVideoRecordCameraWindowParams = new LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mVideoRecordCameraWindowParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mVideoRecordCameraWindowParams.type = LayoutParams.TYPE_PHONE;
}
mVideoRecordCameraWindowParams.format = PixelFormat.RGBA_8888;
mVideoRecordCameraWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
mVideoRecordCameraWindowParams.gravity = Gravity.START | Gravity.TOP;
mVideoRecordCameraWindowParams.width = VideoRecordCameraPreviewView.viewWidth;
mVideoRecordCameraWindowParams.height = VideoRecordCameraPreviewView.viewHeight;
mVideoRecordCameraWindowParams.x = screenWidth - dip2px(context, 106);
mVideoRecordCameraWindowParams.y = 0;
}
mVideoRecordCameraPreviewWindow.setParams(pusher, mVideoRecordCameraWindowParams);
windowManager.addView(mVideoRecordCameraPreviewWindow, mVideoRecordCameraWindowParams);
}
if (mVideoRecordSmallWindow != null) {
//mVideoRecordSmallWindow.setSurfaceView(mVideoRecordCameraPreviewWindow.getSurfaceView());
}
}
public static void removeVideoRecordCameraWindow(Context context) {
if (mVideoRecordCameraPreviewWindow != null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(mVideoRecordCameraPreviewWindow);
mVideoRecordCameraPreviewWindow = null;
}
}
public static void setCameraPreviewVisible(boolean visible) {
mVideoRecordCameraPreviewWindow.setVisible(visible);
}
private static WindowManager getWindowManager(Context context) {
if (mWindowManager == null) {
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
return mWindowManager;
}
public static boolean permission(Context context) {
boolean permission = true;
if (Build.VERSION.SDK_INT >= 23) {
try {
if (!Settings.canDrawOverlays(context)) {
Class clazz = Settings.class;
Field field = clazz.getDeclaredField("ACTION_MANAGE_OVERLAY_PERMISSION");
Intent intent = new Intent(field.get(null).toString());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
permission = false;
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
}
return permission;
}
public static void refreshFloatWindowPosition() {
if (mVideoRecordCameraPreviewWindow != null) {
mVideoRecordCameraPreviewWindow.refreshPosition();
}
}
public static SurfaceView getCameraView() {
if (mVideoRecordCameraPreviewWindow != null) {
return mVideoRecordCameraPreviewWindow.getSurfaceView();
}
return null;
}
/**
* 将dip或dp值转换为px值保证尺寸大小不变
*
* @param dipValue
* @param dipValue DisplayMetrics类中属性density
* @return
*/
private 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);
}
}

View File

@@ -0,0 +1,268 @@
/*
* Copyright (C) 2016 Facishare Technology Co., Ltd. All Rights Reserved.
*/
package com.alivc.live.baselive_recording.floatwindowpermission;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import com.alivc.live.commonui.dialog.CommonDialog;
import com.alivc.live.baselive_recording.R;
import com.alivc.live.baselive_recording.floatwindowpermission.rom.MiuiUtils;
import com.alivc.live.baselive_recording.floatwindowpermission.rom.OppoUtils;
import com.alivc.live.baselive_recording.floatwindowpermission.rom.QikuUtils;
import com.alivc.live.baselive_recording.floatwindowpermission.rom.RomUtils;
import com.alivc.live.baselive_recording.floatwindowpermission.rom.HuaweiUtils;
import com.alivc.live.baselive_recording.floatwindowpermission.rom.MeizuUtils;
import com.alivc.live.commonutils.TextFormatUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Description:
*
* @author zhaozp
* @since 2016-10-17
*/
public class FloatWindowManager {
private static final String TAG = "FloatWindowManager";
private static volatile FloatWindowManager instance;
private CommonDialog dialog;
public static FloatWindowManager getInstance() {
if (instance == null) {
synchronized (FloatWindowManager.class) {
if (instance == null) {
instance = new FloatWindowManager();
}
}
}
return instance;
}
public boolean applyFloatWindow(Context context) {
if (checkPermission(context)) {
return true;
}
applyPermission(context);
return false;
}
private static boolean checkPermission(Context context) {
//6.0 版本之后由于 google 增加了对悬浮窗权限的管理,所以方式就统一了
if (Build.VERSION.SDK_INT < 23) {
if (RomUtils.checkIsMiuiRom()) {
return miuiPermissionCheck(context);
} else if (RomUtils.checkIsMeizuRom()) {
return meizuPermissionCheck(context);
} else if (RomUtils.checkIsHuaweiRom()) {
return huaweiPermissionCheck(context);
} else if (RomUtils.checkIs360Rom()) {
return qikuPermissionCheck(context);
} else if (RomUtils.checkIsOppoRom()) {
return oppoROMPermissionCheck(context);
}
}
return commonROMPermissionCheck(context);
}
private static boolean huaweiPermissionCheck(Context context) {
return HuaweiUtils.checkFloatWindowPermission(context);
}
private static boolean miuiPermissionCheck(Context context) {
return MiuiUtils.checkFloatWindowPermission(context);
}
private static boolean meizuPermissionCheck(Context context) {
return MeizuUtils.checkFloatWindowPermission(context);
}
private static boolean qikuPermissionCheck(Context context) {
return QikuUtils.checkFloatWindowPermission(context);
}
private static boolean oppoROMPermissionCheck(Context context) {
return OppoUtils.checkFloatWindowPermission(context);
}
private static boolean commonROMPermissionCheck(Context context) {
//最新发现魅族6.0的系统这种方式不好用,天杀的,只有你是奇葩,没办法,单独适配一下
if (RomUtils.checkIsMeizuRom()) {
return meizuPermissionCheck(context);
} else {
Boolean result = true;
if (Build.VERSION.SDK_INT >= 23) {
try {
Class clazz = Settings.class;
Method canDrawOverlays = clazz.getDeclaredMethod("canDrawOverlays", Context.class);
result = (Boolean) canDrawOverlays.invoke(null, context);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
}
return result;
}
}
private void applyPermission(Context context) {
if (Build.VERSION.SDK_INT < 23) {
if (RomUtils.checkIsMiuiRom()) {
miuiROMPermissionApply(context);
} else if (RomUtils.checkIsMeizuRom()) {
meizuROMPermissionApply(context);
} else if (RomUtils.checkIsHuaweiRom()) {
huaweiROMPermissionApply(context);
} else if (RomUtils.checkIs360Rom()) {
rom360PermissionApply(context);
} else if (RomUtils.checkIsOppoRom()) {
oppoROMPermissionApply(context);
}
}
commonROMPermissionApply(context);
}
private void rom360PermissionApply(final Context context) {
showConfirmDialog(context, new OnConfirmResult() {
@Override
public void confirmResult(boolean confirm) {
if (confirm) {
QikuUtils.applyPermission(context);
} else {
Log.e(TAG, "ROM:360, user manually refuse OVERLAY_PERMISSION");
}
}
});
}
private void huaweiROMPermissionApply(final Context context) {
showConfirmDialog(context, new OnConfirmResult() {
@Override
public void confirmResult(boolean confirm) {
if (confirm) {
HuaweiUtils.applyPermission(context);
} else {
Log.e(TAG, "ROM:huawei, user manually refuse OVERLAY_PERMISSION");
}
}
});
}
private void meizuROMPermissionApply(final Context context) {
showConfirmDialog(context, new OnConfirmResult() {
@Override
public void confirmResult(boolean confirm) {
if (confirm) {
MeizuUtils.applyPermission(context);
} else {
Log.e(TAG, "ROM:meizu, user manually refuse OVERLAY_PERMISSION");
}
}
});
}
private void miuiROMPermissionApply(final Context context) {
showConfirmDialog(context, new OnConfirmResult() {
@Override
public void confirmResult(boolean confirm) {
if (confirm) {
MiuiUtils.applyMiuiPermission(context);
} else {
Log.e(TAG, "ROM:miui, user manually refuse OVERLAY_PERMISSION");
}
}
});
}
private void oppoROMPermissionApply(final Context context) {
showConfirmDialog(context, new OnConfirmResult() {
@Override
public void confirmResult(boolean confirm) {
if (confirm) {
OppoUtils.applyOppoPermission(context);
} else {
Log.e(TAG, "ROM:miui, user manually refuse OVERLAY_PERMISSION");
}
}
});
}
/**
* 通用 rom 权限申请
*/
private void commonROMPermissionApply(final Context context) {
//这里也一样,魅族系统需要单独适配
if (RomUtils.checkIsMeizuRom()) {
meizuROMPermissionApply(context);
} else {
if (Build.VERSION.SDK_INT >= 23) {
showConfirmDialog(context, new OnConfirmResult() {
@Override
public void confirmResult(boolean confirm) {
if (confirm) {
try {
commonROMPermissionApplyInternal(context);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
} else {
Log.d(TAG, "user manually refuse OVERLAY_PERMISSION");
//需要做统计效果
}
}
});
}
}
}
public static void commonROMPermissionApplyInternal(Context context) throws NoSuchFieldException, IllegalAccessException {
Class clazz = Settings.class;
Field field = clazz.getDeclaredField("ACTION_MANAGE_OVERLAY_PERMISSION");
Intent intent = new Intent(field.get(null).toString());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
private void showConfirmDialog(Context context, OnConfirmResult result) {
showConfirmDialog(context, context.getString(R.string.permission_float_deny_toast), result);
}
private void showConfirmDialog(Context context, String message, final OnConfirmResult result) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
dialog = new CommonDialog(context);
dialog.setDialogContent(message);
dialog.setConfirmButton(TextFormatUtil.getTextFormat(context,R.string.permission_alert_submit_tip), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirmResult(true);
dialog.dismiss();
}
});
dialog.setCancelButton(TextFormatUtil.getTextFormat(context, R.string.permission_alert_cancel_tip), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirmResult(false);
dialog.dismiss();
}
});
dialog.show();
}
private interface OnConfirmResult {
void confirmResult(boolean confirm);
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2016 Facishare Technology Co., Ltd. All Rights Reserved.
*/
package com.alivc.live.baselive_recording.floatwindowpermission.rom;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import java.lang.reflect.Method;
public class HuaweiUtils {
private static final String TAG = "HuaweiUtils";
/**
* 检测 Huawei 悬浮窗权限
*/
public static boolean checkFloatWindowPermission(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, 24); //OP_SYSTEM_ALERT_WINDOW = 24;
}
return true;
}
/**
* 去华为权限申请页面
*/
public static void applyPermission(Context context) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity");//悬浮窗管理页面
intent.setComponent(comp);
if (RomUtils.getEmuiVersion() == 3.1) {
//emui 3.1 的适配
context.startActivity(intent);
} else {
//emui 3.0 的适配
comp = new ComponentName("com.huawei.systemmanager", "com.huawei.notificationmanager.ui.NotificationManagmentActivity");//悬浮窗管理页面
intent.setComponent(comp);
context.startActivity(intent);
}
} catch (SecurityException e) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// ComponentName comp = new ComponentName("com.huawei.systemmanager","com.huawei.permissionmanager.ui.MainActivity");//华为权限管理
ComponentName comp = new ComponentName("com.huawei.systemmanager",
"com.huawei.permissionmanager.ui.MainActivity");//华为权限管理跳转到本app的权限管理页面,这个需要华为接口权限,未解决
// ComponentName comp = new ComponentName("com.huawei.systemmanager","com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity");//悬浮窗管理页面
intent.setComponent(comp);
context.startActivity(intent);
Log.e(TAG, Log.getStackTraceString(e));
} catch (ActivityNotFoundException e) {
/**
* 手机管家版本较低 HUAWEI SC-UL10
*/
// Toast.makeText(MainActivity.this, "act找不到", Toast.LENGTH_LONG).show();
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName comp = new ComponentName("com.Android.settings", "com.android.settings.permission.TabItem");//权限管理页面 android4.4
// ComponentName comp = new ComponentName("com.android.settings","com.android.settings.permission.single_app_activity");//此处可跳转到指定app对应的权限管理页面但是需要相关权限未解决
intent.setComponent(comp);
context.startActivity(intent);
e.printStackTrace();
Log.e(TAG, Log.getStackTraceString(e));
} catch (Exception e) {
//抛出异常时提示信息
Toast.makeText(context, "进入设置页面失败,请手动设置", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Class clazz = AppOpsManager.class;
Method method = clazz.getDeclaredMethod("checkOp", int.class, int.class, String.class);
return AppOpsManager.MODE_ALLOWED == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
} else {
Log.e(TAG, "Below API 19 cannot invoke!");
}
return false;
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2016 Facishare Technology Co., Ltd. All Rights Reserved.
*/
package com.alivc.live.baselive_recording.floatwindowpermission.rom;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.util.Log;
import com.alivc.live.baselive_recording.floatwindowpermission.FloatWindowManager;
import java.lang.reflect.Method;
public class MeizuUtils {
private static final String TAG = "MeizuUtils";
/**
* 检测 meizu 悬浮窗权限
*/
public static boolean checkFloatWindowPermission(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, 24); //OP_SYSTEM_ALERT_WINDOW = 24;
}
return true;
}
/**
* 去魅族权限申请页面
*/
public static void applyPermission(Context context) {
try {
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
intent.setClassName("com.meizu.safe", "com.meizu.safe.security.AppSecActivity");
intent.putExtra("packageName", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}catch (Exception e) {
try {
Log.e(TAG, "获取悬浮窗权限, 打开AppSecActivity失败, " + Log.getStackTraceString(e));
// 最新的魅族flyme 6.2.5 用上述方法获取权限失败, 不过又可以用下述方法获取权限了
FloatWindowManager.commonROMPermissionApplyInternal(context);
} catch (Exception eFinal) {
Log.e(TAG, "获取悬浮窗权限失败, 通用获取方法失败, " + Log.getStackTraceString(eFinal));
}
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Class clazz = AppOpsManager.class;
Method method = clazz.getDeclaredMethod("checkOp", int.class, int.class, String.class);
return AppOpsManager.MODE_ALLOWED == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
} else {
Log.e(TAG, "Below API 19 cannot invoke!");
}
return false;
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2016 Facishare Technology Co., Ltd. All Rights Reserved.
*/
package com.alivc.live.baselive_recording.floatwindowpermission.rom;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import java.lang.reflect.Method;
public class MiuiUtils {
private static final String TAG = "MiuiUtils";
/**
* 获取小米 rom 版本号,获取失败返回 -1
*
* @return miui rom version code, if fail , return -1
*/
public static int getMiuiVersion() {
String version = RomUtils.getSystemProperty("ro.miui.ui.version.name");
if (version != null) {
try {
return Integer.parseInt(version.substring(1));
} catch (Exception e) {
Log.e(TAG, "get miui version code error, version : " + version);
Log.e(TAG, Log.getStackTraceString(e));
}
}
return -1;
}
/**
* 检测 miui 悬浮窗权限
*/
public static boolean checkFloatWindowPermission(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, 24); //OP_SYSTEM_ALERT_WINDOW = 24;
} else {
// if ((context.getApplicationInfo().flags & 1 << 27) == 1) {
// return true;
// } else {
// return false;
// }
return true;
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Class clazz = AppOpsManager.class;
Method method = clazz.getDeclaredMethod("checkOp", int.class, int.class, String.class);
return AppOpsManager.MODE_ALLOWED == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
} else {
Log.e(TAG, "Below API 19 cannot invoke!");
}
return false;
}
/**
* 小米 ROM 权限申请
*/
public static void applyMiuiPermission(Context context) {
int versionCode = getMiuiVersion();
if (versionCode == 5) {
goToMiuiPermissionActivityV5(context);
} else if (versionCode == 6) {
goToMiuiPermissionActivityV6(context);
} else if (versionCode == 7) {
goToMiuiPermissionActivityV7(context);
} else if (versionCode == 8) {
goToMiuiPermissionActivityV8(context);
} else {
Log.e(TAG, "this is a special MIUI rom version, its version code " + versionCode);
}
}
private static boolean isIntentAvailable(Intent intent, Context context) {
if (intent == null) {
return false;
}
return context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
/**
* 小米 V5 版本 ROM权限申请
*/
public static void goToMiuiPermissionActivityV5(Context context) {
Intent intent = null;
String packageName = context.getPackageName();
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", packageName, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
Log.e(TAG, "intent is not available!");
}
//设置页面在应用详情页面
// Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
// PackageInfo pInfo = null;
// try {
// pInfo = context.getPackageManager().getPackageInfo
// (HostInterfaceManager.getHostInterface().getApp().getPackageName(), 0);
// } catch (PackageManager.NameNotFoundException e) {
// AVLogUtils.e(TAG, e.getMessage());
// }
// intent.setClassName("com.android.settings", "com.miui.securitycenter.permission.AppPermissionsEditor");
// intent.putExtra("extra_package_uid", pInfo.applicationInfo.uid);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// if (isIntentAvailable(intent, context)) {
// context.startActivity(intent);
// } else {
// AVLogUtils.e(TAG, "Intent is not available!");
// }
}
/**
* 小米 V6 版本 ROM权限申请
*/
public static void goToMiuiPermissionActivityV6(Context context) {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
Log.e(TAG, "Intent is not available!");
}
}
/**
* 小米 V7 版本 ROM权限申请
*/
public static void goToMiuiPermissionActivityV7(Context context) {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
Log.e(TAG, "Intent is not available!");
}
}
/**
* 小米 V8 版本 ROM权限申请
*/
public static void goToMiuiPermissionActivityV8(Context context) {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
// intent.setPackage("com.miui.securitycenter");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.setPackage("com.miui.securitycenter");
intent.putExtra("extra_pkgname", context.getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
Log.e(TAG, "Intent is not available!");
}
}
}
}

View File

@@ -0,0 +1,70 @@
package com.alivc.live.baselive_recording.floatwindowpermission.rom;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Method;
/**
* Description:
*
* @author Shawn_Dut
* @since 2018-02-01
*/
public class OppoUtils {
private static final String TAG = "OppoUtils";
/**
* 检测 360 悬浮窗权限
*/
public static boolean checkFloatWindowPermission(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, 24); //OP_SYSTEM_ALERT_WINDOW = 24;
}
return true;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Class clazz = AppOpsManager.class;
Method method = clazz.getDeclaredMethod("checkOp", int.class, int.class, String.class);
return AppOpsManager.MODE_ALLOWED == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
} else {
Log.e(TAG, "Below API 19 cannot invoke!");
}
return false;
}
/**
* oppo ROM 权限申请
*/
public static void applyOppoPermission(Context context) {
//merge request from https://github.com/zhaozepeng/FloatWindowPermission/pull/26
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//com.coloros.safecenter/.sysfloatwindow.FloatWindowListActivity
ComponentName comp = new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.sysfloatwindow.FloatWindowListActivity");//悬浮窗管理页面
intent.setComponent(comp);
context.startActivity(intent);
}
catch(Exception e){
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2016 Facishare Technology Co., Ltd. All Rights Reserved.
*/
package com.alivc.live.baselive_recording.floatwindowpermission.rom;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Method;
public class QikuUtils {
private static final String TAG = "QikuUtils";
/**
* 检测 360 悬浮窗权限
*/
public static boolean checkFloatWindowPermission(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, 24); //OP_SYSTEM_ALERT_WINDOW = 24;
}
return true;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Class clazz = AppOpsManager.class;
Method method = clazz.getDeclaredMethod("checkOp", int.class, int.class, String.class);
return AppOpsManager.MODE_ALLOWED == (int)method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
}
} else {
Log.e("", "Below API 19 cannot invoke!");
}
return false;
}
/**
* 去360权限申请页面
*/
public static void applyPermission(Context context) {
Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.Settings$OverlaySettingsActivity");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
intent.setClassName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity");
if (isIntentAvailable(intent, context)) {
context.startActivity(intent);
} else {
Log.e(TAG, "can't open permission page with particular name, please use " +
"\"adb shell dumpsys activity\" command and tell me the name of the float window permission page");
}
}
}
private static boolean isIntentAvailable(Intent intent, Context context) {
if (intent == null) {
return false;
}
return context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2016 Facishare Technology Co., Ltd. All Rights Reserved.
*/
package com.alivc.live.baselive_recording.floatwindowpermission.rom;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Description:
*
* @author zhaozp
* @since 2016-05-23
*/
public class RomUtils {
private static final String TAG = "RomUtils";
/**
* 获取 emui 版本号
* @return
*/
public static double getEmuiVersion() {
try {
String emuiVersion = getSystemProperty("ro.build.version.emui");
String version = emuiVersion.substring(emuiVersion.indexOf("_") + 1);
return Double.parseDouble(version);
} catch (Exception e) {
e.printStackTrace();
}
return 4.0;
}
/**
* 获取小米 rom 版本号,获取失败返回 -1
*
* @return miui rom version code, if fail , return -1
*/
public static int getMiuiVersion() {
String version = getSystemProperty("ro.miui.ui.version.name");
if (version != null) {
try {
return Integer.parseInt(version.substring(1));
} catch (Exception e) {
Log.e(TAG, "get miui version code error, version : " + version);
}
}
return -1;
}
public static String getSystemProperty(String propName) {
String line;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + propName);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
Log.e(TAG, "Unable to read sysprop " + propName, ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
Log.e(TAG, "Exception while closing InputStream", e);
}
}
}
return line;
}
public static boolean checkIsHuaweiRom() {
return Build.MANUFACTURER.contains("HUAWEI");
}
/**
* check if is miui ROM
*/
public static boolean checkIsMiuiRom() {
return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name"));
}
public static boolean checkIsMeizuRom() {
//return Build.MANUFACTURER.contains("Meizu");
String meizuFlymeOSFlag = getSystemProperty("ro.build.display.id");
if (TextUtils.isEmpty(meizuFlymeOSFlag)){
return false;
}else if (meizuFlymeOSFlag.contains("flyme") || meizuFlymeOSFlag.toLowerCase().contains("flyme")){
return true;
}else {
return false;
}
}
public static boolean checkIs360Rom() {
//fix issue https://github.com/zhaozepeng/FloatWindowPermission/issues/9
return Build.MANUFACTURER.contains("QiKU")
|| Build.MANUFACTURER.contains("360");
}
public static boolean checkIsOppoRom() {
//https://github.com/zhaozepeng/FloatWindowPermission/pull/26
return Build.MANUFACTURER.contains("OPPO") || Build.MANUFACTURER.contains("oppo");
}
}

View File

@@ -0,0 +1,90 @@
package com.alivc.live.baselive_recording.service;
import static android.app.Notification.FLAG_NO_CLEAR;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.Nullable;
import com.alivc.live.baselive_recording.R;
import com.alivc.live.baselive_recording.ui.VideoRecordConfigActivity;
/**
* 录屏后台service
* 请务必在AndroidManifest.xml里面进行注册否则会因系统权限不足导致推流黑屏
*
* @author aliyun
*/
public class ForegroundService extends Service {
private static final int NOTIFICATION_FLAG = 0X11;
private static final String NOTIFICATION_ID = "alivc_live_push";
private static final String NOTIFICATION_NAME = "alivc_live_push";
@Nullable
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_ID, NOTIFICATION_NAME, NotificationManager.IMPORTANCE_HIGH);
manager.createNotificationChannel(channel);
}
Intent nfIntent = new Intent(this, VideoRecordConfigActivity.class);
PendingIntent pendingIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
pendingIntent = PendingIntent.getActivity(this, 0, nfIntent, PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getActivity(this, 0, nfIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
Notification.Builder builder = new Notification.Builder(this.getApplicationContext());
builder.setContentIntent(pendingIntent)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher))
.setTicker("正在推流中...")
.setContentTitle("推流SDK")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("正在推流中...")
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis())
.setDefaults(Notification.DEFAULT_VIBRATE)
.setPriority(Notification.PRIORITY_HIGH);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(NOTIFICATION_ID);
}
Notification notification = builder.build();
notification.defaults = Notification.DEFAULT_SOUND;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.flags |= FLAG_ONGOING_EVENT;
notification.flags |= FLAG_NO_CLEAR;
manager.notify(NOTIFICATION_FLAG, notification);
// 启动前台服务
startForeground(NOTIFICATION_FLAG, notification);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
// 停止前台服务
stopForeground(true);
}
}

View File

@@ -0,0 +1,761 @@
package com.alivc.live.baselive_recording.ui;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.hardware.SensorManager;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.acker.simplezxing.activity.CaptureActivity;
import com.alivc.live.annotations.AlivcLiveNetworkQuality;
import com.alivc.live.commonui.configview.PushConfigBottomSheetLive;
import com.alivc.live.commonui.configview.PushConfigDialogImpl;
import com.alivc.live.baselive_recording.R;
import com.alivc.live.baselive_recording.VideoRecordViewManager;
import com.alivc.live.baselive_recording.floatwindowpermission.FloatWindowManager;
import com.alivc.live.baselive_recording.service.ForegroundService;
import com.alivc.live.commonbiz.test.PushDemoTestConstants;
import com.alivc.live.commonui.utils.StatusBarUtil;
import com.alivc.live.commonutils.ToastUtils;
import com.alivc.live.pusher.AlivcLiveBase;
import com.alivc.live.pusher.AlivcLivePushConfig;
import com.alivc.live.pusher.AlivcLivePushError;
import com.alivc.live.pusher.AlivcLivePushErrorListener;
import com.alivc.live.pusher.AlivcLivePushInfoListener;
import com.alivc.live.pusher.AlivcLivePushNetworkListener;
import com.alivc.live.pusher.AlivcLivePushStatsInfo;
import com.alivc.live.pusher.AlivcLivePusher;
import com.alivc.live.pusher.AlivcPreviewOrientationEnum;
import com.alivc.live.pusher.AlivcResolutionEnum;
import java.io.File;
public class VideoRecordConfigActivity extends AppCompatActivity {
private static final String TAG = "VideoRecordConfig";
private AlivcResolutionEnum mDefinition = AlivcResolutionEnum.RESOLUTION_540P;
private static final int REQ_CODE_PERMISSION = 0x1111;
private static final int CAPTURE_PERMISSION_REQUEST_CODE = 0x1123;
private static final int OVERLAY_PERMISSION_REQUEST_CODE = 0x1124;
private static final int PROGRESS_0 = 0;
private static final int PROGRESS_20 = 20;
private static final int PROGRESS_40 = 40;
private static final int PROGRESS_60 = 60;
private static final int PROGRESS_80 = 80;
private static final int PROGRESS_90 = 90;
private static final int PROGRESS_100 = 100;
private InputMethodManager manager;
private SeekBar mResolution;
private TextView mResolutionText;
private EditText mUrl;
private ImageView mQr;
private ImageView mBack;
private TextView mPushTex;
private TextView mOrientation;
private TextView mNoteText;
private AlivcLivePushConfig mAlivcLivePushConfig;
private AlivcLivePusher mAlivcLivePusher = null;
private OrientationEventListener mOrientationEventListener;
private Switch mNarrowBandHDConfig;
private int mLastRotation;
private boolean mIsStartPushing = false;
private PushConfigDialogImpl mPushConfigDialog = new PushConfigDialogImpl();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StatusBarUtil.translucent(this, Color.TRANSPARENT);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.video_recording_setting);
initViews();
// 注册推流SDK
AlivcLiveBase.registerSDK();
mAlivcLivePushConfig = new AlivcLivePushConfig();
configurePushImages(AlivcPreviewOrientationEnum.ORIENTATION_PORTRAIT);
mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
@Override
public void onOrientationChanged(int orientation) {
int rotation = getDisplayRotation();
if (rotation != mLastRotation) {
if (mAlivcLivePusher != null) {
mAlivcLivePusher.setScreenOrientation(rotation);
}
mLastRotation = rotation;
}
}
};
// 获取默认推流地址
Intent intent = getIntent();
String url = intent.getStringExtra("pushUrl");
if (!TextUtils.isEmpty(url)) {
mUrl.setText(url);
}
}
private int getDisplayRotation() {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
default:
break;
}
return 0;
}
@Override
protected void onStart() {
super.onStart();
VideoRecordViewManager.hideViewRecordWindow();
}
@Override
protected void onStop() {
super.onStop();
if (mAlivcLivePusher != null && mAlivcLivePusher.isPushing()) {
VideoRecordViewManager.createViewoRecordWindow(VideoRecordConfigActivity.this, getApplicationContext(), mAlivcLivePusher, cameraOnListener);
VideoRecordViewManager.showViewRecordWindow();
}
}
private VideoRecordViewManager.CameraOn cameraOnListener = new VideoRecordViewManager.CameraOn() {
@Override
public void onCameraOn(boolean on) {
if (on) {
VideoRecordViewManager.createViewoRecordCameraWindow(VideoRecordConfigActivity.this, getApplicationContext(), mAlivcLivePusher);
} else {
VideoRecordViewManager.removeVideoRecordCameraWindow(getApplicationContext());
}
}
};
private void initViews() {
mUrl = (EditText) findViewById(R.id.url_editor);
mPushTex = (TextView) findViewById(R.id.pushStatusTex);
mPushTex.setOnClickListener(onClickListener);
mResolution = (SeekBar) findViewById(R.id.resolution_seekbar);
mResolution.setOnSeekBarChangeListener(onSeekBarChangeListener);
mResolutionText = (TextView) findViewById(R.id.resolution_text);
mOrientation = findViewById(R.id.main_orientation);
mOrientation.setOnClickListener(onClickListener);
mQr = (ImageView) findViewById(R.id.qr_code);
mQr.setOnClickListener(onClickListener);
mBack = (ImageView) findViewById(R.id.iv_back);
mBack.setOnClickListener(onClickListener);
mNoteText = (TextView) findViewById(R.id.note_text);
mNarrowBandHDConfig = (Switch) findViewById(R.id.narrowband_hd);
mNarrowBandHDConfig.setOnCheckedChangeListener(onCheckedChangeListener);
// 初始化调试推流地址
String initUrl = PushDemoTestConstants.getTestPushUrl();
if (!initUrl.isEmpty()) {
mUrl.setText(initUrl);
}
}
private View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.pushStatusTex) {
if (mIsStartPushing) {
return;
}
if (!(mUrl.getText().toString().contains("rtmp://") || mUrl.getText().toString().contains("artc://"))) {
ToastUtils.show("url format unsupported");
return;
}
mIsStartPushing = true;
if (getPushConfig() != null) {
if (mAlivcLivePusher == null) {
//if(VideoRecordViewManager.permission(getApplicationContext()))
if (FloatWindowManager.getInstance().applyFloatWindow(VideoRecordConfigActivity.this)) {
Intent intent = new Intent(VideoRecordConfigActivity.this, ForegroundService.class);
startService(intent);
startScreenCapture();
} else {
mIsStartPushing = false;
}
} else {
view.postDelayed(new Runnable() {
@Override
public void run() {
mIsStartPushing = false;
}
}, 1000);
Intent intent = new Intent(VideoRecordConfigActivity.this, ForegroundService.class);
stopService(intent);
stopPushWithoutSurface();
}
}
} else if (id == R.id.qr_code) {
if (ContextCompat.checkSelfPermission(VideoRecordConfigActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// Do not have the permission of camera, request it.
ActivityCompat.requestPermissions(VideoRecordConfigActivity.this, new String[]{Manifest.permission.CAMERA}, REQ_CODE_PERMISSION);
} else {
// Have gotten the permission
startCaptureActivityForResult();
}
} else if (id == R.id.iv_back) {
finish();
} else if (id == R.id.main_orientation) {
mPushConfigDialog.showConfigDialog(mOrientation, mOrientationListener, 0);
}
}
};
private SeekBar.OnSeekBarChangeListener onSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int seekBarId = seekBar.getId();
if (mResolution.getId() == seekBarId) {
if (progress <= PROGRESS_0) {
mDefinition = AlivcResolutionEnum.RESOLUTION_180P;
mResolutionText.setText(R.string.setting_resolution_180P);
} else if (progress > PROGRESS_0 && progress <= PROGRESS_20) {
mDefinition = AlivcResolutionEnum.RESOLUTION_240P;
mResolutionText.setText(R.string.setting_resolution_240P);
} else if (progress > PROGRESS_20 && progress <= PROGRESS_40) {
mDefinition = AlivcResolutionEnum.RESOLUTION_360P;
mResolutionText.setText(R.string.setting_resolution_360P);
} else if (progress > PROGRESS_40 && progress <= PROGRESS_60) {
mDefinition = AlivcResolutionEnum.RESOLUTION_480P;
mResolutionText.setText(R.string.setting_resolution_480P);
} else if (progress > PROGRESS_60 && progress <= PROGRESS_80) {
mDefinition = AlivcResolutionEnum.RESOLUTION_540P;
mResolutionText.setText(R.string.setting_resolution_540P);
} else if (progress > PROGRESS_80 && progress <= PROGRESS_90) {
mDefinition = AlivcResolutionEnum.RESOLUTION_720P;
mResolutionText.setText(R.string.setting_resolution_720P);
} else if (progress > PROGRESS_90) {
mDefinition = AlivcResolutionEnum.RESOLUTION_1080P;
mResolutionText.setText(R.string.setting_resolution_1080P);
}
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
if (mResolution.getId() == seekBar.getId()) {
if (progress < PROGRESS_0) {
seekBar.setProgress(0);
} else if (progress > PROGRESS_0 && progress <= PROGRESS_20) {
seekBar.setProgress(PROGRESS_20);
} else if (progress > PROGRESS_20 && progress <= PROGRESS_40) {
seekBar.setProgress(PROGRESS_40);
} else if (progress > PROGRESS_40 && progress <= PROGRESS_60) {
seekBar.setProgress(PROGRESS_60);
} else if (progress > PROGRESS_60 && progress <= PROGRESS_80) {
seekBar.setProgress(PROGRESS_80);
} else if (progress > PROGRESS_80 && progress <= PROGRESS_90) {
seekBar.setProgress(PROGRESS_90);
} else if (progress > PROGRESS_90) {
seekBar.setProgress(PROGRESS_100);
}
}
}
};
private PushConfigBottomSheetLive.OnPushConfigSelectorListener mOrientationListener = new PushConfigBottomSheetLive.OnPushConfigSelectorListener() {
@Override
public void confirm(String data, int index) {
AlivcPreviewOrientationEnum currentOrientation = AlivcPreviewOrientationEnum.ORIENTATION_PORTRAIT;
if (index == 1) {
currentOrientation = AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_LEFT;
} else if (index == 2) {
currentOrientation = AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT;
}
if (mAlivcLivePushConfig != null) {
mAlivcLivePushConfig.setPreviewOrientation(currentOrientation);
configurePushImages(currentOrientation);
}
}
};
private OnCheckedChangeListener onCheckedChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int id = buttonView.getId();
if (id == R.id.narrowband_hd) {
mAlivcLivePushConfig.setEnableNarrowbandHDForScreenPusher(isChecked);
}
}
};
/**
* 根据预览方向设置暂停推流和网络不佳时的图片
*
* @param orientation 预览方向
*/
private void configurePushImages(AlivcPreviewOrientationEnum orientation) {
if (mAlivcLivePushConfig == null) {
return;
}
if (orientation == AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_RIGHT || orientation == AlivcPreviewOrientationEnum.ORIENTATION_LANDSCAPE_HOME_LEFT) {
// 横屏模式
mAlivcLivePushConfig.setNetworkPoorPushImage(getFilesDir().getPath() + File.separator + "alivc_resource/poor_network_land.png");
mAlivcLivePushConfig.setPausePushImage(getFilesDir().getPath() + File.separator + "alivc_resource/background_push_land.png");
} else {
// 竖屏模式
mAlivcLivePushConfig.setNetworkPoorPushImage(getFilesDir().getPath() + File.separator + "alivc_resource/poor_network.png");
mAlivcLivePushConfig.setPausePushImage(getFilesDir().getPath() + File.separator + "alivc_resource/background_push.png");
}
}
@Override
protected void onPause() {
super.onPause();
VideoRecordViewManager.refreshFloatWindowPosition();
}
@Override
protected void onResume() {
super.onResume();
if (mOrientationEventListener != null && mOrientationEventListener.canDetectOrientation()) {
mOrientationEventListener.enable();
}
}
private void startCaptureActivityForResult() {
Intent intent = new Intent(VideoRecordConfigActivity.this, CaptureActivity.class);
Bundle bundle = new Bundle();
bundle.putBoolean(CaptureActivity.KEY_NEED_BEEP, CaptureActivity.VALUE_BEEP);
bundle.putBoolean(CaptureActivity.KEY_NEED_VIBRATION, CaptureActivity.VALUE_VIBRATION);
bundle.putBoolean(CaptureActivity.KEY_NEED_EXPOSURE, CaptureActivity.VALUE_NO_EXPOSURE);
bundle.putByte(CaptureActivity.KEY_FLASHLIGHT_MODE, CaptureActivity.VALUE_FLASHLIGHT_OFF);
bundle.putByte(CaptureActivity.KEY_ORIENTATION_MODE, CaptureActivity.VALUE_ORIENTATION_AUTO);
bundle.putBoolean(CaptureActivity.KEY_SCAN_AREA_FULL_SCREEN, CaptureActivity.VALUE_SCAN_AREA_FULL_SCREEN);
bundle.putBoolean(CaptureActivity.KEY_NEED_SCAN_HINT_TEXT, CaptureActivity.VALUE_SCAN_HINT_TEXT);
intent.putExtra(CaptureActivity.EXTRA_SETTING_BUNDLE, bundle);
startActivityForResult(intent, CaptureActivity.REQ_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQ_CODE_PERMISSION: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// User agree the permission
startCaptureActivityForResult();
} else {
// User disagree the permission
ToastUtils.show("You must agree the camera permission request before you use the code scan function");
}
}
break;
default:
break;
}
}
private AlivcLivePushConfig getPushConfig() {
if (mUrl.getText().toString().isEmpty()) {
ToastUtils.show(getString(R.string.url_empty));
return null;
}
mAlivcLivePushConfig.setResolution(mDefinition);
return mAlivcLivePushConfig;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CaptureActivity.REQ_CODE:
switch (resultCode) {
case RESULT_OK:
mUrl.setText(data.getStringExtra(CaptureActivity.EXTRA_SCAN_RESULT)); //or do sth
break;
case RESULT_CANCELED:
if (data != null) {
// for some reason camera is not working correctly
mUrl.setText(data.getStringExtra(CaptureActivity.EXTRA_SCAN_RESULT));
}
break;
default:
break;
}
break;
case CAPTURE_PERMISSION_REQUEST_CODE: {
if (resultCode == Activity.RESULT_CANCELED) {
ToastUtils.show("Start screen recording failed, cancelled by the user");
mIsStartPushing = false;
return;
}
if (resultCode == Activity.RESULT_OK) {
mAlivcLivePushConfig.setMediaProjectionPermissionResultData(data);
if (mAlivcLivePushConfig.getMediaProjectionPermissionResultData() != null) {
if (mAlivcLivePusher == null) {
startPushWithoutSurface(mUrl.getText().toString());
} else {
stopPushWithoutSurface();
}
}
}
}
break;
case OVERLAY_PERMISSION_REQUEST_CODE:
break;
default:
break;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (getCurrentFocus() != null && getCurrentFocus().getWindowToken() != null) {
if (manager == null) {
manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
}
manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
return super.onTouchEvent(event);
}
@Override
protected void onDestroy() {
Intent intent = new Intent(VideoRecordConfigActivity.this, ForegroundService.class);
stopService(intent);
VideoRecordViewManager.removeVideoRecordCameraWindow(getApplicationContext());
VideoRecordViewManager.removeVideoRecordWindow(getApplicationContext());
if (mAlivcLivePusher != null) {
try {
mAlivcLivePusher.stopCamera();
} catch (Exception e) {
}
try {
mAlivcLivePusher.stopCameraMix();
} catch (Exception e) {
}
try {
mAlivcLivePusher.stopPush();
} catch (Exception e) {
}
try {
mAlivcLivePusher.stopPreview();
} catch (Exception e) {
}
mAlivcLivePusher.destroy();
mAlivcLivePusher.setLivePushInfoListener(null);
mAlivcLivePusher = null;
}
if (mOrientationEventListener != null) {
mOrientationEventListener.disable();
}
super.onDestroy();
}
private void startScreenCapture() {
if (Build.VERSION.SDK_INT >= 21) {
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
try {
this.startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), CAPTURE_PERMISSION_REQUEST_CODE);
} catch (ActivityNotFoundException ex) {
ex.printStackTrace();
ToastUtils.show("Start ScreenRecording failed, current device is NOT supported!");
}
} else {
ToastUtils.show("录屏需要5.0版本以上");
}
}
private void stopPushWithoutSurface() {
VideoRecordViewManager.removeVideoRecordCameraWindow(getApplicationContext());
VideoRecordViewManager.removeVideoRecordWindow(getApplicationContext());
if (mAlivcLivePusher != null) {
try {
mAlivcLivePusher.stopCamera();
} catch (Exception e) {
}
try {
mAlivcLivePusher.stopCameraMix();
} catch (Exception e) {
}
try {
mAlivcLivePusher.stopPush();
} catch (Exception e) {
}
try {
mAlivcLivePusher.stopPreview();
} catch (Exception e) {
}
try {
mAlivcLivePusher.destroy();
} catch (Exception e) {
}
mAlivcLivePusher.setLivePushInfoListener(null);
mAlivcLivePusher = null;
}
mPushTex.setText(R.string.start_push);
mNoteText.setText(getString(R.string.screen_note1));
mNoteText.setVisibility(View.VISIBLE);
mResolution.setEnabled(true);
mNarrowBandHDConfig.setEnabled(true);
}
private void startPushWithoutSurface(String url) {
mAlivcLivePusher = new AlivcLivePusher();
try {
mAlivcLivePusher.init(getApplicationContext(), mAlivcLivePushConfig);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
mAlivcLivePusher.setLivePushInfoListener(new AlivcLivePushInfoListener() {
@Override
public void onPreviewStarted(AlivcLivePusher pusher) {
Log.d(TAG, "onPreviewStarted: ");
}
@Override
public void onPreviewStopped(AlivcLivePusher pusher) {
Log.d(TAG, "onPreviewStopped: ");
}
@Override
public void onPushStarted(AlivcLivePusher pusher) {
Log.d(TAG, "onPushStarted: ");
}
@Override
public void onPushPaused(AlivcLivePusher pusher) {
Log.d(TAG, "onPushPaused: ");
}
@Override
public void onPushResumed(AlivcLivePusher pusher) {
Log.d(TAG, "onPushResumed: ");
}
@Override
public void onPushStopped(AlivcLivePusher pusher) {
Log.d(TAG, "onPushStopped: ");
}
@Override
public void onPushRestarted(AlivcLivePusher pusher) {
Log.d(TAG, "onPushRestarted: ");
}
@Override
public void onFirstFramePushed(AlivcLivePusher pusher) {
Log.d(TAG, "onFirstFramePushed: ");
}
@Override
public void onFirstFramePreviewed(AlivcLivePusher pusher) {
Log.d(TAG, "onFirstFramePreviewed: ");
mIsStartPushing = false;
}
@Override
public void onDropFrame(AlivcLivePusher pusher, int countBef, int countAft) {
Log.d(TAG, "onDropFrame: ");
}
@Override
public void onAdjustBitrate(AlivcLivePusher pusher, int currentBitrate, int targetBitrate) {
Log.i(TAG, "onAdjustBitrate: " + currentBitrate + "->" + targetBitrate);
}
@Override
public void onAdjustFps(AlivcLivePusher pusher, int curFps, int targetFps) {
Log.d(TAG, "onAdjustFps: ");
}
@Override
public void onPushStatistics(AlivcLivePusher pusher, AlivcLivePushStatsInfo statistics) {
// Log.i(TAG, "onPushStatistics: ");
}
});
mAlivcLivePusher.setLivePushErrorListener(new AlivcLivePushErrorListener() {
@Override
public void onSystemError(AlivcLivePusher livePusher, AlivcLivePushError error) {
showDialog(getString(R.string.system_error) + error.toString());
}
@Override
public void onSDKError(AlivcLivePusher livePusher, AlivcLivePushError error) {
showDialog(getString(R.string.sdk_error) + error.toString());
}
});
mAlivcLivePusher.setLivePushNetworkListener(new AlivcLivePushNetworkListener() {
@Override
public void onNetworkPoor(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onNetworkPoor: ");
}
@Override
public void onNetworkRecovery(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onNetworkRecovery: ");
}
@Override
public void onReconnectStart(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onReconnectStart: ");
}
@Override
public void onConnectionLost(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onConnectionLost: ");
}
@Override
public void onReconnectFail(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onReconnectFail: ");
}
@Override
public void onReconnectSucceed(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onReconnectSucceed: ");
}
@Override
public void onSendDataTimeout(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onSendDataTimeout: ");
}
@Override
public void onConnectFail(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onConnectFail: ");
showDialog(getResources().getString(R.string.connect_fail));
}
@Override
public void onNetworkQualityChanged(AlivcLiveNetworkQuality upQuality, AlivcLiveNetworkQuality downQuality) {
}
@Override
public String onPushURLAuthenticationOverdue(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onPushURLAuthenticationOverdue: ");
return null;
}
@Override
public void onPushURLTokenWillExpire(AlivcLivePusher pusher) {
Log.d(TAG, "onPushURLTokenWillExpire: ");
}
@Override
public void onPushURLTokenExpired(AlivcLivePusher pusher) {
Log.d(TAG, "onPushURLTokenExpired: ");
}
@Override
public void onSendMessage(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onSendMessage: ");
}
@Override
public void onPacketsLost(AlivcLivePusher alivcLivePusher) {
Log.d(TAG, "onPacketsLost: ");
}
});
try {
mAlivcLivePusher.startPreview(null);
} catch (Exception e) {
showDialog("StartPreview failed");
return;
}
try {
mAlivcLivePusher.startPush(url);
} catch (Exception e) {
showDialog("startPush failed");
return;
}
mPushTex.setText(R.string.stop_button);
mNoteText.setText(getString(R.string.screen_note));
mNoteText.setVisibility(View.VISIBLE);
mResolution.setEnabled(false);
mNarrowBandHDConfig.setEnabled(false);
}
private void showDialog(final String message) {
if (getApplicationContext() == null || message == null) {
return;
}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
mNoteText.setText(message);
}
});
}
}

View File

@@ -0,0 +1,195 @@
package com.alivc.live.baselive_recording.ui.widget;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import com.alivc.live.baselive_recording.R;
import com.alivc.live.pusher.AlivcLivePushStats;
import com.alivc.live.pusher.AlivcLivePusher;
import java.lang.reflect.Field;
public class VideoRecordCameraPreviewView extends LinearLayout {
public static int viewWidth;
public static int viewHeight;
private static int statusBarHeight;
private WindowManager windowManager;
private WindowManager.LayoutParams mParams;
private AlivcLivePusher mLivePusher = null;
private float xInScreen;
private float yInScreen;
private float xDownInScreen;
private float yDownInScreen;
private float xInView;
private float yInView;
private Activity mActivity;
private SurfaceView cameraPreview = null;
public VideoRecordCameraPreviewView(Activity activity, Context context) {
super(context);
this.mActivity = activity;
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(R.layout.record_camera_preview, this);
View view = findViewById(R.id.record_camera_layout);
viewWidth = dip2px(activity, 90);
viewHeight = dip2px(activity, 160);
cameraPreview = (SurfaceView) findViewById(R.id.camera_preview);
cameraPreview.getHolder().addCallback(mCallback);
}
public void setVisible(boolean visible) {
if (visible) {
cameraPreview.setVisibility(VISIBLE);
} else {
cameraPreview.setVisibility(INVISIBLE);
}
}
SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (mLivePusher != null) {
AlivcLivePushStats currentStatus = mLivePusher.getCurrentStatus();
mLivePusher.startCamera(cameraPreview);
int rotation = getDisplayRotation();
mLivePusher.setScreenOrientation(rotation);
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (mLivePusher != null) {
try {
mLivePusher.stopCamera();
} catch (Exception e) {
}
}
}
};
public void refreshPosition() {
updateViewPosition();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
xInView = event.getX();
yInView = event.getY();
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY() - getStatusBarHeight();
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
break;
case MotionEvent.ACTION_MOVE:
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {
}
break;
default:
break;
}
return true;
}
public void setParams(AlivcLivePusher pusher, WindowManager.LayoutParams params) {
mParams = params;
mLivePusher = pusher;
}
/**
* 更新小悬浮窗在屏幕中的位置。
*/
private void updateViewPosition() {
mParams.x = (int) (xInScreen - xInView);
mParams.y = (int) (yInScreen - yInView);
windowManager.updateViewLayout(this, mParams);
}
/**
* 用于获取状态栏的高度。
*
* @return 返回状态栏高度的像素值。
*/
private int getStatusBarHeight() {
if (statusBarHeight == 0) {
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);
statusBarHeight = getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusBarHeight;
}
public SurfaceView getSurfaceView() {
return cameraPreview;
}
private int getDisplayRotation() {
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
default:
break;
}
return 0;
}
/**
* 将dip或dp值转换为px值保证尺寸大小不变
*
* @param dipValue
* @param dipValue DisplayMetrics类中属性density
* @return
*/
private 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);
}
}

View File

@@ -0,0 +1,299 @@
package com.alivc.live.baselive_recording.ui.widget;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.alivc.live.baselive_recording.R;
import com.alivc.live.baselive_recording.ui.VideoRecordConfigActivity;
import com.alivc.live.pusher.AlivcLivePusher;
import com.alivc.live.baselive_recording.VideoRecordViewManager;
import java.lang.reflect.Field;
import java.util.List;
public class VideoRecordSmallView extends LinearLayout {
public static int viewHeight;
private static int statusBarHeight;
private WindowManager windowManager;
private WindowManager.LayoutParams mParams;
private AlivcLivePusher mAlivcLivePusher = null;
private float xInScreen;
private float yInScreen;
private float xDownInScreen;
private float yDownInScreen;
private float xInView;
private float yInView;
private LinearLayout mRecording;
private LinearLayout mOpera;
private TextView mPrivacy;
private TextView mCamera;
private TextView mMic;
private TextView mMix;
private boolean mPrivacyOn = false;
private boolean mCameraOn = false;
private boolean mMicOn = true;
private boolean mMixOn = false;
private Context mContext;
private int mCurrentTaskId;
private View mRootView = null;
private VideoRecordViewManager.CameraOn mCameraOnListener = null;
private final View mContentView;
private Runnable mCloseRunnable = new Runnable() {
@Override
public void run() {
mContentView.setAlpha(0.5f);
mOpera.setVisibility(GONE);
}
};
public VideoRecordSmallView(Context context, int currentTaskId) {
super(context);
this.mContext = context;
this.mCurrentTaskId = currentTaskId;
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mRootView = LayoutInflater.from(context).inflate(R.layout.record_view_small, this);
mContentView = findViewById(R.id.record_window_layout);
mRecording = (LinearLayout) mContentView.findViewById(R.id.recording_linear);
mOpera = (LinearLayout) mContentView.findViewById(R.id.opera_linear);
mPrivacy = (TextView) mContentView.findViewById(R.id.privacy);
mPrivacy.setSelected(mPrivacyOn);
mCamera = (TextView) mContentView.findViewById(R.id.camera);
mCamera.setSelected(mCameraOn);
mMic = (TextView) mContentView.findViewById(R.id.mic);
mMic.setSelected(mMicOn);
mMix = (TextView) mContentView.findViewById(R.id.mix);
mMix.setSelected(mMixOn);
mRecording.setOnClickListener(mOnClickListener);
mOpera.setOnClickListener(mOnClickListener);
mPrivacy.setOnClickListener(mOnClickListener);
mCamera.setOnClickListener(mOnClickListener);
mMic.setOnClickListener(mOnClickListener);
mMix.setOnClickListener(mOnClickListener);
viewHeight = mContentView.getLayoutParams().height;
}
public void setVisible(boolean visible) {
if (visible) {
mRootView.setVisibility(VISIBLE);
} else {
mRootView.setVisibility(INVISIBLE);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("fclaa", "onTouchEvent: "+event.getActionMasked() );
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
xInView = event.getX();
yInView = event.getY();
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY() - getStatusBarHeight();
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
break;
case MotionEvent.ACTION_MOVE:
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {
}
break;
default:
break;
}
return true;
}
public void setParams(AlivcLivePusher pusher, WindowManager.LayoutParams params) {
mAlivcLivePusher = pusher;
mParams = params;
}
public void setCameraOnListern(VideoRecordViewManager.CameraOn listern) {
mCameraOnListener = listern;
}
/**
* 更新小悬浮窗在屏幕中的位置。
*/
private void updateViewPosition() {
mParams.x = (int) (xInScreen - xInView);
mParams.y = (int) (yInScreen - yInView);
windowManager.updateViewLayout(this, mParams);
}
/**
* 用于获取状态栏的高度。
*
* @return 返回状态栏高度的像素值。
*/
private int getStatusBarHeight() {
if (statusBarHeight == 0) {
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);
statusBarHeight = getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusBarHeight;
}
private boolean IsForeground(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (tasks != null && !tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
private OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.recording_linear) {
if (mOpera.getVisibility() == VISIBLE){
mContentView.removeCallbacks(mCloseRunnable);
mOpera.setVisibility(GONE);
mContentView.setAlpha(0.5f);
if (mContext != null) {
if (!IsForeground(mContext) && mCurrentTaskId != 0) {
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
if (am != null) {
am.moveTaskToFront(mCurrentTaskId, ActivityManager.MOVE_TASK_WITH_HOME);
}
} else {
Intent intent = new Intent(mContext, VideoRecordConfigActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
}else {
mContentView.setAlpha(1.0f);
mOpera.setVisibility(VISIBLE);
mContentView.removeCallbacks(mCloseRunnable);
mContentView.postDelayed(mCloseRunnable,5000);
}
} else if (id == R.id.privacy) {
if (mAlivcLivePusher != null && mPrivacyOn) {
try {
mAlivcLivePusher.resumeScreenCapture();
} catch (Exception e) {
}
mPrivacyOn = false;
} else if (mAlivcLivePusher != null && !mPrivacyOn) {
try {
mAlivcLivePusher.pauseScreenCapture();
} catch (Exception e) {
}
mPrivacyOn = true;
}
mPrivacy.setSelected(mPrivacyOn);
} else if (id == R.id.camera) {
if (mAlivcLivePusher != null && !mCameraOn && mCameraOnListener != null) {
mMix.setSelected(false);
mMix.setClickable(false);
mCameraOnListener.onCameraOn(true);
mCameraOn = true;
} else if (mAlivcLivePusher != null && mCameraOn && mCameraOnListener != null) {
try {
mAlivcLivePusher.stopCamera();
} catch (Exception e) {
}
mCameraOnListener.onCameraOn(false);
mCameraOn = false;
mMix.setClickable(true);
}
mCamera.setSelected(mCameraOn);
} else if (id == R.id.mix) {
if (mAlivcLivePusher != null && !mMixOn) {
mCamera.setSelected(false);
mCamera.setClickable(false);
try {
mAlivcLivePusher.startCamera(null);
} catch (Exception e) {
e.printStackTrace();
}
//set orientation
/*int orientation = getContext().getResources().getConfiguration().orientation;
if(orientation == 0) {
mAlivcLivePusher.setScreenOrientation(0);
} else if(orientation == 2) {
mAlivcLivePusher.setScreenOrientation(90);
} else if(orientation == 1) {
mAlivcLivePusher.setScreenOrientation(270);
}*/
mAlivcLivePusher.startCameraMix(0.6f, 0.08f, 0.3f, 0.3f);
mMixOn = true;
} else if (mAlivcLivePusher != null && mMixOn) {
mAlivcLivePusher.stopCameraMix();
// if (mCameraOpenByMix) {
// mAlivcLivePusher.stopCamera();
// }
mMixOn = false;
mCamera.setClickable(true);
}
mMix.setSelected(mMixOn);
} else if (id == R.id.mic) {
if (mAlivcLivePusher != null) {
try {
mAlivcLivePusher.setMute(mMicOn);
} catch (Exception e) {
e.printStackTrace();
}
mMicOn = !mMicOn;
mMic.setSelected(mMicOn);
}
}
}
};
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mContentView != null){
mContentView.removeCallbacks(mCloseRunnable);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View 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_selected="true" android:drawable="@drawable/ic_camera_on"/>
<item android:state_selected="false" android:drawable="@drawable/ic_camera_off"/>
</selector>

View 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_selected="true" android:drawable="@drawable/ic_mic_on"/>
<item android:state_selected="false" android:drawable="@drawable/ic_mic_off"/>
</selector>

View 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_selected="true" android:drawable="@drawable/ic_mix_on"/>
<item android:state_selected="false" android:drawable="@drawable/ic_mix_off"/>
</selector>

View 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_selected="true" android:drawable="@drawable/ic_privacy_on"/>
<item android:state_selected="false" android:drawable="@drawable/ic_privacy_off"/>
</selector>

View 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_selected="true" android:color="#4DCFE1"/>
<item android:state_selected="false" android:color="#FCFCFD"/>
</selector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#1C1D22" />
<corners android:topLeftRadius="32dp" android:bottomLeftRadius="32dp" />
</shape>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#4D4DCFE1"/>
<stroke android:color="#4DCFE1" android:width="1px"/>
<corners android:radius="24dp" />
</shape>

View File

@@ -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>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/record_camera_layout"
android:layout_width="90dp"
android:layout_height="160dp">
<SurfaceView
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/record_window_layout"
android:layout_width="wrap_content"
android:layout_height="64dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:alpha="0.5"
android:background="@drawable/shap_oval_gray">
<LinearLayout
android:id="@+id/recording_linear"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_blue_back"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="19dp"
android:gravity="center"
android:text="@string/back"
android:textSize="15sp"
android:textColor="#4DCFE1"/>
</LinearLayout>
<LinearLayout
android:id="@+id/opera_linear"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/privacy"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center"
android:text="@string/privacy_on"
android:textSize="10sp"
android:drawablePadding="5dp"
android:layout_marginEnd="20dp"
android:drawableTop="@drawable/selector_push_drawable_privacy"
android:textColor="@drawable/selector_push_text_color"/>
<TextView
android:id="@+id/camera"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="center"
android:text="@string/camera_on"
android:textSize="10sp"
android:drawablePadding="8dp"
android:layout_marginEnd="20dp"
android:drawableTop="@drawable/selector_push_drawable_camera"
android:textColor="@drawable/selector_push_text_color"/>
<TextView
android:id="@+id/mix"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="center"
android:text="@string/mix_on"
android:textSize="10sp"
android:drawablePadding="5dp"
android:layout_marginEnd="20dp"
android:drawableTop="@drawable/selector_push_drawable_mix"
android:textColor="@drawable/selector_push_text_color"/>
<TextView
android:id="@+id/mic"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="center"
android:text="@string/mic_on"
android:textSize="10sp"
android:drawablePadding="1dp"
android:layout_marginEnd="20dp"
android:drawableTop="@drawable/selector_push_drawable_mic"
android:textColor="@drawable/selector_push_text_color"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,228 @@
<?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="#1C1D22"
android:fitsSystemWindows="true"
android:orientation="vertical">
<View
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#141416" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#1C1D22"
android:orientation="vertical">
<LinearLayout
android:id="@+id/title_layout"
android:layout_width="match_parent"
android:layout_height="63dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="24dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_back"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginTop="8dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_live_action_bar_back" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_marginStart="8dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="0dp"
android:background="#23262F"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/qr_code"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:background="@drawable/ic_live_scan"
android:scaleType="fitXY" />
<EditText
android:id="@+id/url_editor"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@null"
android:ellipsize="end"
android:hint="@string/view_string_hint_push_url"
android:singleLine="true"
android:textColor="#747A8C"
android:textColorHint="#747A8C"
android:textSize="@dimen/view_size_text_14" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#3A3D48" />
<TextView
android:id="@+id/note_text"
android:layout_width="match_parent"
android:layout_height="39dp"
android:background="@color/tips_color"
android:gravity="center"
android:text="@string/screen_note"
android:textColor="@color/wheel_white"
android:visibility="gone" />
<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/resolution_label"
android:textColor="#747A8C"
android:textSize="@dimen/font_size_24px" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_size_45"
android:orientation="horizontal"
android:paddingEnd="20dp">
<SeekBar
android:id="@+id/resolution_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:progressDrawable="@drawable/live_seekbar_drawable"
android:layout_marginEnd="30dp"
android:maxHeight="5dp"
android:minHeight="5dp"
android:progress="80"
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>
<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/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:paddingEnd="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="@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/narrowband_hd"
android:textColor="#FCFCFD"
android:textSize="@dimen/font_size_30px" />
<Switch
android:id="@+id/narrowband_hd"
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>
</LinearLayout>
<TextView
android:id="@+id/pushStatusTex"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="42dp"
android:background="@drawable/shape_rect_blue"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="false"
android:maxLines="2"
android:text="@string/start_push"
android:textColor="@android:color/white"
android:textSize="@dimen/font_size_28px" />
</FrameLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="screen_note">You can start other applications and start live...</string>
<string name="screen_note1">The screen function has stopped.</string>
<string name="narrowband_hd">Narrowband HD</string>
<string name="permission_float_deny_toast">The floating window permission is required. Obtain the floating window permission and try again.</string>
<string name="permission_alert_cancel_tip">Enable Later</string>
<string name="permission_alert_submit_tip">Enable Now</string>
<string name="back">back</string>
<string name="privacy_on">Privacy</string>
<string name="camera_on">Camera</string>
<string name="mix_on">Mix</string>
<string name="mix_off">Mix Off</string>
<string name="mic_on">Mic</string>
<string name="mic_off">Mic Off</string>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="screen_note">录制中</string>
<string name="screen_note1">录屏功能已停止</string>
<string name="narrowband_hd">窄带高清</string>
<string name="permission_float_deny_toast">您的手机没有授予悬浮窗权限,请开启后再试</string>
<string name="permission_alert_cancel_tip">暂不开启</string>
<string name="permission_alert_submit_tip">现在去开启</string>
<string name="back">返回</string>
<string name="privacy_on">隐私模式</string>
<string name="camera_on">摄像头</string>
<string name="mix_on">混流</string>
<string name="mix_off">混流关</string>
<string name="mic_on">麦克风</string>
<string name="mic_off">麦克风关</string>
</resources>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="screen_note">You can start other applications and start live...</string>
<string name="screen_note1">The screen function has stopped.</string>
<string name="narrowband_hd">Narrowband HD</string>
<string name="permission_float_deny_toast">The floating window permission is required. Obtain the floating window permission and try again.</string>
<string name="permission_alert_cancel_tip">Enable Later</string>
<string name="permission_alert_submit_tip">Enable Now</string>
<string name="back">back</string>
<string name="privacy_on">Privacy</string>
<string name="camera_on">Camera</string>
<string name="mix_on">Mix</string>
<string name="mix_off">Mix Off</string>
<string name="mic_on">Mic</string>
<string name="mic_off">Mic Off</string>
</resources>