Browse Source

修改学生端直播间页面

Pq 2 years ago
parent
commit
ad61694fa7
100 changed files with 6620 additions and 5 deletions
  1. 2 0
      BaseLibrary/build.gradle
  2. BIN
      BaseLibrary/libs/emoji-ios-release.aar
  3. BIN
      BaseLibrary/libs/emoji-release.aar
  4. 2 0
      BaseLibrary/src/main/java/com/cooleshow/base/common/WebConstants.java
  5. 1 0
      BaseLibrary/src/main/java/com/cooleshow/base/router/RouterPath.kt
  6. 49 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/AppUtils.java
  7. 172 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/SoftKeyboardUtil.java
  8. 86 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/SoftKeyboardUtils.java
  9. 5 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/UiUtils.java
  10. 2 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/UriUtils.java
  11. 154 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/InputBar.java
  12. 70 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/dialog/InputBarDialog.java
  13. BIN
      BaseLibrary/src/main/res/drawable-xhdpi/ic_voice_room_emoji.png
  14. BIN
      BaseLibrary/src/main/res/drawable-xhdpi/ic_voice_room_keybroad.png
  15. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/ic_voice_room_emoji.png
  16. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/ic_voice_room_keybroad.png
  17. 9 0
      BaseLibrary/src/main/res/drawable/bg_white_shape_5dp.xml
  18. 6 0
      BaseLibrary/src/main/res/drawable/shape_live_room_chat_input_bg.xml
  19. 5 0
      BaseLibrary/src/main/res/drawable/shape_live_room_chat_send_bg.xml
  20. 65 0
      BaseLibrary/src/main/res/layout/view_inputbar.xml
  21. 11 0
      BaseLibrary/src/main/res/values/colors.xml
  22. 1 0
      BaseLibrary/src/main/res/values/dimens.xml
  23. 12 0
      BaseLibrary/src/main/res/values/styles.xml
  24. 6 0
      rong_im/live/src/main/java/com/rong/io/live/LiveRoomMsgConstants.java
  25. 8 0
      rong_im/live/src/main/java/com/rong/io/live/config/LiveConfig.java
  26. 189 0
      rong_im/live/src/main/java/com/rong/io/live/helper/VideoViewManager.java
  27. 8 5
      rong_im/live/src/main/java/com/rong/io/live/message/RCChatRoomMemberNumMessage.java
  28. 114 0
      rong_im/live/src/main/java/com/rong/io/live/message/RCLiveBlackUserBlockMessage.java
  29. 113 0
      rong_im/live/src/main/java/com/rong/io/live/message/RCLiveBlackUserUnBlockMessage.java
  30. 117 0
      rong_im/live/src/main/java/com/rong/io/live/message/RCLiveGoodsChangeMessage.java
  31. 132 0
      rong_im/live/src/main/java/com/rong/io/live/message/RCOnSnappingUpMessage.java
  32. 90 0
      rong_im/live/src/main/java/com/rong/io/live/message/RCPauseLiveMessage.java
  33. 145 0
      rong_im/live/src/main/java/com/rong/io/live/widget/LiveRoomMicIconView.java
  34. BIN
      rong_im/live/src/main/res/drawable-xhdpi/icon_live_room_mic_other.png
  35. BIN
      rong_im/live/src/main/res/drawable-xhdpi/icon_live_room_mic_own.png
  36. BIN
      rong_im/live/src/main/res/drawable-xxhdpi/icon_live_room_mic_other.png
  37. BIN
      rong_im/live/src/main/res/drawable-xxhdpi/icon_live_room_mic_own.png
  38. 7 0
      rong_im/live/src/main/res/drawable/shape_gray_14dp_border_white.xml
  39. 5 0
      rong_im/live/src/main/res/drawable/shape_live_mic_bg_round.xml
  40. 5 0
      rong_im/live/src/main/res/drawable/shape_live_room_mic_nickname_bg.xml
  41. 5 0
      rong_im/live/src/main/res/drawable/shape_live_room_mic_nickname_bg_normal.xml
  42. 23 0
      rong_im/live/src/main/res/drawable/shape_live_video_progress.xml
  43. 43 0
      rong_im/live/src/main/res/layout/item_live_room_mic_user_layout.xml
  44. 63 0
      rong_im/live/src/main/res/layout/view_live_video_status_layout.xml
  45. 13 0
      student/src/main/AndroidManifest.xml
  46. 418 0
      student/src/main/java/com/cooleshow/student/adapter/MessageAdapter.java
  47. 34 0
      student/src/main/java/com/cooleshow/student/api/APIService.java
  48. 133 0
      student/src/main/java/com/cooleshow/student/bean/FriendInfoBean.java
  49. 71 0
      student/src/main/java/com/cooleshow/student/bean/ImUserState.java
  50. 157 0
      student/src/main/java/com/cooleshow/student/bean/LiveRoomInfoBean.java
  51. 171 0
      student/src/main/java/com/cooleshow/student/contract/LiveRoomContract.java
  52. 970 0
      student/src/main/java/com/cooleshow/student/presenter/live/LiveRoomPresenter.java
  53. 1707 0
      student/src/main/java/com/cooleshow/student/ui/live/LiveRoomActivity.java
  54. 302 0
      student/src/main/java/com/cooleshow/student/ui/live/floatPop/FloatWindowHelper.java
  55. 92 0
      student/src/main/java/com/cooleshow/student/ui/live/floatPop/FloatingWindowService.java
  56. 24 0
      student/src/main/java/com/cooleshow/student/utils/helper/LiveRTCEngineInitHelper.java
  57. 58 0
      student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomCloseMicTipDialog.java
  58. 66 0
      student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomClosePageOnMicTipDialog.java
  59. 58 0
      student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomCloseTipDialog.java
  60. 50 0
      student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomInviteSeatMicTipDialog.java
  61. 339 0
      student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomShopCarDialog.java
  62. 64 0
      student/src/main/java/com/cooleshow/student/widgets/dialog/OpenOverlayPermissionTipDialog.java
  63. 61 0
      student/src/main/java/com/cooleshow/student/widgets/helper/LiveRoomAddLikeHelper.java
  64. 107 0
      student/src/main/java/com/cooleshow/student/widgets/helper/LiveRoomAnimatorHelper.java
  65. BIN
      student/src/main/res/drawable-xhdpi/icon_add_like.png
  66. BIN
      student/src/main/res/drawable-xhdpi/icon_close_gray.png
  67. BIN
      student/src/main/res/drawable-xhdpi/icon_like_num.png
  68. BIN
      student/src/main/res/drawable-xhdpi/icon_live_msg_room_author.png
  69. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_1.png
  70. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_2.png
  71. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_3.png
  72. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_4.png
  73. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_5.png
  74. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_6.png
  75. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_7.png
  76. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_add_like_8.png
  77. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_chat_speak.png
  78. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_close_video.png
  79. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_number_people.png
  80. BIN
      student/src/main/res/drawable-xhdpi/icon_live_room_rest_bg.png
  81. BIN
      student/src/main/res/drawable-xhdpi/icon_live_shop_car_header.png
  82. BIN
      student/src/main/res/drawable-xhdpi/icon_mic_conected.png
  83. BIN
      student/src/main/res/drawable-xhdpi/icon_mic_connecting.png
  84. BIN
      student/src/main/res/drawable-xhdpi/icon_mic_unconnect.png
  85. BIN
      student/src/main/res/drawable-xhdpi/icon_video_orientation_convert.png
  86. BIN
      student/src/main/res/drawable-xxhdpi/icon_add_like.png
  87. BIN
      student/src/main/res/drawable-xxhdpi/icon_close_gray.png
  88. BIN
      student/src/main/res/drawable-xxhdpi/icon_like_num.png
  89. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_msg_room_author.png
  90. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_1.png
  91. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_2.png
  92. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_3.png
  93. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_4.png
  94. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_5.png
  95. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_6.png
  96. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_7.png
  97. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_8.png
  98. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_chat_speak.png
  99. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_close_video.png
  100. BIN
      student/src/main/res/drawable-xxhdpi/icon_live_room_number_people.png

+ 2 - 0
BaseLibrary/build.gradle

@@ -152,4 +152,6 @@ dependencies {
     api 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
     //圆角imageview
     api 'com.makeramen:roundedimageview:2.3.0'
+    //lottie动画
+    api 'com.airbnb.android:lottie:5.0.3'
 }

BIN
BaseLibrary/libs/emoji-ios-release.aar


BIN
BaseLibrary/libs/emoji-release.aar


+ 2 - 0
BaseLibrary/src/main/java/com/cooleshow/base/common/WebConstants.java

@@ -49,6 +49,8 @@ public abstract class WebConstants {
     public static  final String STUDENT_MUSIC_ALBUM=getBaseUrlH5() +"/#/music-album";
     //专辑详情
     public static  final String STUDENT_MUSIC_ALBUM_DETAIL=getBaseUrlH5() +"/#/music-album-detail/";
+    //学生端直播间购物车
+    public static  final String STUDENT_LIVE_SHOP_CAR_URL=getBaseUrlH5() +"/#/liveActiveList";
 
 
 

+ 1 - 0
BaseLibrary/src/main/java/com/cooleshow/base/router/RouterPath.kt

@@ -24,6 +24,7 @@ object RouterPath {
     class LiveCenter{
         companion object{
             const val PATH_LIVE ="/com/daya/live_teaching/ui/LiveActivity"
+            const val ACTIVITY_LIVE_ROOM="/com/cooleshow/student/ui/live/LiveRoomActivity"
             const val ACTIVITY_PHOTO_PREVIEW ="/com/daya/live_teaching/ui/ACTIVITY_PHOTO_PREVIEW"
         }
     }

+ 49 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/AppUtils.java

@@ -839,6 +839,55 @@ public final class AppUtils {
     }
 
     /**
+     * 判断APP是否在后台运行
+     *
+     * @param context
+     * @return
+     */
+    public static boolean isApplicationInBackground(Context context) {
+        ActivityManager acm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        if (acm != null) {
+            List<ActivityManager.RunningAppProcessInfo> runApps = acm.getRunningAppProcesses();
+            if (runApps != null && !runApps.isEmpty()) {
+                for (ActivityManager.RunningAppProcessInfo app : runApps) {
+                    if (app.processName.equals(context.getPackageName())) {
+                        //不是前台进程就返回true
+                        if (app.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断某个服务是否正在运行的方法
+     *
+     * @param mContext
+     * @param serviceName 是包名+服务的类名(例如:net.loonggg.testbackstage.TestService)
+     * @return true代表正在运行,false代表服务没有正在运行
+     */
+    public static boolean isServiceWork(Context mContext, String serviceName) {
+        boolean isWork = false;
+        ActivityManager myAM = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningServiceInfo> myList = myAM.getRunningServices(40);
+        if (myList.size() <= 0) {
+            return false;
+        }
+        for (int i = 0; i < myList.size(); i++) {
+            String mName = myList.get(i).service.getClassName().toString();
+            if (mName.equals(serviceName)) {
+                isWork = true;
+                break;
+            }
+        }
+        return isWork;
+    }
+
+
+    /**
      * The application's information.
      */
     public static class AppInfo {

+ 172 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/SoftKeyboardUtil.java

@@ -0,0 +1,172 @@
+package com.cooleshow.base.utils;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+
+public class SoftKeyboardUtil {
+    private static int sDecorViewDelta = 0;
+    private static final int TAG_ON_GLOBAL_LAYOUT_LISTENER = -8;
+    /**
+     * 隐藏或显示软键盘
+     * 如果现在是显示调用后则隐藏 反之则显示
+     *
+     * @param activity
+     */
+    public static void showORhideSoftKeyboard(Activity activity) {
+        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
+    }
+
+    /**
+     * 强制显示软键盘
+     *
+     * @param activity
+     */
+    public static void showSoftKeyboard(Activity activity) {
+        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.showSoftInput(activity.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED);
+    }
+
+    /**
+     * 强制隐藏软键盘
+     *
+     * @param activity
+     */
+    public static void hideSoftKeyboard(Activity activity) {
+        try {
+            InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+            imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); //强制隐藏键盘
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    /**
+     * 调用系统方法 强制隐藏软键盘
+     *
+     * @param activity
+     */
+    public static void hideSystemSoftKeyboard(Activity activity) {
+        ((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+    }
+
+    /**
+     * 判断软键盘是否显示方法
+     *
+     * @param activity
+     * @return
+     */
+
+    public static boolean isSoftShowing(Activity activity) {
+        //获取当屏幕内容的高度
+        int screenHeight = activity.getWindow().getDecorView().getHeight();
+        //获取View可见区域的bottom
+        Rect rect = new Rect();
+        //DecorView即为activity的顶级view
+        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+        //考虑到虚拟导航栏的情况(虚拟导航栏情况下:screenHeight = rect.bottom + 虚拟导航栏高度)
+        //选取screenHeight*2/3进行判断
+        return screenHeight * 2 / 3 > rect.bottom + getSoftButtonsBarHeight(activity);
+    }
+
+    /**
+     * 底部虚拟按键栏的高度
+     *
+     * @return
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    private static int getSoftButtonsBarHeight(Activity activity) {
+        DisplayMetrics metrics = new DisplayMetrics();
+        //这个方法获取可能不是真实屏幕的高度
+        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        int usableHeight = metrics.heightPixels;
+        //获取当前屏幕的真实高度
+        activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
+        int realHeight = metrics.heightPixels;
+        if (realHeight > usableHeight) {
+            return realHeight - usableHeight;
+        } else {
+            return 0;
+        }
+    }
+
+    public interface OnSoftInputChangedListener {
+        void onSoftInputChanged(int height);
+    }
+    /**
+     * Register soft input changed listener.
+     *
+     * @param window The window.
+     * @param listener The soft input changed listener.
+     */
+    public static void registerSoftInputChangedListener(@NonNull final Window window,
+                                                        @NonNull
+                                                        final OnSoftInputChangedListener listener) {
+        final int flags = window.getAttributes().flags;
+        if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) {
+            window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        }
+        final FrameLayout contentView = window.findViewById(android.R.id.content);
+        final int[] decorViewInvisibleHeightPre = { getDecorViewInvisibleHeight(window) };
+        ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+            @Override
+            public void onGlobalLayout() {
+                int height = getDecorViewInvisibleHeight(window);
+                if (decorViewInvisibleHeightPre[0] != height) {
+                    listener.onSoftInputChanged(height);
+                    decorViewInvisibleHeightPre[0] = height;
+                }
+            }
+        };
+        contentView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
+        contentView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, onGlobalLayoutListener);
+    }
+
+    /**
+     * Unregister soft input changed listener.
+     *
+     * @param window The window.
+     */
+    public static void unregisterSoftInputChangedListener(@NonNull final Window window) {
+        final View contentView = window.findViewById(android.R.id.content);
+        if (contentView == null) {
+            return;
+        }
+        Object tag = contentView.getTag(TAG_ON_GLOBAL_LAYOUT_LISTENER);
+        if (tag instanceof ViewTreeObserver.OnGlobalLayoutListener) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                contentView.getViewTreeObserver().removeOnGlobalLayoutListener((ViewTreeObserver.OnGlobalLayoutListener) tag);
+                //这里会发生内存泄漏 如果不设置为null
+                contentView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, null);
+            }
+        }
+    }
+
+    private static int getDecorViewInvisibleHeight(@NonNull final Window window) {
+        final View decorView = window.getDecorView();
+        final Rect outRect = new Rect();
+        decorView.getWindowVisibleDisplayFrame(outRect);
+        Log.d("KeyboardUtils",
+                "getDecorViewInvisibleHeight: " + (decorView.getBottom() - outRect.bottom));
+        int delta = Math.abs(decorView.getBottom() - outRect.bottom);
+        if (delta <= BarUtils.getNavBarHeight() + BarUtils.getStatusBarHeight()) {
+            sDecorViewDelta = delta;
+            return 0;
+        }
+        return delta - sDecorViewDelta;
+    }
+}

+ 86 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/SoftKeyboardUtils.java

@@ -0,0 +1,86 @@
+package com.cooleshow.base.utils;
+
+import android.app.Service;
+import android.content.Context;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.annotation.Nullable;
+
+
+public final class SoftKeyboardUtils {
+
+    private SoftKeyboardUtils() {
+        // no instance.
+    }
+
+    public static boolean isShown(Context context) {
+        InputMethodManager inputManager = getInputManager(context);
+        return inputManager != null && inputManager.isAcceptingText();
+    }
+
+    @Nullable
+    private static InputMethodManager getInputManager(Context context) {
+        if (context == null) {
+            return null;
+        }
+
+        return (InputMethodManager) context.getSystemService(Service.INPUT_METHOD_SERVICE);
+    }
+
+    public static void showSoftKeyboard(final View view) {
+        showSoftKeyboard(view, 100, false);
+    }
+
+    public static void showSoftKeyboard(final View view, final long delayedTime, final boolean force) {
+        if (view == null) {
+            return;
+        }
+
+        final InputMethodManager inputMethodManager = getInputManager(view.getContext());
+        if (inputMethodManager == null) {
+            return;
+        }
+        UiUtils.postDelayed(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        view.requestFocus();
+                        view.setFocusable(true);
+                        view.setFocusableInTouchMode(true);
+                        inputMethodManager.showSoftInput(view, InputMethodManager.RESULT_UNCHANGED_SHOWN);
+                    }
+                },
+                delayedTime
+        );
+    }
+
+    public static void showSoftKeyboard(final View view, final long delayedTime) {
+        showSoftKeyboard(view, delayedTime, false);
+    }
+
+    public static void hideSoftKeyboard(final View view) {
+        hideSoftKeyboard(view, 0);
+    }
+
+    public static void hideSoftKeyboard(final View view, final long delayedTime) {
+        if (view == null) {
+            return;
+        }
+
+        final InputMethodManager inputMethodManager = getInputManager(view.getContext());
+        if (inputMethodManager == null) {
+            return;
+        }
+        if (delayedTime == 0) {
+            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
+        } else {
+            UiUtils.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
+                }
+            }, delayedTime);
+        }
+    }
+}

+ 5 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/UiUtils.java

@@ -101,6 +101,11 @@ public class UiUtils {
         return getMaxHeightAtAspectRatio(context, ratio);
     }
 
+    public static int getHeightAtRatio16_9(Context context, float width) {
+        float ratio = 16 / 9f;
+        return (int) (width / ratio);
+    }
+
     public static int getMaxHeightAtAspectRatio(Context context, float ratio) {
         DisplayMetrics deviceSize = DeviceUtil.getDeviceSize(context);
         if (deviceSize != null) {

+ 2 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/UriUtils.java

@@ -228,6 +228,8 @@ public final class UriUtils {
                     contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                 } else if ("audio".equals(type)) {
                     contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+                } else if("document".equals(type)){
+                    contentUri = MediaStore.Files.getContentUri("external");
                 } else {
                     Log.d("UriUtils", uri.toString() + " parse failed. -> 1_2");
                     return null;

+ 154 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/InputBar.java

@@ -0,0 +1,154 @@
+package com.cooleshow.base.widgets;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Space;
+import android.widget.TextView;
+
+import com.cooleshow.base.R;
+import com.cooleshow.base.utils.SizeUtils;
+import com.cooleshow.base.utils.SoftKeyboardUtil;
+import com.cooleshow.base.utils.SoftKeyboardUtils;
+import com.vanniktech.emoji.EmojiEditText;
+import com.vanniktech.emoji.EmojiPopup;
+import com.vanniktech.emoji.listeners.OnEmojiPopupDismissListener;
+import com.vanniktech.emoji.listeners.OnEmojiPopupShownListener;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.core.graphics.drawable.DrawableCompat;
+
+/**
+ * Created by gyn on 2021/11/12
+ */
+public class InputBar extends LinearLayout implements OnEmojiPopupShownListener, OnEmojiPopupDismissListener {
+    private final static String TAG = InputBar.class.getSimpleName();
+    private EmojiEditText etInput;
+    private Space space1;
+    private ImageView ivEmoji;
+    private Space space2;
+    private TextView tvSend;
+    private InputBarListener inputBarListener;
+    /**
+     * emoji选择框
+     */
+    private EmojiPopup mEmojiPopup;
+
+    public InputBar(Context context) {
+        this(context, null);
+    }
+
+    public InputBar(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        LayoutInflater.from(context).inflate(R.layout.view_inputbar, this);
+        initView();
+    }
+
+
+    public void initView() {
+        // init view
+        this.setOrientation(HORIZONTAL);
+        this.setBackgroundColor(getContext().getResources().getColor(R.color.white));
+        this.setMinimumHeight(SizeUtils.dp2px(50));
+        this.setGravity(Gravity.CENTER_VERTICAL);
+        this.setPadding(SizeUtils.dp2px(12), SizeUtils.dp2px( 7), SizeUtils.dp2px(12), SizeUtils.dp2px(7));
+        etInput = (EmojiEditText) findViewById(R.id.et_input);
+        space1 = (Space) findViewById(R.id.space1);
+        ivEmoji = (ImageView) findViewById(R.id.iv_emoji);
+        space2 = (Space) findViewById(R.id.space2);
+        tvSend = (TextView) findViewById(R.id.tv_send);
+        setEmoJiImage(R.drawable.ic_voice_room_emoji);
+        setPopup();
+        ivEmoji.setOnClickListener(v -> {
+            if (inputBarListener != null) {
+                boolean intercept = inputBarListener.onClickEmoji();
+                if (intercept) {
+
+                } else {
+                    mEmojiPopup.toggle();
+                }
+            }
+        });
+        tvSend.setOnClickListener(v -> {
+            send();
+        });
+        etInput.setOnEditorActionListener((v, actionId, event) -> {
+            send();
+            return false;
+        });
+    }
+
+    private void setPopup() {
+        mEmojiPopup = EmojiPopup
+                .Builder
+                .fromRootView(this)
+                .setPopGravity(Gravity.LEFT)
+                .setKeyboardAnimationStyle(R.style.my_emoji_fade_animation_style)
+                .setOnEmojiPopupShownListener(this)
+                .setOnEmojiPopupDismissListener(this).build(etInput);
+    }
+
+    private void setEmoJiImage(@DrawableRes int resId) {
+        Drawable drawable = ContextCompat.getDrawable(getContext(), resId);
+        Drawable.ConstantState state = drawable.getConstantState();
+        Drawable drawable1 = DrawableCompat.wrap(state == null ? drawable : state.newDrawable()).mutate();
+        drawable1.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+        DrawableCompat.setTint(drawable, ContextCompat.getColor(getContext(), R.color.black_333));
+        ivEmoji.setImageDrawable(drawable);
+    }
+
+    public void send() {
+        String message = "";
+        if (etInput.getText() != null) {
+            message = etInput.getText().toString().trim();
+        }
+        etInput.setText("");
+
+        if (inputBarListener != null) {
+            inputBarListener.onClickSend(message);
+        }
+    }
+
+    public void showInputBar() {
+        setPopup();
+//        this.setVisibility(VISIBLE);
+        etInput.requestFocus();
+        etInput.setFocusable(true);
+        etInput.setFocusableInTouchMode(true);
+        SoftKeyboardUtils.showSoftKeyboard(etInput, 50);
+    }
+
+    public void hideInputBar() {
+        mEmojiPopup.dismiss();
+//        this.setVisibility(GONE);
+        etInput.clearFocus();
+        SoftKeyboardUtils.hideSoftKeyboard(etInput);
+    }
+
+    public void setInputBarListener(InputBarListener inputBarListener) {
+        this.inputBarListener = inputBarListener;
+    }
+
+    @Override
+    public void onEmojiPopupDismiss() {
+        setEmoJiImage(R.drawable.ic_voice_room_emoji);
+    }
+
+    @Override
+    public void onEmojiPopupShown() {
+        setEmoJiImage(R.drawable.ic_voice_room_keybroad);
+    }
+
+    public interface InputBarListener {
+
+        void onClickSend(String message);
+
+        boolean onClickEmoji();
+    }
+}

+ 70 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/dialog/InputBarDialog.java

@@ -0,0 +1,70 @@
+package com.cooleshow.base.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.view.Gravity;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.cooleshow.base.R;
+import com.cooleshow.base.widgets.InputBar;
+
+
+/**
+ * 底部编辑弹框
+ */
+public class InputBarDialog extends Dialog {
+    InputBar.InputBarListener inputBarListener;
+    InputBar inputBar;
+
+    public InputBarDialog(Context context, InputBar.InputBarListener inputBarListener) {
+        super(context, R.style.InputBar_Dialog_Style);
+        this.inputBarListener = inputBarListener;
+        inputBar = new InputBar(context);
+        inputBar.setInputBarListener(new InputBar.InputBarListener() {
+            @Override
+            public void onClickSend(String message) {
+                dismiss();
+                if (inputBarListener != null) {
+                    inputBarListener.onClickSend(message);
+                }
+            }
+
+            @Override
+            public boolean onClickEmoji() {
+                if (inputBarListener != null) {
+                    return inputBarListener.onClickEmoji();
+                }
+                return false;
+            }
+        });
+        setContentView(inputBar);
+        Window window = getWindow();
+        if (window != null) {
+            //获取对话框当前的参数值
+            WindowManager.LayoutParams params = window.getAttributes();
+            params.gravity = Gravity.BOTTOM;
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            window.setAttributes(params);
+        }
+    }
+
+    @Override
+    public void dismiss() {
+        if (inputBar != null) {
+            inputBar.hideInputBar();
+        }
+        super.dismiss();
+    }
+
+    public void showInput(){
+        if (inputBar != null) {
+            inputBar.showInputBar();
+        }
+    }
+
+    @Override
+    public void show() {
+        super.show();
+    }
+}

BIN
BaseLibrary/src/main/res/drawable-xhdpi/ic_voice_room_emoji.png


BIN
BaseLibrary/src/main/res/drawable-xhdpi/ic_voice_room_keybroad.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/ic_voice_room_emoji.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/ic_voice_room_keybroad.png


+ 9 - 0
BaseLibrary/src/main/res/drawable/bg_white_shape_5dp.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+
+    <solid android:color="#ffffffff"/>
+
+    <corners android:radius="5dp"/>
+</shape>
+

+ 6 - 0
BaseLibrary/src/main/res/drawable/shape_live_room_chat_input_bg.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_F8F8F8"/>
+    <stroke android:color="@color/color_d1d1d1" android:width="1px"/>
+    <corners android:radius="3dp"/>
+</shape>

+ 5 - 0
BaseLibrary/src/main/res/drawable/shape_live_room_chat_send_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_00B7AC"/>
+    <corners android:radius="3dp"/>
+</shape>

+ 65 - 0
BaseLibrary/src/main/res/layout/view_inputbar.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/rootView"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/white"
+    android:paddingStart="12dp"
+    android:paddingTop="7dp"
+    android:paddingEnd="12dp"
+    android:paddingBottom="7dp"
+    tools:parentTag="android.widget.LinearLayout">
+
+    <com.vanniktech.emoji.EmojiEditText
+        android:background="@drawable/shape_live_room_chat_input_bg"
+        android:id="@+id/et_input"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:gravity="center_vertical"
+        android:hint="快来互动吧!"
+        android:imeOptions="actionSend"
+        android:maxHeight="108dp"
+        android:maxLines="3"
+        android:minHeight="36dp"
+        android:paddingStart="10dp"
+        android:paddingTop="5dp"
+        android:paddingEnd="10dp"
+        android:paddingBottom="5dp"
+        android:textColor="#333333"
+        android:textSize="14sp" />
+
+    <Space
+        android:id="@+id/space1"
+        android:layout_width="12dp"
+        android:layout_height="0dp" />
+
+    <ImageView
+        android:layout_gravity="center_vertical"
+        android:src="@drawable/ic_voice_room_emoji"
+        android:id="@+id/iv_emoji"
+        android:layout_width="32dp"
+        android:layout_height="32dp" />
+
+    <Space
+        android:id="@+id/space2"
+        android:layout_width="12dp"
+        android:layout_height="0dp" />
+
+    <TextView
+        android:background="@drawable/shape_live_room_chat_send_bg"
+        android:layout_gravity="center_vertical"
+        android:id="@+id/tv_send"
+        android:layout_width="wrap_content"
+        android:layout_height="30dp"
+        android:gravity="center"
+        android:paddingStart="14dp"
+        android:paddingEnd="14dp"
+        android:text="发送"
+        android:textColor="@color/white"
+        android:textSize="14sp" />
+
+</merge>

+ 11 - 0
BaseLibrary/src/main/res/values/colors.xml

@@ -95,4 +95,15 @@
     <color name="color_f97215">#F97215</color>
     <color name="color_ff4444">#FF4444</color>
     <color name="color_808080">#808080</color>
+    <color name="color_25292e">#25292E</color>
+    <color name="color_F8F8F8">#F8F8F8</color>
+    <color name="color_d1d1d1">#D1D1D1</color>
+    <color name="color_00B7AC">#00B7AC</color>
+    <color name="color_52000000">#52000000</color>
+    <color name="color_00d6c9">#00D6C9</color>
+    <color name="color_dedede">#DEDEDE</color>
+    <color name="white_translucent">#80ffffff</color>
+    <color name="white_50">#50ffffff</color>
+    <color name="color_b2b2b2">#B2B2B2</color>
+    <color name="color_90ffffff">#90ffffff</color>
 </resources>

+ 1 - 0
BaseLibrary/src/main/res/values/dimens.xml

@@ -14,6 +14,7 @@
     <dimen name="common_padding_small">5dp</dimen>
     <dimen name="common_radius">6dp</dimen>
     <dimen name="common_border_size">1px</dimen>
+    <dimen name="statusbar_view_height">0dp</dimen>
 
     <dimen name="text_small_size">12sp</dimen>
     <dimen name="text_middle_size">14sp</dimen>

+ 12 - 0
BaseLibrary/src/main/res/values/styles.xml

@@ -270,6 +270,8 @@
         <item name="android:windowExitAnimation">@anim/left_exit_anim</item>
     </style>
 
+    <style name="my_emoji_fade_animation_style" parent="emoji_fade_animation_style"/>
+
 
     <style name="picture.daya.style" parent="AppTheme">
         <!-- Customize your theme here. -->
@@ -339,6 +341,16 @@
         <item name="android:textSize">@dimen/sp_15</item>
     </style>
 
+    <style name="InputBar_Dialog_Style" parent="android:Theme.Dialog">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowFrame">@null</item><!--边框-->
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowIsTranslucent">false</item><!--半透明-->
+        <item name="android:backgroundDimEnabled">false</item><!--模糊-->
+    </style>
+
     <declare-styleable name="RatingBar">
         <!--尺寸值-->
         <attr name="starImageSize" format="dimension" />

+ 6 - 0
rong_im/live/src/main/java/com/rong/io/live/LiveRoomMsgConstants.java

@@ -12,6 +12,7 @@ public class LiveRoomMsgConstants {
     public static final int ACTION_SEND_CANCEL_SEAT_AGREE_RESPONSE = -105;//被邀请连麦->观众同意上麦
     public static final int ACTION_SEND_CANCEL_SEAT_DISAGREE_RESPONSE = -106;//被邀请连麦->观众不同意上麦
     public static final int ACTION_SEND_ADD_LIKE_COUNT = -107;//点赞数量发送
+    public static final int ACTION_SEND_ON_SNAP_UP = -108;//XX正在抢购
 
     public static final int MIC_ACTION_INVITE_SEAT_BY_CREATE = 1;//连麦-主讲人邀请
     public static final int MIC_ACTION_CANCEL_INVITE_SEAT_BY_CREATE = 2;//连麦-主讲人取消邀请
@@ -40,5 +41,10 @@ public class LiveRoomMsgConstants {
     public static final String TAG_CHAT_ROOM_CHAT_MODE_CTRL = "RC:Chatroom:ChatBan"; //聊天控制
     public static final String TAG_CHAT_ROOM_SEAT_APPLY = "RC:Chatroom:SeatApply"; //连麦申请
     public static final String TAG_CHAT_ROOM_SEAT_RESPONSE = "RC:Chatroom:SeatResponse"; //连麦行为响应
+    public static final String TAG_LIVE_GOODS_CHANGE = "DY:LIVE_GOODS_CHANGE"; //直播间商品变化
+    public static final String TAG_LIVE_PAUSE = "RC:Chatroom:PauseLive"; //暂停直播
+    public static final String TAG_LIVE_ON_SNAP_UP = "RC:Chatroom:SnapUp"; //正在抢购
+    public static final String TAG_LIVE_ADD_BLACK_USER= "RC:BLOCK_BLACK_USER"; //添加黑名单,禁止聊天,禁止连麦
+    public static final String TAG_LIVE_REMOVE_BLACK_USER= "RC:UNBLOCK_BLACK_USER"; //解除黑名单
 
 }

+ 8 - 0
rong_im/live/src/main/java/com/rong/io/live/config/LiveConfig.java

@@ -0,0 +1,8 @@
+package com.rong.io.live.config;
+
+/**
+ * Author by pq, Date on 2022/6/1.
+ */
+public class LiveConfig {
+    public static boolean isNeedReInitRTC =false;
+}

+ 189 - 0
rong_im/live/src/main/java/com/rong/io/live/helper/VideoViewManager.java

@@ -0,0 +1,189 @@
+package com.rong.io.live.helper;
+
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.cooleshow.base.utils.SizeUtils;
+import com.rong.io.live.R;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
+import cn.rongcloud.rtc.api.stream.view.RCRTCRendererEventsListener;
+import cn.rongcloud.rtc.core.RendererCommon;
+
+public class VideoViewManager {
+
+    private static final String TAG = "VideoViewManager";
+    private static final int MAX_WAIT_RENDER_TIME = 8000;
+    ArrayList<RCRTCVideoView> arrayListVideoView;
+    int mWidth, mHeight;
+    private RelativeLayout flSurfaceContainer;
+    private Map<String, RCRTCVideoView> linkedHashMap = new LinkedHashMap<>();
+    private boolean isFullScreen = false;
+    private int mainScreenPosition = 0;
+    private int otherVideoViewMaxWidth = 0;
+    private int otherVideoViewMaxHeight = 0;
+    private View mStatusView;
+    private ProgressBar mPbLoading;
+    private TextView mTvLoading;
+    private TextView mTvLiveStatusTipText;
+    private TextView mTvRetry;
+
+    private Runnable mRunnable = new Runnable() {
+        @Override
+        public void run() {
+            showRetryStatus();
+        }
+    };
+
+    public VideoViewManager(RelativeLayout surfaceContainer, int width, int height) {
+        flSurfaceContainer = surfaceContainer;
+        mWidth = width;
+        mHeight = height;
+        otherVideoViewMaxWidth = SizeUtils.dp2px(100);
+        otherVideoViewMaxHeight = SizeUtils.dp2px(57);
+        initStatusView();
+    }
+
+    private void initStatusView() {
+        mStatusView = LayoutInflater.from(flSurfaceContainer.getContext()).inflate(R.layout.view_live_video_status_layout, flSurfaceContainer, false);
+        mPbLoading = mStatusView.findViewById(R.id.pb_loading);
+        mTvLoading = mStatusView.findViewById(R.id.tv_loading);
+        mTvLiveStatusTipText = mStatusView.findViewById(R.id.tv_live_status_tip_text);
+        mTvRetry = mStatusView.findViewById(R.id.tv_retry);
+    }
+
+    /**
+     * 2 列多行显示 videoview
+     *
+     * @param list
+     */
+    public void update(ArrayList<RCRTCVideoView> list, int mainScreenPosition, boolean isShowLoading) {
+        Log.i("pq", "update" + list.size());
+        Log.i("pq", "mainScreenPosition" + mainScreenPosition);
+        arrayListVideoView = list;
+        this.mainScreenPosition = mainScreenPosition;
+        int row = 0;
+        int column = 0;
+
+//        column = list.size() > 1 ? 2 : 1;
+//        row = (list.size() + 1) / 2;
+        row = list.size();
+
+        flSurfaceContainer.removeAllViews();
+
+
+        int width = mWidth;
+        int height = mHeight;
+        int index = 0;
+        for (int i = 0; i < row; i++) {
+            RelativeLayout.LayoutParams layoutParams;
+//            if (i == mainScreenPosition) {
+//            } else {
+//                layoutParams = new RelativeLayout.LayoutParams(otherVideoViewMaxWidth, otherVideoViewMaxHeight);
+//                layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+//            }
+
+            layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+            layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+//                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+//            int marginLeft = j * (width / column);
+//            int marginRight = mWidth - (marginLeft + width / column);
+//            int marginTop = i * (height / row);
+//            int marginBottom = mHeight - (marginTop + height / row);
+//            layoutParams.setMargins(marginLeft, marginTop, marginRight, marginBottom);
+            if (index >= arrayListVideoView.size()) {
+                break;
+            }
+            arrayListVideoView.get(i).setRendererEventsListener(new RCRTCRendererEventsListener() {
+                @Override
+                public void onFirstFrame() {
+                    Log.i("pq", "视频第一帧渲染");
+                    hideStatusView();
+
+                }
+            });
+            arrayListVideoView.get(i).setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
+            flSurfaceContainer.addView(arrayListVideoView.get(i), layoutParams);
+            index++;
+        }
+        if (isShowLoading) {
+            showLoadStatus();
+        }
+    }
+
+    public void setRetryClickListener(View.OnClickListener retryClickListener) {
+        if (mTvRetry != null) {
+            mTvRetry.setOnClickListener(retryClickListener);
+        }
+    }
+
+    private void hideStatusView() {
+        if (mStatusView == null) {
+            return;
+        }
+        mStatusView.removeCallbacks(mRunnable);
+        mStatusView.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mStatusView != null) {
+                    mStatusView.setVisibility(View.GONE);
+                }
+            }
+        });
+    }
+
+    private void showLoadStatus() {
+        if (mStatusView == null) {
+            return;
+        }
+        flSurfaceContainer.addView(mStatusView);
+        mStatusView.setVisibility(View.VISIBLE);
+        mPbLoading.setVisibility(View.VISIBLE);
+        mTvLoading.setVisibility(View.VISIBLE);
+        mTvLiveStatusTipText.setVisibility(View.GONE);
+        mTvRetry.setVisibility(View.GONE);
+        mStatusView.postDelayed(mRunnable, MAX_WAIT_RENDER_TIME);
+    }
+
+    private void showRetryStatus() {
+        if (mStatusView == null) {
+            return;
+        }
+        mStatusView.setVisibility(View.VISIBLE);
+        mPbLoading.setVisibility(View.GONE);
+        mTvLoading.setVisibility(View.GONE);
+        mTvLiveStatusTipText.setVisibility(View.VISIBLE);
+        mTvRetry.setVisibility(View.VISIBLE);
+    }
+
+    public void release() {
+        if (null != arrayListVideoView && 0 != arrayListVideoView.size()) {
+            for (RCRTCVideoView v : arrayListVideoView) {
+                v.release();
+            }
+        }
+    }
+
+    public ArrayList<RCRTCVideoView> getAllVideoViews() {
+        return arrayListVideoView;
+    }
+
+    public void setIsNeedFillScreen(boolean isFullScreen) {
+        this.isFullScreen = isFullScreen;
+    }
+
+    public void onRelease() {
+        if (mStatusView != null && mRunnable != null) {
+            mStatusView.removeCallbacks(mRunnable);
+        }
+    }
+}

+ 8 - 5
rong_im/live/src/main/java/com/rong/io/live/message/RCChatRoomMemberNumMessage.java

@@ -17,9 +17,9 @@ import io.rong.imlib.model.UserInfo;
  * Author by pq, Date on 2022/4/1.
  * 观众数量(web发送消息 学生端同步数据)
  */
-@MessageTag(value = "RC:Chatroom:MemberCount", flag = MessageTag.STATUS)
+@MessageTag(value = "RC:Chatroom:MemberCountUp", flag = MessageTag.STATUS)
 public class RCChatRoomMemberNumMessage extends MessageContent {
-    private String count ;
+    private String count;
 
     public String getCount() {
         return count;
@@ -41,8 +41,11 @@ public class RCChatRoomMemberNumMessage extends MessageContent {
         }
         try {
             JSONObject jsonObject = new JSONObject(jsonStr);
-            if (jsonObject.has("count")) {
-                count = jsonObject.optString("count");
+            if (jsonObject.has("content")) {
+                JSONObject content = (JSONObject) jsonObject.opt("content");
+                if (content != null) {
+                    count = content.optString("count");
+                }
             }
 
             if (jsonObject.has("user")) {
@@ -92,7 +95,7 @@ public class RCChatRoomMemberNumMessage extends MessageContent {
     protected RCChatRoomMemberNumMessage(Parcel in) {
         this.count = in.readString();
         this.setExtra(ParcelUtils.readFromParcel(in));
-        this.setUserInfo((UserInfo)ParcelUtils.readFromParcel(in, UserInfo.class));
+        this.setUserInfo((UserInfo) ParcelUtils.readFromParcel(in, UserInfo.class));
     }
 
     public static final Creator<RCChatRoomMemberNumMessage> CREATOR = new Creator<RCChatRoomMemberNumMessage>() {

+ 114 - 0
rong_im/live/src/main/java/com/rong/io/live/message/RCLiveBlackUserBlockMessage.java

@@ -0,0 +1,114 @@
+package com.rong.io.live.message;
+
+import android.os.Parcel;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+
+import io.rong.common.ParcelUtils;
+import io.rong.imlib.MessageTag;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/4/1.
+ * 黑名单消息-禁止聊天禁止发起连麦
+ */
+@MessageTag(value = "RC:BLOCK_BLACK_USER", flag = MessageTag.STATUS)
+public class RCLiveBlackUserBlockMessage extends MessageContent {
+    private String userId;
+
+
+    public RCLiveBlackUserBlockMessage() {
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String str) {
+        this.userId = str;
+    }
+
+    public RCLiveBlackUserBlockMessage(byte[] data) {
+        String jsonStr = null;
+        try {
+            jsonStr = new String(data, "UTF-8");
+            Log.i("pq", "json:" + jsonStr);
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        try {
+            JSONObject jsonObject = new JSONObject(jsonStr);
+
+            if (jsonObject.has("user")) {
+                setUserInfo(this.parseJsonToUserInfo(jsonObject.getJSONObject("user")));
+            }
+
+            if (jsonObject.has("content")) {
+                JSONObject content = (JSONObject) jsonObject.opt("content");
+                if (content != null) {
+                    userId = content.optString("userId");
+                }
+            }
+            Log.i("pq", "add black user userId:" + userId);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public byte[] encode() {
+        JSONObject jsonObj = new JSONObject();
+        try {
+            // 消息携带用户信息时, 自定义消息需添加下面代码
+            JSONObject jsonUserInfo = this.getJSONUserInfo();
+            if (jsonUserInfo != null) {
+                jsonObj.putOpt("user", jsonUserInfo);
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        try {
+            return jsonObj.toString().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.userId);
+        ParcelUtils.writeToParcel(dest, getExtra());
+        ParcelUtils.writeToParcel(dest, getUserInfo());
+    }
+
+    protected RCLiveBlackUserBlockMessage(Parcel in) {
+        this.userId = in.readString();
+        this.setExtra(ParcelUtils.readFromParcel(in));
+        this.setUserInfo((UserInfo) ParcelUtils.readFromParcel(in, UserInfo.class));
+    }
+
+    public static final Creator<RCLiveBlackUserBlockMessage> CREATOR = new Creator<RCLiveBlackUserBlockMessage>() {
+        @Override
+        public RCLiveBlackUserBlockMessage createFromParcel(Parcel source) {
+            return new RCLiveBlackUserBlockMessage(source);
+        }
+
+        @Override
+        public RCLiveBlackUserBlockMessage[] newArray(int size) {
+            return new RCLiveBlackUserBlockMessage[size];
+        }
+    };
+}

+ 113 - 0
rong_im/live/src/main/java/com/rong/io/live/message/RCLiveBlackUserUnBlockMessage.java

@@ -0,0 +1,113 @@
+package com.rong.io.live.message;
+
+import android.os.Parcel;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+
+import io.rong.common.ParcelUtils;
+import io.rong.imlib.MessageTag;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/4/1.
+ * 黑名单解除消息
+ */
+@MessageTag(value = "RC:UNBLOCK_BLACK_USER", flag = MessageTag.STATUS)
+public class RCLiveBlackUserUnBlockMessage extends MessageContent {
+    private String userId;
+
+
+    public RCLiveBlackUserUnBlockMessage() {
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String str) {
+        this.userId = str;
+    }
+
+    public RCLiveBlackUserUnBlockMessage(byte[] data) {
+        String jsonStr = null;
+        try {
+            jsonStr = new String(data, "UTF-8");
+            Log.i("pq", "json:" + jsonStr);
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        try {
+            JSONObject jsonObject = new JSONObject(jsonStr);
+
+            if (jsonObject.has("user")) {
+                setUserInfo(this.parseJsonToUserInfo(jsonObject.getJSONObject("user")));
+            }
+
+            if (jsonObject.has("content")) {
+                JSONObject content = (JSONObject) jsonObject.opt("content");
+                if (content != null) {
+                    userId = content.optString("userId");
+                }
+            }
+            Log.i("pq", "add black user userId:" + userId);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public byte[] encode() {
+        JSONObject jsonObj = new JSONObject();
+        try {
+            // 消息携带用户信息时, 自定义消息需添加下面代码
+            JSONObject jsonUserInfo = this.getJSONUserInfo();
+            if (jsonUserInfo != null) {
+                jsonObj.putOpt("user", jsonUserInfo);
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        try {
+            return jsonObj.toString().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.userId);
+        ParcelUtils.writeToParcel(dest, getExtra());
+        ParcelUtils.writeToParcel(dest, getUserInfo());
+    }
+
+    protected RCLiveBlackUserUnBlockMessage(Parcel in) {
+        this.userId = in.readString();
+        this.setExtra(ParcelUtils.readFromParcel(in));
+        this.setUserInfo((UserInfo) ParcelUtils.readFromParcel(in, UserInfo.class));
+    }
+
+    public static final Creator<RCLiveBlackUserUnBlockMessage> CREATOR = new Creator<RCLiveBlackUserUnBlockMessage>() {
+        @Override
+        public RCLiveBlackUserUnBlockMessage createFromParcel(Parcel source) {
+            return new RCLiveBlackUserUnBlockMessage(source);
+        }
+
+        @Override
+        public RCLiveBlackUserUnBlockMessage[] newArray(int size) {
+            return new RCLiveBlackUserUnBlockMessage[size];
+        }
+    };
+}

+ 117 - 0
rong_im/live/src/main/java/com/rong/io/live/message/RCLiveGoodsChangeMessage.java

@@ -0,0 +1,117 @@
+package com.rong.io.live.message;
+
+import android.os.Parcel;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import io.rong.common.ParcelUtils;
+import io.rong.imlib.MessageTag;
+import io.rong.imlib.model.MentionedInfo;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/4/1.
+ * 直播购物车商品变化
+ */
+@MessageTag(value = "DY:LIVE_GOODS_CHANGE", flag = MessageTag.STATUS)
+public class RCLiveGoodsChangeMessage extends MessageContent {
+    private String goodsContent;
+
+
+    public RCLiveGoodsChangeMessage() {
+    }
+
+    public String getContent() {
+        return goodsContent;
+    }
+
+    public void setContent(String str) {
+        this.goodsContent = str;
+    }
+
+    public RCLiveGoodsChangeMessage(byte[] data) {
+        String jsonStr = null;
+        try {
+            jsonStr = new String(data, "UTF-8");
+            Log.i("pq", "json:" + jsonStr);
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        try {
+            JSONObject jsonObject = new JSONObject(jsonStr);
+
+            if (jsonObject.has("user")) {
+                setUserInfo(this.parseJsonToUserInfo(jsonObject.getJSONObject("user")));
+            }
+
+            if (jsonObject.has("content")) {
+                JSONArray jsonArray = jsonObject.optJSONArray("content");
+                goodsContent = jsonArray.toString();
+            }
+            Log.i("pq", "goodsContent:" + goodsContent);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public byte[] encode() {
+        JSONObject jsonObj = new JSONObject();
+        try {
+            // 消息携带用户信息时, 自定义消息需添加下面代码
+            JSONObject jsonUserInfo = this.getJSONUserInfo();
+            if (jsonUserInfo != null) {
+                jsonObj.putOpt("user", jsonUserInfo);
+            }
+
+            jsonObj.putOpt("content", goodsContent);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        try {
+            return jsonObj.toString().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.goodsContent);
+        ParcelUtils.writeToParcel(dest, getExtra());
+        ParcelUtils.writeToParcel(dest, getUserInfo());
+    }
+
+    protected RCLiveGoodsChangeMessage(Parcel in) {
+        this.goodsContent = in.readString();
+        this.setExtra(ParcelUtils.readFromParcel(in));
+        this.setUserInfo((UserInfo) ParcelUtils.readFromParcel(in, UserInfo.class));
+    }
+
+    public static final Creator<RCLiveGoodsChangeMessage> CREATOR = new Creator<RCLiveGoodsChangeMessage>() {
+        @Override
+        public RCLiveGoodsChangeMessage createFromParcel(Parcel source) {
+            return new RCLiveGoodsChangeMessage(source);
+        }
+
+        @Override
+        public RCLiveGoodsChangeMessage[] newArray(int size) {
+            return new RCLiveGoodsChangeMessage[size];
+        }
+    };
+}

+ 132 - 0
rong_im/live/src/main/java/com/rong/io/live/message/RCOnSnappingUpMessage.java

@@ -0,0 +1,132 @@
+package com.rong.io.live.message;
+
+import android.os.Parcel;
+import android.text.TextUtils;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+
+import io.rong.common.ParcelUtils;
+import io.rong.imlib.MessageTag;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/4/1.
+ * xxx正在抢购消息
+ */
+@MessageTag(value = "RC:Chatroom:SnapUp",flag = MessageTag.STATUS)
+public class RCOnSnappingUpMessage extends MessageContent {
+    private String userId ;
+    private String userName;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+
+    public RCOnSnappingUpMessage() {
+    }
+    public RCOnSnappingUpMessage(byte[] data) {
+        String jsonStr = null;
+        try {
+            jsonStr = new String(data, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        try {
+            JSONObject jsonObject = new JSONObject(jsonStr);
+            if(jsonObject.has("userId")){
+                userId = jsonObject.optString("userId");
+            }
+            if(jsonObject.has("userName")){
+                userName = jsonObject.optString("userName");
+            }
+
+            if (jsonObject.has("user")) {
+                setUserInfo(this.parseJsonToUserInfo(jsonObject.getJSONObject("user")));
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public byte[] encode() {
+        JSONObject jsonObj = new JSONObject();
+        try {
+            // 消息携带用户信息时, 自定义消息需添加下面代码
+            if(!TextUtils.isEmpty(userId)){
+                jsonObj.putOpt("userId", userId);
+            }
+            if(!TextUtils.isEmpty(userName)){
+                jsonObj.putOpt("userName", userName);
+            }
+
+            JSONObject jsonUserInfo = this.getJSONUserInfo();
+            if (jsonUserInfo != null) {
+                jsonObj.putOpt("user", jsonUserInfo);
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        try {
+            return jsonObj.toString().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.userId);
+        dest.writeString(this.userName);
+        ParcelUtils.writeToParcel(dest, getExtra());
+        ParcelUtils.writeToParcel(dest, getUserInfo());
+    }
+
+    public void readFromParcel(Parcel source) {
+        this.userId = source.readString();
+        this.userName = source.readString();
+    }
+
+    protected RCOnSnappingUpMessage(Parcel in) {
+        this.userId = in.readString();
+        this.userName = in.readString();
+        this.setExtra(ParcelUtils.readFromParcel(in));
+        this.setUserInfo((UserInfo)ParcelUtils.readFromParcel(in, UserInfo.class));
+    }
+
+    public static final Creator<RCOnSnappingUpMessage> CREATOR = new Creator<RCOnSnappingUpMessage>() {
+        @Override
+        public RCOnSnappingUpMessage createFromParcel(Parcel source) {
+            return new RCOnSnappingUpMessage(source);
+        }
+
+        @Override
+        public RCOnSnappingUpMessage[] newArray(int size) {
+            return new RCOnSnappingUpMessage[size];
+        }
+    };
+}

+ 90 - 0
rong_im/live/src/main/java/com/rong/io/live/message/RCPauseLiveMessage.java

@@ -0,0 +1,90 @@
+package com.rong.io.live.message;
+
+import android.os.Parcel;
+import android.text.TextUtils;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+
+import io.rong.common.ParcelUtils;
+import io.rong.imlib.MessageTag;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/4/1.
+ * 暂停直播
+ */
+@MessageTag(value = "RC:Chatroom:PauseLive",flag = MessageTag.STATUS)
+public class RCPauseLiveMessage extends MessageContent {
+    public RCPauseLiveMessage() {
+    }
+    public RCPauseLiveMessage(byte[] data) {
+        String jsonStr = null;
+        try {
+            jsonStr = new String(data, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        try {
+            JSONObject jsonObject = new JSONObject(jsonStr);
+
+            if (jsonObject.has("user")) {
+                setUserInfo(this.parseJsonToUserInfo(jsonObject.getJSONObject("user")));
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public byte[] encode() {
+        JSONObject jsonObj = new JSONObject();
+        try {
+            // 消息携带用户信息时, 自定义消息需添加下面代码
+            JSONObject jsonUserInfo = this.getJSONUserInfo();
+            if (jsonUserInfo != null) {
+                jsonObj.putOpt("user", jsonUserInfo);
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        try {
+            return jsonObj.toString().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        ParcelUtils.writeToParcel(dest, getExtra());
+        ParcelUtils.writeToParcel(dest, getUserInfo());
+    }
+
+    protected RCPauseLiveMessage(Parcel in) {
+        this.setExtra(ParcelUtils.readFromParcel(in));
+        this.setUserInfo((UserInfo)ParcelUtils.readFromParcel(in, UserInfo.class));
+    }
+
+    public static final Creator<RCPauseLiveMessage> CREATOR = new Creator<RCPauseLiveMessage>() {
+        @Override
+        public RCPauseLiveMessage createFromParcel(Parcel source) {
+            return new RCPauseLiveMessage(source);
+        }
+
+        @Override
+        public RCPauseLiveMessage[] newArray(int size) {
+            return new RCPauseLiveMessage[size];
+        }
+    };
+}

+ 145 - 0
rong_im/live/src/main/java/com/rong/io/live/widget/LiveRoomMicIconView.java

@@ -0,0 +1,145 @@
+package com.rong.io.live.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.cooleshow.usercenter.helper.UserHelper;
+import com.rong.io.live.R;
+
+import java.util.ArrayList;
+
+import androidx.annotation.Nullable;
+import io.rong.imlib.model.UserInfo;
+
+/**
+ * Author by pq, Date on 2022/4/6.
+ */
+public class LiveRoomMicIconView extends LinearLayout {
+    private ArrayList<UserInfo> mMicUserInfos;
+    private String mCurrentUserId;
+    public static final String DEFAULT_NICK = "连麦用户";
+
+    public LiveRoomMicIconView(Context context) {
+        this(context, null);
+    }
+
+    public LiveRoomMicIconView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, -1);
+    }
+
+    public LiveRoomMicIconView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        setOrientation(HORIZONTAL);
+        setGravity(Gravity.CENTER_VERTICAL);
+        mMicUserInfos = new ArrayList<>();
+        mCurrentUserId = UserHelper.getUserId();
+    }
+
+    public void delAllExcludeOwn() {
+        if (mMicUserInfos != null) {
+            int i = checkContain(mCurrentUserId);
+            UserInfo userInfo;
+            if (i != -1) {
+                userInfo = mMicUserInfos.get(i);
+                mMicUserInfos.clear();
+                addMicUser(userInfo);
+            } else {
+                delAll();
+            }
+        }
+    }
+
+    public void delAll() {
+        if (mMicUserInfos != null) {
+            mMicUserInfos.clear();
+            this.removeAllViews();
+        }
+    }
+
+    public void addMicUser(UserInfo userInfo) {
+        int i = checkContain(userInfo.getUserId());
+        if (i != -1) {
+            String oldName = mMicUserInfos.get(i).getName();
+            if (!TextUtils.isEmpty(oldName) && !TextUtils.equals(oldName, DEFAULT_NICK)) {
+                userInfo.setName(mMicUserInfos.get(i).getName());
+            }
+            mMicUserInfos.set(i, userInfo);
+        } else {
+            mMicUserInfos.add(userInfo);
+        }
+        removeAllViews();
+        createMicTag();
+    }
+
+    private void createMicTag() {
+        for (int i = 0; i < mMicUserInfos.size(); i++) {
+            UserInfo userInfo = mMicUserInfos.get(i);
+            View view = LayoutInflater.from(getContext()).inflate(R.layout.item_live_room_mic_user_layout, this, false);
+            ImageView iv_icon = view.findViewById(R.id.iv_icon);
+            TextView tv_name = view.findViewById(R.id.tv_name);
+            String nickName = DEFAULT_NICK;
+            if (!TextUtils.isEmpty(userInfo.getName())) {
+                nickName = userInfo.getName();
+            }
+            userInfo.setName(nickName);
+            tv_name.setText(nickName);
+            if (userInfo != null && TextUtils.equals(userInfo.getUserId(), mCurrentUserId)) {
+                //自己
+                iv_icon.setImageResource(R.drawable.icon_live_room_mic_own);
+                tv_name.setBackgroundResource(R.drawable.shape_live_room_mic_nickname_bg);
+            } else {
+                iv_icon.setImageResource(R.drawable.icon_live_room_mic_other);
+                tv_name.setBackgroundResource(R.drawable.shape_live_room_mic_nickname_bg_normal);
+            }
+            this.addView(view);
+        }
+    }
+
+    public void deleteMicUser(UserInfo userInfo) {
+        int i = checkContain(userInfo.getUserId());
+        if (i != -1) {
+            try {
+                mMicUserInfos.remove(i);
+                this.removeViewAt(i);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+    }
+
+    private int checkContain(String id) {
+        int pos = -1;
+
+        if (mMicUserInfos.size() == 0) {
+            return pos;
+        }
+        for (int i = 0; i < mMicUserInfos.size(); i++) {
+            UserInfo targetUserInfo = mMicUserInfos.get(i);
+            if (TextUtils.equals(id, targetUserInfo.getUserId())) {
+                pos = i;
+                return pos;
+            }
+        }
+        return pos;
+    }
+
+    public UserInfo getUserInfoIfExist(String userId) {
+        int i = checkContain(userId);
+        if (i != -1 && i < mMicUserInfos.size()) {
+            return mMicUserInfos.get(i);
+        }
+        return null;
+    }
+}

BIN
rong_im/live/src/main/res/drawable-xhdpi/icon_live_room_mic_other.png


BIN
rong_im/live/src/main/res/drawable-xhdpi/icon_live_room_mic_own.png


BIN
rong_im/live/src/main/res/drawable-xxhdpi/icon_live_room_mic_other.png


BIN
rong_im/live/src/main/res/drawable-xxhdpi/icon_live_room_mic_own.png


+ 7 - 0
rong_im/live/src/main/res/drawable/shape_gray_14dp_border_white.xml

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

+ 5 - 0
rong_im/live/src/main/res/drawable/shape_live_mic_bg_round.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@color/color_52000000"/>
+</shape>

+ 5 - 0
rong_im/live/src/main/res/drawable/shape_live_room_mic_nickname_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#F37C17"/>
+    <corners android:radius="7dp"/>
+</shape>

+ 5 - 0
rong_im/live/src/main/res/drawable/shape_live_room_mic_nickname_bg_normal.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_52000000"/>
+    <corners android:radius="7dp"/>
+</shape>

+ 23 - 0
rong_im/live/src/main/res/drawable/shape_live_video_progress.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<animated-rotate
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pivotX="50%" android:pivotY="50%"
+    android:fromDegrees="0"
+    android:toDegrees="360">
+
+    <shape
+        android:shape="ring"
+        android:innerRadiusRatio="3"
+        android:thicknessRatio="8"
+        android:useLevel="false">
+        <gradient
+            android:type="sweep"
+            android:useLevel="false"
+            android:startColor="@color/white_translucent"
+            android:centerColor="@color/white_50"
+            android:centerY="0.50"
+            android:endColor="@color/transparent" />
+    </shape>
+
+</animated-rotate>

+ 43 - 0
rong_im/live/src/main/res/layout/item_live_room_mic_user_layout.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="5dp"
+    android:layout_marginEnd="5dp">
+    <View
+        app:layout_constraintRight_toRightOf="@+id/iv_icon"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_icon"
+        app:layout_constraintBottom_toBottomOf="@+id/iv_icon"
+        app:layout_constraintTop_toTopOf="@+id/iv_icon"
+        android:background="@drawable/shape_live_mic_bg_round"
+        android:layout_width="0dp"
+        android:layout_height="0dp"/>
+    <ImageView
+        android:id="@+id/iv_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/icon_live_room_mic_own"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="3dp"
+        android:background="@drawable/shape_live_room_mic_nickname_bg"
+        android:includeFontPadding="false"
+        android:paddingStart="5dp"
+        android:paddingTop="1dp"
+        android:paddingEnd="5dp"
+        android:paddingBottom="1dp"
+        android:textColor="@color/white"
+        android:textSize="@dimen/sp_10"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_icon"
+        app:layout_constraintRight_toRightOf="@+id/iv_icon"
+        app:layout_constraintTop_toBottomOf="@+id/iv_icon"
+        tools:text="张嘉佳" />
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 63 - 0
rong_im/live/src/main/res/layout/view_live_video_status_layout.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/color_1a1a1a"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <ProgressBar
+        android:id="@+id/pb_loading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:indeterminateDrawable="@drawable/shape_live_video_progress"
+        android:max="100" />
+
+    <TextView
+        android:id="@+id/tv_loading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="10dp"
+        android:text="加载中"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12" />
+
+    <TextView
+        android:id="@+id/tv_live_status_tip_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="7dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:text="直播加载失败,您的网络可能不佳"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_center_icon"
+        app:layout_constraintRight_toRightOf="@+id/iv_center_icon"
+        app:layout_constraintTop_toBottomOf="@+id/iv_center_icon" />
+
+    <TextView
+        android:id="@+id/tv_retry"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="7dp"
+        android:background="@drawable/shape_gray_14dp_border_white"
+        android:paddingStart="18dp"
+        android:paddingTop="4dp"
+        android:paddingEnd="18dp"
+        android:paddingBottom="4dp"
+        android:text="重试"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="@+id/iv_center_icon"
+        app:layout_constraintRight_toRightOf="@+id/iv_center_icon"
+        app:layout_constraintTop_toBottomOf="@+id/iv_center_icon"
+        tools:text="重试" />
+</LinearLayout>

+ 13 - 0
student/src/main/AndroidManifest.xml

@@ -3,6 +3,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="com.cooleshow.student">
 
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
     <application
         android:name=".App"
         android:allowBackup="true"
@@ -140,6 +141,18 @@
             android:configChanges="orientation|screenSize|keyboardHidden"
             android:screenOrientation="portrait" />
 
+        <activity
+            android:name=".ui.live.LiveRoomActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:launchMode="singleTask"
+            android:exported="false"
+            android:screenOrientation="portrait"
+            android:windowSoftInputMode="adjustPan">
+            <intent-filter>
+                <action android:name="com.daya.studaya_android.ui.live.LiveRoomActivity" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 
 </manifest>

+ 418 - 0
student/src/main/java/com/cooleshow/student/adapter/MessageAdapter.java

@@ -0,0 +1,418 @@
+package com.cooleshow.student.adapter;
+
+import android.content.Context;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.cooleshow.base.utils.SizeUtils;
+import com.cooleshow.base.utils.UiUtils;
+import com.cooleshow.student.R;
+import com.cooleshow.usercenter.helper.UserHelper;
+import com.rong.io.live.LiveRoomMsgConstants;
+import com.rong.io.live.message.RCChatJoinRoomMessage;
+import com.rong.io.live.message.RCChatModeMessage;
+import com.rong.io.live.message.RCChatroomLocationMessage;
+import com.rong.io.live.message.RCOnSnappingUpMessage;
+import com.rong.io.live.message.RCUserAddLikeMessage;
+import com.rong.io.live.message.RCUserSeatApplyMessage;
+import com.rong.io.live.message.RCUserSeatResponseMessage;
+import com.rong.io.live.message.RCUserSeatsCtrlMessage;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import io.rong.imlib.model.Message;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+import io.rong.message.TextMessage;
+
+/**
+ * Author by pq, Date on 2022/3/31.
+ */
+public class MessageAdapter extends RecyclerView.Adapter {
+    private Context context;
+    private String roomAuthorId = "";
+    private ArrayList<Message> mMessageList;
+    public static final int MESSAGE_TYPE_TEXT = -1;//文本消息
+    public static final int MESSAGE_TYPE_JOIN_ROOM = -2;//加入直播间
+    public static final int MESSAGE_TYPE_LOCAL_MSG = -3;//本地消息
+    public static final int MESSAGE_TYPE_ADD_LIKE_MSG = -4;//点赞消息
+    public static final int MESSAGE_TYPE_SEAT_CTRL_MSG = -5;//连麦控制消息
+    public static final int MESSAGE_TYPE_CHAT_CTRL_MSG = -6;//聊天控制消息
+    public static final int MESSAGE_TYPE_SEAT_APPLY_MSG = -7;//观众连麦申请
+    public static final int MESSAGE_TYPE_SEAT_RESPONSE_MSG = -8;//连麦响应消息
+    public static final int MESSAGE_TYPE_ON_SNAP_UP_MSG = -9;//xxx正在抢购
+    public static final String[] MSG_TAGS = new String[]{LiveRoomMsgConstants.TAG_TXT, LiveRoomMsgConstants.TAG_CHAT_ROOM_ENTER
+            , LiveRoomMsgConstants.TAG_CHAT_ROOM_LOCAL_MSG, LiveRoomMsgConstants.TAG_CHAT_ROOM_ADD_LIKE, LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_CTRL
+            , LiveRoomMsgConstants.TAG_CHAT_ROOM_CHAT_MODE_CTRL, LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_APPLY,
+            LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_RESPONSE, LiveRoomMsgConstants.TAG_LIVE_ON_SNAP_UP};
+    public List<String> msgTags;
+
+    public MessageAdapter(Context context) {
+        this.context = context;
+        mMessageList = new ArrayList();
+        msgTags = Arrays.asList(MSG_TAGS);
+
+    }
+
+    public void addMessage(Message message) {
+        if (message == null) {
+            return;
+        }
+        if (TextUtils.isEmpty(message.getObjectName())) {
+            return;
+        }
+        if (!msgTags.contains(message.getObjectName())) {
+            return;
+        }
+        if (message.getContent() instanceof RCUserSeatResponseMessage) {
+            RCUserSeatResponseMessage responseMessage = (RCUserSeatResponseMessage) message.getContent();
+            if (!TextUtils.equals(responseMessage.getAudienceId(), UserHelper.getUserId())) {
+                return;
+            }
+        }
+        if (message.getContent() instanceof RCUserSeatApplyMessage) {
+            RCUserSeatApplyMessage applyMessage = (RCUserSeatApplyMessage) message.getContent();
+            if (!TextUtils.equals(applyMessage.getAudienceId(), UserHelper.getUserId())) {
+                return;
+            }
+        }
+        mMessageList.add(message);
+        notifyDataSetChanged();
+    }
+
+    public void setRoomAuthorId(String roomAuthorId) {
+        this.roomAuthorId = roomAuthorId;
+    }
+
+    @NonNull
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        switch (viewType) {
+            case MESSAGE_TYPE_TEXT:
+            case MESSAGE_TYPE_LOCAL_MSG:
+                View view = LayoutInflater.from(context).inflate(R.layout.item_live_room_message_text, parent, false);
+                return new TextMessageHolder(view);
+            case MESSAGE_TYPE_ON_SNAP_UP_MSG:
+            case MESSAGE_TYPE_ADD_LIKE_MSG:
+            case MESSAGE_TYPE_JOIN_ROOM:
+                View joinView = LayoutInflater.from(context).inflate(R.layout.item_live_room_join_message_text, parent, false);
+                return new JoinRoomMessageHolder(joinView);
+            case MESSAGE_TYPE_SEAT_APPLY_MSG:
+            case MESSAGE_TYPE_SEAT_RESPONSE_MSG:
+            case MESSAGE_TYPE_CHAT_CTRL_MSG:
+            case MESSAGE_TYPE_SEAT_CTRL_MSG:
+                View modechangeView = LayoutInflater.from(context).inflate(R.layout.item_live_room_message_mode_change, parent, false);
+                return new ModeChangeMessageHolder(modechangeView);
+        }
+        return null;
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+        Message message = mMessageList.get(position);
+        String nickNameShow = "用户" + message != null ? message.getSenderUserId() : "";
+        switch (getItemViewType(position)) {
+            case MESSAGE_TYPE_LOCAL_MSG:
+                TextMessageHolder localMsgHolder = (TextMessageHolder) holder;
+                RCChatroomLocationMessage localMsgContent = (RCChatroomLocationMessage) message.getContent();
+                localMsgHolder.mTvText.setText(localMsgContent.getContent());
+                localMsgHolder.mTvText.setTextColor(context.getResources().getColor(com.cooleshow.base.R.color.color_00d6c9));
+                break;
+            case MESSAGE_TYPE_TEXT:
+                TextMessageHolder textMessageHolder = (TextMessageHolder) holder;
+                TextMessage content = (TextMessage) message.getContent();
+                Log.i("pq", "textMessage:" + content.toString());
+                //昵称
+                String authorName = "用户" + message.getUId();
+                SpannableString spannableString;
+                if (content.getUserInfo() != null) {
+                    UserInfo userInfo = content.getUserInfo();
+                    if (!TextUtils.isEmpty(userInfo.getName())) {
+                        authorName = content.getUserInfo().getName();
+                    }
+                    if (TextUtils.equals(message.getSenderUserId(), roomAuthorId)) {
+                        //房间主讲人
+                        spannableString = getRoomAuthorTextStyleSpan(context.getString(R.string.live_msg_text_nickname, authorName), content.getContent());
+                    } else {
+                        //其他
+                        spannableString = getNormalTextStyleSpan(context.getString(R.string.live_msg_text_nickname, authorName), content.getContent());
+                    }
+                } else {
+                    spannableString = getNormalTextStyleSpan(context.getString(R.string.live_msg_text_nickname, authorName), content.getContent());
+                }
+                textMessageHolder.mTvText.setText(spannableString);
+                break;
+
+            case MESSAGE_TYPE_JOIN_ROOM:
+                JoinRoomMessageHolder joinRoomMessageHolder = (JoinRoomMessageHolder) holder;
+                Message joinMessage = mMessageList.get(position);
+                RCChatJoinRoomMessage content1 = (RCChatJoinRoomMessage) joinMessage.getContent();
+                String name = "用户" + joinMessage.getSenderUserId();
+                if (content1.getUserInfo() != null && !TextUtils.isEmpty(content1.getUserInfo().getName())) {
+                    name = content1.getUserInfo().getName();
+                }
+                joinRoomMessageHolder.mTvText.setText(getNormalTextStyleSpan(name, "进入直播间"));
+                break;
+            case MESSAGE_TYPE_ADD_LIKE_MSG:
+                JoinRoomMessageHolder addLikeMessageHolder = (JoinRoomMessageHolder) holder;
+                Message addLikeMessage = mMessageList.get(position);
+                RCUserAddLikeMessage addLikeContent = (RCUserAddLikeMessage) addLikeMessage.getContent();
+                String nick = "用户" + addLikeMessage.getSenderUserId();
+                if (addLikeContent.getUserInfo() != null && !TextUtils.isEmpty(addLikeContent.getUserInfo().getName())) {
+                    nick = addLikeContent.getUserInfo().getName();
+                }
+                int counts = addLikeContent.getCounts();
+                addLikeMessageHolder.mTvText.setText(getNormalTextStyleSpan(nick, context.getString(R.string.live_room_add_like_count_text_str, counts)));
+                break;
+            case MESSAGE_TYPE_SEAT_CTRL_MSG:
+                //连麦控制
+                ModeChangeMessageHolder seatModeChangeHolder = (ModeChangeMessageHolder) holder;
+                Message modeChangeMsg = mMessageList.get(position);
+                RCUserSeatsCtrlMessage ctrlContent = (RCUserSeatsCtrlMessage) modeChangeMsg.getContent();
+                String nickName = "用户" + modeChangeMsg != null ? modeChangeMsg.getSenderUserId() : "";
+                if (!TextUtils.isEmpty(ctrlContent.getUserName())) {
+                    nickName = ctrlContent.getUserName();
+                }
+                boolean isEnableSeat = ctrlContent.isSeatBan();
+                String afterContent = isEnableSeat ? "关闭连麦" : "开启连麦";
+                seatModeChangeHolder.mIvIcon.setVisibility(View.VISIBLE);
+                seatModeChangeHolder.mTvText.setText(getNormalTextStyleSpan(nickName, afterContent));
+                break;
+            case MESSAGE_TYPE_CHAT_CTRL_MSG:
+                //聊天控制
+                ModeChangeMessageHolder chatModeChangeHolder = (ModeChangeMessageHolder) holder;
+                Message chatModeChangeMsg = mMessageList.get(position);
+                RCChatModeMessage chatModeContent = (RCChatModeMessage) chatModeChangeMsg.getContent();
+                String nickName2 = "用户" + chatModeChangeMsg != null ? chatModeChangeMsg.getSenderUserId() : "";
+                if (!TextUtils.isEmpty(chatModeContent.getUserName())) {
+                    nickName2 = chatModeContent.getUserName();
+                }
+                boolean isEnableChat = chatModeContent.isChatBan();
+                String afterContent2 = isEnableChat ? "关闭聊天" : "开启聊天";
+                chatModeChangeHolder.mIvIcon.setVisibility(View.VISIBLE);
+                chatModeChangeHolder.mTvText.setText(getNormalTextStyleSpan(nickName2, afterContent2));
+                break;
+            case MESSAGE_TYPE_SEAT_APPLY_MSG:
+                ModeChangeMessageHolder seatApplyMsgHolder = (ModeChangeMessageHolder) holder;
+                RCUserSeatApplyMessage content2 = (RCUserSeatApplyMessage) message.getContent();
+                int type = content2.getType();
+                if (type == LiveRoomMsgConstants.MIC_ACTION_SEAT_BY_USER
+                        || type == LiveRoomMsgConstants.MIC_ACTION_CANCEL_SEAT_BY_USER) {
+                    seatApplyMsgHolder.mIvIcon.setVisibility(View.GONE);
+                    seatApplyMsgHolder.mTvText.setPadding(SizeUtils.dp2px(10), 0, SizeUtils.dp2px(10), 0);
+                    if (!TextUtils.isEmpty(content2.getAudienceName())) {
+                        nickNameShow = content2.getAudienceName();
+                    }
+                } else {
+                    seatApplyMsgHolder.mIvIcon.setVisibility(View.VISIBLE);
+                    seatApplyMsgHolder.mTvText.setPadding(SizeUtils.dp2px(5), 0, SizeUtils.dp2px(10), 0);
+                    if (!TextUtils.isEmpty(content2.getTeacherName())) {
+                        nickNameShow = content2.getTeacherName();
+                    }
+                }
+                String contentText = "";
+                if (type == LiveRoomMsgConstants.MIC_ACTION_SEAT_BY_USER) {
+                    //观众发起连麦申请
+                    contentText = "发起了连麦申请";
+                }
+                if (type == LiveRoomMsgConstants.MIC_ACTION_CANCEL_SEAT_BY_USER) {
+                    //观众取消连麦申请
+                    contentText = "取消了连麦申请";
+                }
+
+                if (type == LiveRoomMsgConstants.MIC_ACTION_CANCEL_SEAT_BY_CREATE) {
+                    //主讲人将观众抱下麦
+                    contentText = "将你抱下麦";
+                }
+
+                if (type == LiveRoomMsgConstants.MIC_ACTION_INVITE_SEAT_BY_CREATE) {
+                    //主讲人发起了连麦邀请
+                    contentText = "发起了连麦邀请";
+                }
+                if (type == LiveRoomMsgConstants.MIC_ACTION_CANCEL_INVITE_SEAT_BY_CREATE) {
+                    //主讲人取消了连麦邀请
+                    contentText = "取消了连麦邀请";
+                }
+                seatApplyMsgHolder.mTvText.setText(getNormalTextStyleSpan(nickNameShow, contentText));
+                break;
+            case MESSAGE_TYPE_SEAT_RESPONSE_MSG:
+                ModeChangeMessageHolder seatResponseMsgHolder = (ModeChangeMessageHolder) holder;
+                RCUserSeatResponseMessage responseContent = (RCUserSeatResponseMessage) message.getContent();
+                int responseType = responseContent.getType();
+                if (responseType == LiveRoomMsgConstants.MIC_RESPONSE_AGREE_BY_USER
+                        || responseType == LiveRoomMsgConstants.MIC_RESPONSE_DISAGREE_BY_USER) {
+                    seatResponseMsgHolder.mIvIcon.setVisibility(View.GONE);
+                    seatResponseMsgHolder.mTvText.setPadding(SizeUtils.dp2px(10), 0, SizeUtils.dp2px(10), 0);
+                    if (!TextUtils.isEmpty(responseContent.getAudienceName())) {
+                        nickNameShow = responseContent.getAudienceName();
+                    }
+                } else {
+                    seatResponseMsgHolder.mIvIcon.setVisibility(View.VISIBLE);
+                    seatResponseMsgHolder.mTvText.setPadding(SizeUtils.dp2px(5), 0, SizeUtils.dp2px(10), 0);
+                    if (!TextUtils.isEmpty(responseContent.getTeacherName())) {
+                        nickNameShow = responseContent.getTeacherName();
+                    }
+                }
+                String responseContentText = "";
+                if (responseType == LiveRoomMsgConstants.MIC_RESPONSE_AGREE) {
+                    //主讲人同意观众上麦申请
+                    responseContentText = "同意了连麦申请";
+                }
+                if (responseType == LiveRoomMsgConstants.MIC_RESPONSE_DISAGREE) {
+                    //主讲人不同意观众上麦申请
+                    responseContentText = "取消了连麦申请";
+                }
+                if (responseType == LiveRoomMsgConstants.MIC_RESPONSE_AGREE_BY_USER) {
+                    //观众同意了连麦邀请
+                    responseContentText = "同意了连麦邀请";
+                }
+                if (responseType == LiveRoomMsgConstants.MIC_RESPONSE_DISAGREE_BY_USER) {
+                    //观众取消了连麦邀请
+                    responseContentText = "取消了连麦邀请";
+                }
+                seatResponseMsgHolder.mTvText.setText(getNormalTextStyleSpan(nickNameShow, responseContentText));
+                break;
+            case MESSAGE_TYPE_ON_SNAP_UP_MSG:
+                JoinRoomMessageHolder onSnapUpHolder = (JoinRoomMessageHolder) holder;
+                Message onSnapUpMessage = mMessageList.get(position);
+                RCOnSnappingUpMessage onSnapUpContent = (RCOnSnappingUpMessage) onSnapUpMessage.getContent();
+                String lastName = getNickName(onSnapUpMessage, onSnapUpContent != null ? onSnapUpContent.getUserName() : "");
+                onSnapUpHolder.mTvText.setText(getNormalTextStyleSpan(lastName, " 正在抢购"));
+                break;
+
+        }
+    }
+
+    private void setDefaultInfo(Message message) {
+
+    }
+
+    private String getNickName(Message message, String defaultName) {
+        if (!TextUtils.isEmpty(defaultName)) {
+            return defaultName;
+        }
+        return getNickName(message);
+    }
+
+    private String getNickName(Message message) {
+        //昵称
+        String name = "用户" + message.getSenderUserId();
+        MessageContent content = message.getContent();
+        if (content.getUserInfo() != null && !TextUtils.isEmpty(content.getUserInfo().getName())) {
+            name = content.getUserInfo().getName();
+        }
+        return name;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mMessageList != null ? mMessageList.size() : 0;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        Message message = mMessageList.get(position);
+        String objectName = message.getObjectName();
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_TXT)) {
+            //文本消息
+            return MESSAGE_TYPE_TEXT;
+        }
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_ENTER)) {
+            //进入房间消息
+            return MESSAGE_TYPE_JOIN_ROOM;
+        }
+
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_LOCAL_MSG)) {
+            //本地消息
+            return MESSAGE_TYPE_LOCAL_MSG;
+        }
+
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_ADD_LIKE)) {
+            //点赞消息
+            return MESSAGE_TYPE_ADD_LIKE_MSG;
+        }
+
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_CTRL)) {
+            //连麦控制
+            return MESSAGE_TYPE_SEAT_CTRL_MSG;
+        }
+
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_CHAT_MODE_CTRL)) {
+            //聊天控制
+            return MESSAGE_TYPE_CHAT_CTRL_MSG;
+        }
+
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_APPLY)) {
+            //连麦相关
+            return MESSAGE_TYPE_SEAT_APPLY_MSG;
+        }
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_RESPONSE)) {
+            //连麦响应相关
+            return MESSAGE_TYPE_SEAT_RESPONSE_MSG;
+        }
+
+        if (TextUtils.equals(objectName, LiveRoomMsgConstants.TAG_LIVE_ON_SNAP_UP)) {
+            //正在抢购
+            return MESSAGE_TYPE_ON_SNAP_UP_MSG;
+        }
+        return super.getItemViewType(position);
+    }
+
+
+    private static class TextMessageHolder extends RecyclerView.ViewHolder {
+
+        private final TextView mTvText;
+
+        public TextMessageHolder(@NonNull View itemView) {
+            super(itemView);
+            mTvText = itemView.findViewById(R.id.tv_text);
+        }
+    }
+
+    private static class ModeChangeMessageHolder extends RecyclerView.ViewHolder {
+
+        private final TextView mTvText;
+        private final ImageView mIvIcon;
+
+        public ModeChangeMessageHolder(@NonNull View itemView) {
+            super(itemView);
+            mTvText = itemView.findViewById(R.id.tv_text);
+            mIvIcon = itemView.findViewById(R.id.iv_icon);
+        }
+    }
+
+    private static class JoinRoomMessageHolder extends RecyclerView.ViewHolder {
+
+        private final TextView mTvText;
+
+        public JoinRoomMessageHolder(@NonNull View itemView) {
+            super(itemView);
+            mTvText = itemView.findViewById(R.id.tv_text);
+        }
+    }
+
+    private SpannableString getNormalTextStyleSpan(String startStr, String contentText) {
+        return UiUtils.diffColorString(startStr
+                , contentText
+                , context.getResources().getColor(com.cooleshow.base.R.color.color_00d6c9)
+                , context.getResources().getColor(R.color.white));
+    }
+
+    private SpannableString getRoomAuthorTextStyleSpan(String nickName, String contentText) {
+        return UiUtils.diffColorString(nickName
+                , contentText
+                , context.getResources().getColor(com.cooleshow.base.R.color.color_00d6c9)
+                , context.getResources().getColor(R.color.white)
+                , context.getResources().getDrawable(R.drawable.icon_live_msg_room_author));
+    }
+}

+ 34 - 0
student/src/main/java/com/cooleshow/student/api/APIService.java

@@ -11,11 +11,13 @@ import com.cooleshow.student.bean.AddressBean;
 import com.cooleshow.student.bean.AppHomeBean;
 import com.cooleshow.student.bean.CountOfUnreadBean;
 import com.cooleshow.student.bean.CourseTableDataBean;
+import com.cooleshow.student.bean.FriendInfoBean;
 import com.cooleshow.student.bean.HomeLiveAndVideoBean;
 import com.cooleshow.student.bean.HomeStyleBean;
 import com.cooleshow.student.bean.HomeworkListBean;
 import com.cooleshow.student.bean.HotAlbumBean;
 import com.cooleshow.student.bean.LiveCourseListBean;
+import com.cooleshow.student.bean.LiveRoomInfoBean;
 import com.cooleshow.student.bean.PayTestBean;
 import com.cooleshow.student.bean.PracticeCourseListBean;
 import com.cooleshow.student.bean.QuerySubjectBean;
@@ -361,4 +363,36 @@ public interface APIService {
      */
     @GET(STUDENT_GROUP + "student/setSubject")
     Observable<BaseResponse<Object>> setSubject(@Query("subjectIds") String subjectIds);
+
+    /**
+     * 查询直播房间信息
+     *
+     * @return
+     */
+    @GET("api-web/imLiveBroadcastRoom/queryRoom")
+    Observable<BaseResponse<LiveRoomInfoBean>> getLiveRoomInfo(@Query("roomUid") String roomUid);
+
+    /**
+     * 通知加入直播房间成功
+     *
+     * @return
+     */
+    @GET("api-web/imLiveBroadcastRoom/joinRoom")
+    Observable<BaseResponse<Object>> notifyJoinRoomAction(@Query("roomUid") String roomUid, @Query("userId") String userId);
+
+    /**
+     * 通知离开直播房间
+     *
+     * @return
+     */
+    @POST("api-im/user/statusImUser")
+    Observable<BaseResponse<Object>> notifyLeaveRoomAction(@Body RequestBody body);
+
+    /**
+     * 查询friend信息
+     *
+     * @return
+     */
+    @GET("api-student/imGroup/queryFriendDetail")
+    Observable<BaseResponse<FriendInfoBean>> queryFriendDetail(@Query("userId") String userId);
 }

+ 133 - 0
student/src/main/java/com/cooleshow/student/bean/FriendInfoBean.java

@@ -0,0 +1,133 @@
+package com.cooleshow.student.bean;
+
+/**
+ * Author by pq, Date on 2022/4/11.
+ */
+public class FriendInfoBean {
+
+    /**
+     * friend : {"roles":null,"username":"嗷嗷","password":"$2a$10$Ex7buphWImsizz8iVpZVwu9znDsRGUadunLNfiyxURdJtg3gY1uNK","gender":1,"certificateType":"","delFlag":0,"organId":1007,"salt":"","organName":"","userType":"STUDENT","phone":"18341111119","avatar":"","currentClass":"2班","currentGrade":"","birthdate":null,"idCardNo":"","imToken":"lCvSFgo4OaH5OzMX/k6QoO1hdlQbTOD5RxAXMAscMjM=@n56a.cn.rongnav.com;n56a.cn.rongcfg.com","createTime":"2022-02-25 16:46:49","email":"","teacherId":0,"isSuperAdmin":false,"lockFlag":0,"deptId":0,"deptIds":"","postDeptIds":"","updateTime":"2022-03-08 11:05:19","organIdList":"","currentGradeNum":2,"operatingTag":0,"serviceTag":0,"postalCode":"","postIds":"","bankCard":"","openBankAddress":"","positionName":"","positions":"","superAdmin":false,"wxOpenid":"","qqOpenid":"","nation":"","wechatId":"","contactAddress":"","id":2163097,"realName":"","tenantId":1}
+     * tags :
+     * userId : 0
+     * memberRankSettingId : 0
+     * createTime : null
+     * memo :
+     * subjectId :
+     * friendId : 2163097
+     * updateTime : null
+     * subjectName :
+     * friendNickname : 嗷嗷
+     * id : 0
+     * tenantId : 1
+     */
+
+    public FriendBean friend;
+    public String tags;
+    public int userId;
+    public int memberRankSettingId;
+    public Object createTime;
+    public String memo;
+    public String subjectId;
+    public String friendId;
+    public Object updateTime;
+    public String subjectName;
+    public String friendNickname;
+    public int id;
+    public int tenantId;
+
+    public static class FriendBean {
+        /**
+         * roles : null
+         * username : 嗷嗷
+         * password : $2a$10$Ex7buphWImsizz8iVpZVwu9znDsRGUadunLNfiyxURdJtg3gY1uNK
+         * gender : 1
+         * certificateType :
+         * delFlag : 0
+         * organId : 1007
+         * salt :
+         * organName :
+         * userType : STUDENT
+         * phone : 18341111119
+         * avatar :
+         * currentClass : 2班
+         * currentGrade :
+         * birthdate : null
+         * idCardNo :
+         * imToken : lCvSFgo4OaH5OzMX/k6QoO1hdlQbTOD5RxAXMAscMjM=@n56a.cn.rongnav.com;n56a.cn.rongcfg.com
+         * createTime : 2022-02-25 16:46:49
+         * email :
+         * teacherId : 0
+         * isSuperAdmin : false
+         * lockFlag : 0
+         * deptId : 0
+         * deptIds :
+         * postDeptIds :
+         * updateTime : 2022-03-08 11:05:19
+         * organIdList :
+         * currentGradeNum : 2
+         * operatingTag : 0
+         * serviceTag : 0
+         * postalCode :
+         * postIds :
+         * bankCard :
+         * openBankAddress :
+         * positionName :
+         * positions :
+         * superAdmin : false
+         * wxOpenid :
+         * qqOpenid :
+         * nation :
+         * wechatId :
+         * contactAddress :
+         * id : 2163097
+         * realName :
+         * tenantId : 1
+         */
+
+        public Object roles;
+        public String username;
+        public String password;
+        public int gender;
+        public String certificateType;
+        public int delFlag;
+        public int organId;
+        public String salt;
+        public String organName;
+        public String userType;
+        public String phone;
+        public String avatar;
+        public String currentClass;
+        public String currentGrade;
+        public Object birthdate;
+        public String idCardNo;
+        public String imToken;
+        public String createTime;
+        public String email;
+        public int teacherId;
+        public boolean isSuperAdmin;
+        public int lockFlag;
+        public int deptId;
+        public String deptIds;
+        public String postDeptIds;
+        public String updateTime;
+        public String organIdList;
+        public int currentGradeNum;
+        public int operatingTag;
+        public int serviceTag;
+        public String postalCode;
+        public String postIds;
+        public String bankCard;
+        public String openBankAddress;
+        public String positionName;
+        public String positions;
+        public boolean superAdmin;
+        public String wxOpenid;
+        public String qqOpenid;
+        public String nation;
+        public String wechatId;
+        public String contactAddress;
+        public int id;
+        public String realName;
+        public int tenantId;
+    }
+}

+ 71 - 0
student/src/main/java/com/cooleshow/student/bean/ImUserState.java

@@ -0,0 +1,71 @@
+package com.cooleshow.student.bean;
+
+import java.io.Serializable;
+
+/**
+ * @author hgw
+ * Created by 2022-02-18
+ */
+public class ImUserState implements Serializable {
+    public static final String ACTION_LEAVE_LIVE_ROOM = "3";
+    /**
+     * 用户 Id
+     */
+    private String userid;
+    /**
+     * 状态:0:online 上线、1:offline 离线、2:logout 登出  3:退出直播间
+     */
+    private String status;
+    /**
+     * 操作系统:iOS、Android、Websocket、PC、MiniProgram(小程序),用户上线时同步
+     */
+    private String os;
+    /**
+     * 发生时间
+     */
+    private Long time;
+    /**
+     * 用户当前的 IP 地址及端口
+     */
+    private String clientIp;
+
+    public String getUserid() {
+        return userid;
+    }
+
+    public void setUserid(String userid) {
+        this.userid = userid;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getOs() {
+        return os;
+    }
+
+    public void setOs(String os) {
+        this.os = os;
+    }
+
+    public Long getTime() {
+        return time;
+    }
+
+    public void setTime(Long time) {
+        this.time = time;
+    }
+
+    public String getClientIp() {
+        return clientIp;
+    }
+
+    public void setClientIp(String clientIp) {
+        this.clientIp = clientIp;
+    }
+}

+ 157 - 0
student/src/main/java/com/cooleshow/student/bean/LiveRoomInfoBean.java

@@ -0,0 +1,157 @@
+package com.cooleshow.student.bean;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Author by pq, Date on 2022/3/29.
+ */
+public class LiveRoomInfoBean implements Parcelable {
+
+    /**
+     * createdByName :
+     * id : 0
+     * imToken :
+     * likeNum : 0
+     * liveRemark :
+     * liveStartTime :
+     * liveState : 0
+     * lookNum : 0
+     * os :
+     * preTemplate :
+     * roomConfig :
+     * roomState : 0
+     * roomTitle :
+     * roomUid :
+     * speakerId : 0
+     * speakerName :
+     * speakerPic :
+     * tenantId : 0
+     * tenantLogo :
+     * tenantName :
+     * totalLookNum : 0
+     */
+
+    public String createdByName;
+    public int id;
+    public String imToken;
+    public int likeNum;
+    public String liveRemark;
+    public String liveStartTime;
+    public int liveState;
+    public int lookNum;
+    public String os;
+    public String preTemplate;
+    public String roomConfig;
+    public int roomState;
+    public String roomTitle;
+    public String roomUid;
+    public String speakerId;
+    public String speakerName;
+    public String speakerPic;
+    public int tenantId;
+    public String tenantLogo;
+    public String tenantName;
+    public int totalLookNum;
+    public int blacklistFlag;//当前登录人是否是黑名单用户 0否 1是
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.createdByName);
+        dest.writeInt(this.id);
+        dest.writeString(this.imToken);
+        dest.writeInt(this.likeNum);
+        dest.writeString(this.liveRemark);
+        dest.writeString(this.liveStartTime);
+        dest.writeInt(this.liveState);
+        dest.writeInt(this.lookNum);
+        dest.writeString(this.os);
+        dest.writeString(this.preTemplate);
+        dest.writeString(this.roomConfig);
+        dest.writeInt(this.roomState);
+        dest.writeString(this.roomTitle);
+        dest.writeString(this.roomUid);
+        dest.writeString(this.speakerId);
+        dest.writeString(this.speakerName);
+        dest.writeString(this.speakerPic);
+        dest.writeInt(this.tenantId);
+        dest.writeString(this.tenantLogo);
+        dest.writeString(this.tenantName);
+        dest.writeInt(this.totalLookNum);
+        dest.writeInt(this.blacklistFlag);
+    }
+
+    public void readFromParcel(Parcel source) {
+        this.createdByName = source.readString();
+        this.id = source.readInt();
+        this.imToken = source.readString();
+        this.likeNum = source.readInt();
+        this.liveRemark = source.readString();
+        this.liveStartTime = source.readString();
+        this.liveState = source.readInt();
+        this.lookNum = source.readInt();
+        this.os = source.readString();
+        this.preTemplate = source.readString();
+        this.roomConfig = source.readString();
+        this.roomState = source.readInt();
+        this.roomTitle = source.readString();
+        this.roomUid = source.readString();
+        this.speakerId = source.readString();
+        this.speakerName = source.readString();
+        this.speakerPic = source.readString();
+        this.tenantId = source.readInt();
+        this.tenantLogo = source.readString();
+        this.tenantName = source.readString();
+        this.totalLookNum = source.readInt();
+        this.blacklistFlag = source.readInt();
+    }
+
+    public LiveRoomInfoBean() {
+    }
+
+    protected LiveRoomInfoBean(Parcel in) {
+        this.createdByName = in.readString();
+        this.id = in.readInt();
+        this.imToken = in.readString();
+        this.likeNum = in.readInt();
+        this.liveRemark = in.readString();
+        this.liveStartTime = in.readString();
+        this.liveState = in.readInt();
+        this.lookNum = in.readInt();
+        this.os = in.readString();
+        this.preTemplate = in.readString();
+        this.roomConfig = in.readString();
+        this.roomState = in.readInt();
+        this.roomTitle = in.readString();
+        this.roomUid = in.readString();
+        this.speakerId = in.readString();
+        this.speakerName = in.readString();
+        this.speakerPic = in.readString();
+        this.tenantId = in.readInt();
+        this.tenantLogo = in.readString();
+        this.tenantName = in.readString();
+        this.totalLookNum = in.readInt();
+        this.blacklistFlag = in.readInt();
+    }
+
+    public static final Creator<LiveRoomInfoBean> CREATOR = new Creator<LiveRoomInfoBean>() {
+        @Override
+        public LiveRoomInfoBean createFromParcel(Parcel source) {
+            return new LiveRoomInfoBean(source);
+        }
+
+        @Override
+        public LiveRoomInfoBean[] newArray(int size) {
+            return new LiveRoomInfoBean[size];
+        }
+    };
+
+    public String getRoomId(){
+        return roomUid;
+    }
+}

+ 171 - 0
student/src/main/java/com/cooleshow/student/contract/LiveRoomContract.java

@@ -0,0 +1,171 @@
+package com.cooleshow.student.contract;
+
+import android.view.View;
+
+import com.cooleshow.base.presenter.view.BaseView;
+import com.cooleshow.student.bean.FriendInfoBean;
+import com.cooleshow.student.bean.LiveRoomInfoBean;
+import com.rong.io.live.message.RCUserKickOutMessage;
+import com.rong.io.live.message.RCUserLogOutUnusualMessage;
+import com.rong.io.live.message.RCUserSeatApplyMessage;
+import com.rong.io.live.message.RCUserSeatResponseMessage;
+import com.rong.io.live.message.RCUserSyncAddLikeCountMessage;
+
+import java.util.List;
+
+import cn.rongcloud.rtc.api.RCRTCRemoteUser;
+import cn.rongcloud.rtc.api.stream.RCRTCInputStream;
+import cn.rongcloud.rtc.base.RCRTCLiveRole;
+import io.rong.imlib.model.Message;
+import io.rong.imlib.model.MessageContent;
+
+/**
+ * Author by pq, Date on 2022/3/29.
+ */
+public interface LiveRoomContract {
+    interface view extends BaseView {
+        void getRoomInfoSuccess(LiveRoomInfoBean roomInfoBean);
+
+        void getRoomInfoError(Throwable t);
+
+        void showFinishView();
+
+        void syncAudioStatus(boolean isCloseAudioStream);
+
+        //显示休息一下再回来状态图
+        void showRestView();
+
+        //显示主播关闭的视频状态图
+        void showCloseVideoView();
+
+        void showEmptyStatusView();
+
+        View getContentView();
+
+        /**
+         * 添加多条公屏消息
+         */
+        void addMessageList(List<MessageContent> messageContents, boolean isReset);
+
+        /**
+         * 添加单条公屏消息
+         */
+        void addMessageContent(Message message, boolean isReset);
+
+
+        /**
+         * 聊天模式控制消息
+         *
+         * @param isEnableChat
+         */
+        void switchChatMode(boolean isEnableChat);
+
+        /**
+         * 关闭直播间
+         */
+        void liveRoomOffline();
+
+        /**
+         * 直播间商品
+         *
+         * @param goodsStr
+         */
+        void liveGoodsChange(String goodsStr);
+
+        /**
+         * 连麦回复
+         *
+         * @param rcUserSeatResponseMessage
+         */
+        void seatResponse(RCUserSeatResponseMessage rcUserSeatResponseMessage);
+
+
+        void onSwitchRole(String id, RCRTCLiveRole role);
+
+        void onUserJoinRoom(RCRTCRemoteUser rcrtcRemoteUser);
+
+        /**
+         * 观众下麦(身份从主播切换到观众)
+         */
+        void onUserLeftRoomMic(RCRTCRemoteUser rcrtcRemoteUser);
+
+        /**
+         * 观众下麦(身份从主播切换到观众)
+         */
+        void onUserOfflineRoomMic(RCRTCRemoteUser rcrtcRemoteUser);
+
+        /**
+         * 同步成员数量
+         *
+         * @param count
+         */
+        void syncMemberCount(String count);
+
+        /**
+         * 用户被踢出房间消息
+         *
+         * @param userKickOutMessage
+         */
+        void onUserKickOutMsg(RCUserKickOutMessage userKickOutMessage);
+
+        //连麦模式控制消息
+        void changeMicControlMode(boolean isEnableMic);
+
+        /**
+         * 拿到RCRTCRoom用于显示直播view
+         */
+        void subscribeAVStreamSuccess(List<RCRTCInputStream> inputStreams);
+
+        void onSubscribeFailed();
+
+        /**
+         * 设置房间数据
+         */
+        void setRoomData(LiveRoomInfoBean roomInfoBean);
+
+        //连麦成功(身份切换成功)
+        void onSeatMicSuccess();
+
+        //连麦失败
+        void onSeatMicFail();
+
+        //取消连麦成功(身份切换观众成功)
+        void onExitSeatMicSuccess();
+
+        //邀请上麦
+        void onInviteSeatMic(RCUserSeatApplyMessage seatApplyMessage);
+
+        //用户异常退出消息
+        void onUserUnusualLogout(RCUserLogOutUnusualMessage loginOutUnusualMessage);
+
+        /**
+         * 暂停直播
+         */
+        void onLivePause();
+
+        void onAddLikeMessage(Message message, RCUserSyncAddLikeCountMessage addLikeMessage);
+
+        void getFriendInfoSuccess(FriendInfoBean friendInfoBean);
+
+        void onPublishSuccess();
+
+        /**
+         * 黑名单用户状态切换
+         * @param userId
+         * @param isAddBlack
+         */
+        void changeBlackUserStatus(String userId,boolean isAddBlack);
+    }
+
+    interface Presenter {
+        void getRoomInfo(String roomId);
+
+        void notifyJoinRoomAction(String roomId, String userId);
+
+        void notifyLeaveRoomAction();
+
+        void handleAction(int action);
+
+        void getUserInfoByUserId(String friendUserId);
+    }
+}

+ 970 - 0
student/src/main/java/com/cooleshow/student/presenter/live/LiveRoomPresenter.java

@@ -0,0 +1,970 @@
+package com.cooleshow.student.presenter.live;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.cooleshow.base.data.net.BaseResponse;
+import com.cooleshow.base.presenter.BasePresenter;
+import com.cooleshow.base.rx.BaseObserver;
+import com.cooleshow.base.utils.RequestBodyUtil;
+import com.cooleshow.student.api.APIService;
+import com.cooleshow.student.bean.FriendInfoBean;
+import com.cooleshow.student.bean.ImUserState;
+import com.cooleshow.student.bean.LiveRoomInfoBean;
+import com.cooleshow.student.contract.LiveRoomContract;
+import com.cooleshow.student.utils.helper.LiveRTCEngineInitHelper;
+import com.cooleshow.usercenter.helper.UserHelper;
+import com.google.gson.Gson;
+import com.rong.io.live.LiveRoomMsgConstants;
+import com.rong.io.live.callback.ClickCallback;
+import com.rong.io.live.callback.IRoomCallBack;
+import com.rong.io.live.helper.LiveEventHelper;
+import com.rong.io.live.manager.RCChatRoomMessageManager;
+import com.rong.io.live.message.RCChatJoinRoomMessage;
+import com.rong.io.live.message.RCChatModeMessage;
+import com.rong.io.live.message.RCChatRoomCloseMessage;
+import com.rong.io.live.message.RCChatRoomMemberNumMessage;
+import com.rong.io.live.message.RCChatroomLocationMessage;
+import com.rong.io.live.message.RCLiveBlackUserBlockMessage;
+import com.rong.io.live.message.RCLiveBlackUserUnBlockMessage;
+import com.rong.io.live.message.RCLiveGoodsChangeMessage;
+import com.rong.io.live.message.RCOnSnappingUpMessage;
+import com.rong.io.live.message.RCUserAddLikeMessage;
+import com.rong.io.live.message.RCUserKickOutMessage;
+import com.rong.io.live.message.RCUserLeaveRoomMessage;
+import com.rong.io.live.message.RCUserLogOutUnusualMessage;
+import com.rong.io.live.message.RCUserMicLeaveMessage;
+import com.rong.io.live.message.RCUserSeatApplyMessage;
+import com.rong.io.live.message.RCUserSeatResponseMessage;
+import com.rong.io.live.message.RCUserSeatsCtrlMessage;
+import com.rong.io.live.message.RCUserSyncAddLikeCountMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cn.rongcloud.rtc.api.RCRTCEngine;
+import cn.rongcloud.rtc.api.RCRTCRemoteUser;
+import cn.rongcloud.rtc.api.RCRTCRoom;
+import cn.rongcloud.rtc.api.callback.IRCRTCResultCallback;
+import cn.rongcloud.rtc.api.callback.IRCRTCResultDataCallback;
+import cn.rongcloud.rtc.api.callback.IRCRTCRoomEventsListener;
+import cn.rongcloud.rtc.api.callback.IRCRTCSwitchRoleCallback;
+import cn.rongcloud.rtc.api.callback.IRCRTCSwitchRoleDataCallback;
+import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCLiveInfo;
+import cn.rongcloud.rtc.api.stream.RCRTCOutputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoOutputStream;
+import cn.rongcloud.rtc.base.RCRTCLiveRole;
+import cn.rongcloud.rtc.base.RCRTCMediaType;
+import cn.rongcloud.rtc.base.RTCErrorCode;
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.functions.Consumer;
+import io.reactivex.rxjava3.observers.DisposableObserver;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+import io.rong.imkit.IMCenter;
+import io.rong.imlib.IRongCoreCallback;
+import io.rong.imlib.RongIMClient;
+import io.rong.imlib.model.Message;
+import io.rong.imlib.model.MessageContent;
+import okhttp3.RequestBody;
+
+/**
+ * Author by pq, Date on 2022/3/29.
+ */
+public class LiveRoomPresenter extends BasePresenter<LiveRoomContract.view> implements LiveRoomContract.Presenter {
+    private boolean isInRoom;//是否已经在房间
+    private LiveRoomInfoBean currentRoomInfo;
+    private int addLikeCount = 0;
+    private List<String> shields = new ArrayList<>();//当前屏蔽词
+    private List<Disposable> disposablesManager = new ArrayList<>();//监听管理器
+    private final IRCRTCRoomEventsListener mRoomEventsListener = new IRCRTCRoomEventsListener() {
+        @Override
+        public void onRemoteUserPublishResource(RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {
+            Log.i("pq", "onRemoteUserPublishResource");
+            subscribeAVStream();
+        }
+
+        @Override
+        public void onRemoteUserMuteAudio(RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean b) {
+            Log.i("pq", "onRemoteUserMuteAudio:" + b);
+            if (getView() != null) {
+                getView().syncAudioStatus(b);
+            }
+        }
+
+        @Override
+        public void onRemoteUserMuteVideo(RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean b) {
+        }
+
+        @Override
+        public void onRemoteUserUnpublishResource(RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {
+            Log.i("pq", "onRemoteUserUnpublishResource");
+            if (getView() != null) {
+                getView().showCloseVideoView();
+            }
+        }
+
+        @Override
+        public void onUserJoined(RCRTCRemoteUser rcrtcRemoteUser) {
+            //当房间中用户使用RCRTCLocalUser#switchToBroadcaster 方法上麦成功时
+            // ,房间中观众会收到IRCRTCRoomEventsListener#onUserJoined 回调。
+            if (null != getView()) {
+                getView().onUserJoinRoom(rcrtcRemoteUser);
+            }
+        }
+
+        @Override
+        public void onSwitchRole(String userId, RCRTCLiveRole role) {
+            super.onSwitchRole(userId, role);
+            //当房间内的用户使用 RCRTCLocalUser#switchToBroadcaster 或 RCRTCLocalUser#switchToAudience 方法上下麦时
+            // ,同房间内的其他主播会收到 IRCRTCRoomEventsListener#onSwitchRole 回调。
+            if (getView() != null) {
+                getView().onSwitchRole(userId, role);
+            }
+        }
+
+        @Override
+        public void onUserLeft(RCRTCRemoteUser rcrtcRemoteUser) {
+            if (getView() != null) {
+                getView().onUserLeftRoomMic(rcrtcRemoteUser);
+            }
+        }
+
+        @Override
+        public void onUserOffline(RCRTCRemoteUser rcrtcRemoteUser) {
+            if (getView() != null) {
+                getView().onUserOfflineRoomMic(rcrtcRemoteUser);
+            }
+        }
+
+        @Override
+        public void onPublishLiveStreams(List<RCRTCInputStream> list) {
+            Log.i("pq", "onPublishLiveStreams");
+        }
+
+        @Override
+        public void onUnpublishLiveStreams(List<RCRTCInputStream> list) {
+            Log.i("pq", "onUnpublishLiveStreams");
+            if (getView() != null) {
+                getView().showRestView();
+            }
+        }
+
+
+        /**
+         * 自己退出房间。 例如断网退出等
+         * @param i 状态码
+         */
+        @Override
+        public void onLeaveRoom(int i) {
+            Log.i("pq", "onLeaveRoom:" + i);
+        }
+    };
+
+    public void init(String roomId, boolean isCreate) {
+//        LiveEventHelper.getInstance().addLiveRoomListeners(this);
+        isInRoom = TextUtils.equals(LiveEventHelper.getInstance().getRoomId(), roomId);
+        RongIMClient.ConnectionStatusListener.ConnectionStatus currentConnectionStatus = RongIMClient.getInstance().getCurrentConnectionStatus();
+        if (currentConnectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED) {
+            Log.i("pq", "LiveRoomActivity init getRoomInfo");
+            getRoomInfo(roomId);
+        } else {
+            String imtoken = UserHelper.getUserIMToken();
+            Log.i("pq", "im未连接,token:" + imtoken);
+            if (!TextUtils.isEmpty(imtoken)) {
+                return;
+            }
+            IMCenter.getInstance().connect(imtoken, new RongIMClient.ConnectCallback() {
+                @Override
+                public void onSuccess(String t) {
+                    Log.i("pq", "连接成功");
+                }
+
+                @Override
+                public void onError(RongIMClient.ConnectionErrorCode e) {
+                    Log.i("pq", "connect error" + e);
+                }
+
+                @Override
+                public void onDatabaseOpened(RongIMClient.DatabaseOpenStatus code) {
+
+                }
+            });
+        }
+
+    }
+
+    public void setAddLikeCount(int addLikeCount) {
+        this.addLikeCount = addLikeCount;
+    }
+
+
+    /**
+     * 获取房间信息
+     *
+     * @param roomId
+     */
+    @Override
+    public void getRoomInfo(String roomId) {
+        addSubscribe(create(APIService.class).getLiveRoomInfo(roomId), new BaseObserver<LiveRoomInfoBean>(getView()) {
+            @Override
+            protected void onSuccess(LiveRoomInfoBean data) {
+                Log.i("pq", "getRoomInfo success" + data);
+                currentRoomInfo = data;
+                setObMessageListener(data.roomUid);
+                if (getView() != null) {
+                    getView().getRoomInfoSuccess(data);
+                }
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                super.onError(e);
+                e.printStackTrace();
+                if (getView() != null) {
+                    getView().getRoomInfoError(e);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void notifyJoinRoomAction(String roomId, String userId) {
+        //主进程调用,因为BaseObserver onStart show了loading控件,防止在子线程创建
+        addSubscribe(create(APIService.class).notifyJoinRoomAction(roomId, userId), new DisposableObserver() {
+            @Override
+            public void onNext(Object o) {
+                //通知服务端加入成功即可,无须关注结果
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                e.printStackTrace();
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+        });
+    }
+
+    @Override
+    public void notifyLeaveRoomAction() {
+        handleAction(LiveRoomMsgConstants.ACTION_SEND_LEAVE_ROOM);
+        ImUserState imUserState = new ImUserState();
+        imUserState.setStatus(ImUserState.ACTION_LEAVE_LIVE_ROOM);
+        imUserState.setUserid(UserHelper.getUserId());
+        ArrayList<ImUserState> imUserStates = new ArrayList();
+        imUserStates.add(imUserState);
+        RequestBody body = RequestBodyUtil.convertToRequestBodyJson(new Gson().toJson(imUserStates));
+        create(APIService.class).notifyLeaveRoomAction(body)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Observer<BaseResponse<Object>>() {
+                    @Override
+                    public void onSubscribe(Disposable d) {
+
+                    }
+
+                    @Override
+                    public void onNext(BaseResponse<Object> objectBaseResponse) {
+                        //通知服务端离开即可,无须关注结果
+                    }
+
+                    @Override
+                    public void onError(Throwable e) {
+
+                    }
+
+                    @Override
+                    public void onComplete() {
+                        //通知服务端离开即可,无须关注结果
+                    }
+                });
+    }
+
+    @Override
+    public void getUserInfoByUserId(String userId) {
+        addSubscribe(create(APIService.class).queryFriendDetail(userId), new DisposableObserver<BaseResponse<FriendInfoBean>>() {
+            @Override
+            public void onNext(BaseResponse<FriendInfoBean> friendInfoBeanBaseResponse) {
+                if (getView() != null && friendInfoBeanBaseResponse != null) {
+                    getView().getFriendInfoSuccess(friendInfoBeanBaseResponse.getData());
+                }
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                e.printStackTrace();
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+        });
+    }
+
+    /**
+     * 处理直播间的行为
+     *
+     * @param action
+     */
+    @Override
+    public void handleAction(int action) {
+        switch (action) {
+            case LiveRoomMsgConstants.ACTION_SEND_JOIN_ROOM:
+                //发送加入房间成功消息
+                RCChatJoinRoomMessage rcChatJoinRoomMessage = new RCChatJoinRoomMessage();
+                sendMessage(rcChatJoinRoomMessage, true);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_ADD_LIKE_COUNT:
+                //发送点赞数量
+                RCUserAddLikeMessage addLikeMessage = new RCUserAddLikeMessage();
+                addLikeMessage.setCounts(addLikeCount);
+                sendMessage(addLikeMessage, false);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_LEAVE_ROOM:
+                //退出直播间消息
+                RCUserLeaveRoomMessage rcUserLeaveRoomMessage = new RCUserLeaveRoomMessage();
+                rcUserLeaveRoomMessage.setUserId(UserHelper.getUserId());
+                rcUserLeaveRoomMessage.setUserName(UserHelper.getUserName());
+                sendMessage(rcUserLeaveRoomMessage, false);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_SEAT_APPLY:
+                //申请连麦
+                RCUserSeatApplyMessage rcUserSeatApplyMessage = new RCUserSeatApplyMessage();
+                rcUserSeatApplyMessage.setType(LiveRoomMsgConstants.MIC_ACTION_SEAT_BY_USER);
+                if (currentRoomInfo != null) {
+                    rcUserSeatApplyMessage.setTeacherId(currentRoomInfo.speakerId);
+                    rcUserSeatApplyMessage.setTeacherName(currentRoomInfo.speakerName);
+                }
+                rcUserSeatApplyMessage.setAudienceId(UserHelper.getUserId());
+                rcUserSeatApplyMessage.setAudienceName(UserHelper.getUserName());
+                sendMessage(rcUserSeatApplyMessage, true);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_CANCEL_SEAT_APPLY:
+                //取消连麦申请
+                RCUserSeatApplyMessage cancelApplyMessage = new RCUserSeatApplyMessage();
+                cancelApplyMessage.setType(LiveRoomMsgConstants.MIC_ACTION_CANCEL_SEAT_BY_USER);
+                if (currentRoomInfo != null) {
+                    cancelApplyMessage.setTeacherId(currentRoomInfo.speakerId);
+                    cancelApplyMessage.setTeacherName(currentRoomInfo.speakerName);
+                }
+                cancelApplyMessage.setAudienceId(UserHelper.getUserId());
+                cancelApplyMessage.setAudienceName(UserHelper.getUserName());
+                sendMessage(cancelApplyMessage, true);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_DOWN_SEAT_MIC:
+                //观众下麦消息
+                RCUserMicLeaveMessage rcUserMicLeaveMessage = new RCUserMicLeaveMessage();
+                rcUserMicLeaveMessage.setAudienceId(UserHelper.getUserId());
+                rcUserMicLeaveMessage.setAudienceName(UserHelper.getUserName());
+                sendMessage(rcUserMicLeaveMessage, false);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_CANCEL_SEAT_AGREE_RESPONSE:
+                //被邀请上麦->观众同意上麦
+                RCUserSeatResponseMessage rcUserSeatResponseMessage = new RCUserSeatResponseMessage();
+                rcUserSeatResponseMessage.setType(LiveRoomMsgConstants.MIC_RESPONSE_AGREE_BY_USER);
+                if (currentRoomInfo != null) {
+                    rcUserSeatResponseMessage.setTeacherId(currentRoomInfo.speakerId);
+                    rcUserSeatResponseMessage.setTeacherName(currentRoomInfo.speakerName);
+                }
+                rcUserSeatResponseMessage.setAudienceId(UserHelper.getUserId());
+                rcUserSeatResponseMessage.setAudienceName(UserHelper.getUserName());
+                sendMessage(rcUserSeatResponseMessage, true);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_CANCEL_SEAT_DISAGREE_RESPONSE:
+                //被邀请上麦->观众不同意上麦
+                RCUserSeatResponseMessage disAgreeSeatResponseMessage = new RCUserSeatResponseMessage();
+                disAgreeSeatResponseMessage.setType(LiveRoomMsgConstants.MIC_RESPONSE_DISAGREE_BY_USER);
+                if (currentRoomInfo != null) {
+                    disAgreeSeatResponseMessage.setTeacherId(currentRoomInfo.speakerId);
+                    disAgreeSeatResponseMessage.setTeacherName(currentRoomInfo.speakerName);
+                }
+                disAgreeSeatResponseMessage.setAudienceId(UserHelper.getUserId());
+                disAgreeSeatResponseMessage.setAudienceName(UserHelper.getUserName());
+                sendMessage(disAgreeSeatResponseMessage, true);
+                break;
+            case LiveRoomMsgConstants.ACTION_SEND_ON_SNAP_UP:
+                //发送正在抢购消息
+                RCOnSnappingUpMessage rcOnSnappingUpMessage = new RCOnSnappingUpMessage();
+                rcOnSnappingUpMessage.setUserId(UserHelper.getUserId());
+                rcOnSnappingUpMessage.setUserName(UserHelper.getUserName());
+                sendMessage(rcOnSnappingUpMessage, true);
+                break;
+        }
+    }
+
+    public void joinChartRoom(String chatroomId, final IRongCoreCallback.OperationCallback callback) {
+        LiveEventHelper.getInstance().joinChatRoom(chatroomId, callback);
+    }
+
+    /**
+     * 先退出上次房间,再加入房间
+     *
+     * @param roomId
+     * @param isCreate
+     * @param isExit
+     */
+    public void leaveRoom(String roomId, boolean isCreate, boolean isExit) {
+        LiveEventHelper.getInstance().leaveRoom(new IRoomCallBack() {
+            @Override
+            public void onSuccess() {
+                if (isExit) {
+                    getView().getContentView().postDelayed(new Runnable() {
+                        @Override
+                        public void run() {
+                            joinRoom(roomId, isCreate);
+                        }
+                    }, 1000);
+                }
+            }
+
+            @Override
+            public void onError(int code, String message) {
+                Log.i("pq", "leaveRoom onError:" + code + "-msg:" + message);
+                if (isExit) {
+                    joinRoom(roomId, isCreate);
+                }
+            }
+        });
+    }
+
+    /**
+     * 加入房间
+     *
+     * @param roomId
+     * @param isCreate
+     */
+    private void joinRoom(String roomId, boolean isCreate) {
+        //如果是观众就直接加入房间
+        Log.i("pq", "joinRoom");
+        LiveEventHelper.getInstance().joinRoom(roomId, new ClickCallback<Boolean>() {
+            @Override
+            public void onResult(Boolean result, String msg) {
+                Log.i("pq", "joinRoom onResult:" + result);
+                if (result) {
+                    setCurrentRoom(currentRoomInfo, isCreate);
+                    refreshMusicView(true);
+                } else {
+                    //加入直播房间失败
+                    if (getView() != null) {
+                        getView().showFinishView();
+                    }
+                    leaveRoom(roomId, isCreate, false);
+                }
+            }
+        });
+    }
+
+    /**
+     * 下麦
+     */
+    public void exitMic() {
+        // 开始切换为观众身份
+        RCRTCEngine.getInstance().getRoom().getLocalUser().switchToAudience(new IRCRTCSwitchRoleCallback() {
+
+            /**
+             * 当切换失败且SDK处于无法回退状态时回调,该角色已经无法使用当前角色继续进行音视频。
+             * SDK内部会退出房间并清理所有资源,该用户只能重新加入房间才能继续音视频。
+             */
+            @Override
+            public void onKicked() {
+                Log.i("pq", "下麦身份切换onKicked");
+            }
+
+            @Override
+            public void onSuccess() {
+                // 该用户切换为观众成功,可以以观众身份进行音视频
+                Log.i("pq", "下麦身份切换成功");
+                if (getView() != null) {
+                    getView().onExitSeatMicSuccess();
+                    subscribeAVStream();
+                }
+            }
+
+            /**
+             * 当切换失败且不影响当前角色继续音视频时回调
+             * @param errorCode 失败错误码
+             */
+            @Override
+            public void onFailed(RTCErrorCode errorCode) {
+                Log.i("pq", "下麦身份切换failed" + errorCode);
+            }
+        });
+    }
+
+    /**
+     * 上麦
+     */
+    public void joinMic() {
+        //连麦
+        ArrayList<RCRTCOutputStream> streams = new ArrayList<>();
+        streams.add(RCRTCEngine.getInstance().getDefaultAudioStream());
+        // 开始切换为主播身份
+        RCRTCEngine.getInstance().getRoom().getLocalUser().switchToBroadcaster(streams, new IRCRTCSwitchRoleDataCallback<RCRTCLiveInfo>() {
+            /**
+             * 当切换失败且SDK处于无法回退状态时回调,该角色已经无法使用当前角色继续进行音视频。
+             * SDK内部会退出房间并清理所有资源,该用户只能重新加入房间才能继续音视频。
+             */
+            @Override
+            public void onKicked() {
+                Log.i("pq", "上麦身份切换kick");
+            }
+
+            @Override
+            public void onSuccess(RCRTCLiveInfo data) {
+                //该用户切换为主播成功,可以以主播身份进行音视频
+                Log.i("pq", "上麦身份切换成功");
+                if (getView() != null) {
+                    getView().onSeatMicSuccess();
+                    subscribeAVStream();
+                }
+            }
+
+            /**
+             * 当切换失败且不影响当前角色继续音视频时回调
+             * @param errorCode 失败错误码
+             */
+            @Override
+            public void onFailed(RTCErrorCode errorCode) {
+                Log.i("pq", "上麦身份切换失败:" + errorCode);
+                if (getView() != null) {
+                    getView().onSeatMicFail();
+                }
+            }
+        });
+    }
+
+    /**
+     * 设置当前房间
+     *
+     * @param roomInfo
+     * @param isCreate
+     */
+    public void setCurrentRoom(LiveRoomInfoBean roomInfo, boolean isCreate) {
+        initLiveRoomListener(roomInfo.roomUid);
+        if (isInRoom) {
+            //恢复一下当前信息就可以了
+            List<MessageContent> messageList = LiveEventHelper.getInstance().getMessageList();
+            getView().addMessageList(messageList, true);
+        } else {
+            // 发送默认消息
+            sendDefaultMessage();
+        }
+        //初次进入的时候,获取房间内的人数信息
+//        MemberCache.getInstance().fetchData(currentRoomInfo.getRoomId());
+        //设置创建者id
+        LiveEventHelper.getInstance().setCreateUserId(roomInfo.speakerId);
+        //最好在订阅流之前再设置一次扬声器模式,不然可能有部分手机有问题,
+        // 在初始化的时候设置扬声器的状态相当于给扬声器一个初始值,时机过于早,
+        // 很可能硬件层还没有准备好。在需要用到扬声器的时候,再设置一下就好了
+        LiveRTCEngineInitHelper.setRTCSpeakerMode(true);
+//        getShield();获取敏感词汇
+        subscribeAVStream();
+        getView().setRoomData(currentRoomInfo);
+    }
+
+    /**
+     * 加入房间后,开始摄像头采集并发布音视频流。
+     */
+    private void startPublish() {
+        RCRTCRoom rcrtcRoom = LiveEventHelper.getInstance().getRtcRoom();
+        RCRTCEngine.getInstance().getDefaultVideoStream().startCamera(null);
+        rcrtcRoom.getLocalUser().publishDefaultLiveStreams(new IRCRTCResultDataCallback<RCRTCLiveInfo>() {
+            @Override
+            public void onSuccess(RCRTCLiveInfo liveInfo) {
+                if (getView() != null) {
+                    getView().onPublishSuccess();
+                }
+            }
+
+            @Override
+            public void onFailed(RTCErrorCode code) {
+                Log.i("pq", "publishDefaultLiveStreamError:" + code);
+            }
+        });
+    }
+
+    /**
+     * 进入房间后发送默认的消息
+     */
+    private void sendDefaultMessage() {
+        if (currentRoomInfo != null) {
+//            getView().addMessageContent(null, true);
+            // 默认消息
+//            RCChatroomLocationMessage welcome = new RCChatroomLocationMessage();
+//            welcome.setContent(String.format("欢迎来到 %s", currentRoomInfo.roomTitle));
+//            sendMessage(welcome);
+            RCChatroomLocationMessage tips = new RCChatroomLocationMessage();
+            tips.setContent("欢迎进入直播课堂,请遵守相关法规,禁止传播低俗、暴力等不良信息。为孩子创造健康绿色的学习环境。");
+            sendMessage(tips);
+        }
+    }
+
+    /**
+     * 发送消息
+     * 默认显示在本地
+     *
+     * @param messageContent
+     */
+    public void sendMessage(MessageContent messageContent) {
+        sendMessage(messageContent, true);
+    }
+
+    /**
+     * 发送消息
+     *
+     * @param messageContent 消息体
+     * @param isShowLocation 是否显示在本地
+     */
+    public void sendMessage(MessageContent messageContent, boolean isShowLocation) {
+        if (!isContainsShield(messageContent)) {
+            LiveEventHelper.getInstance().sendMessage(messageContent, isShowLocation);
+        }
+    }
+
+    /**
+     * 是否包含屏蔽词
+     *
+     * @return
+     */
+    private boolean isContainsShield(MessageContent messageContent) {
+        boolean isContains = false;
+//        if (shields != null) {
+//            for (String shield : shields) {
+//                if (messageContent instanceof RCChatroomBarrage) {
+//                    if (((RCChatroomBarrage) messageContent).getContent().contains(shield)) {
+//                        isContains = true;
+//                        break;
+//                    }
+//                }
+//            }
+//            if (isContains) {
+//                //如果是包含了敏感词'
+//                mView.addMessageContent(messageContent, false);
+//                return true;
+//            }
+//        }
+        return false;
+    }
+
+    /**
+     * 设置直播房的各种监听
+     *
+     * @param roomId
+     */
+    public void initLiveRoomListener(String roomId) {
+        LiveEventHelper.getInstance().getRtcRoom().registerRoomListener(mRoomEventsListener);
+        //添加消息监听
+//        setObShieldListener();
+//        //监听房间里面的人
+//        MemberCache.getInstance().getMemberList()
+//                .observe( new Observer<List<User>>() {
+//                    @Override
+//                    public void onChanged(List<User> users) {
+//                        getView().setOnlineCount(users.size());
+//                        LiveEventHelper.getInstance().getRequestLiveVideoIds(null);
+//                        onInviteLiveVideoIds(users);
+//                    }
+//                });
+//        //监听管理员变化
+//        MemberCache.getInstance().getAdminList()
+//                .observe(((LiveRoomFragment) mView).getViewLifecycleOwner(), new Observer<List<String>>() {
+//                    @Override
+//                    public void onChanged(List<String> strings) {
+//                        mView.refreshMessageList();
+//                    }
+//                });
+    }
+
+    /**
+     * 监听接收房间的所有信息
+     *
+     * @param roomId
+     */
+    public void setObMessageListener(String roomId) {
+        if (disposablesManager.size() != 0) {
+            return;
+        }
+        Disposable subscribe = RCChatRoomMessageManager.
+                obMessageReceiveByRoomId(roomId)
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Consumer<Message>() {
+                    @Override
+                    public void accept(Message message) {
+//                        //将消息显示到列表上
+                        if (LiveEventHelper.getInstance().isShowingMessage(message.getContent())) {
+                            if (null != getView()) {
+                                getView().addMessageContent(message, false);
+                            }
+                        }
+
+
+                        //以下为行为消息逻辑
+                        //行为消息
+                        MessageContent content = message.getContent();
+                        if (content instanceof RCChatRoomCloseMessage) {
+                            //关闭直播间
+                            if (null != getView()) {
+                                getView().liveRoomOffline();
+                            }
+                            return;
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_LIVE_GOODS_CHANGE)) {
+                            //直播间商品变化
+                            if (message.getContent() != null) {
+                                RCLiveGoodsChangeMessage liveGoodsChangeMessage = (RCLiveGoodsChangeMessage) message.getContent();
+                                if (getView() != null && liveGoodsChangeMessage != null) {
+                                    getView().liveGoodsChange(liveGoodsChangeMessage.getContent());
+                                }
+                            }
+                            return;
+                        }
+
+                        //连麦模式控制消息
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_CHAT_ROOM_SEAT_CTRL)) {
+                            if (message.getContent() != null) {
+                                RCUserSeatsCtrlMessage userSeatsCtrlMessage = (RCUserSeatsCtrlMessage) message.getContent();
+                                if (getView() != null && userSeatsCtrlMessage != null) {
+                                    getView().changeMicControlMode(userSeatsCtrlMessage.isSeatBan());
+                                }
+                            }
+                            return;
+                        }
+
+                        //控制聊天模式
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_CHAT_ROOM_CHAT_MODE_CTRL)) {
+                            if (message.getContent() != null) {
+                                RCChatModeMessage chatModeMessage = (RCChatModeMessage) message.getContent();
+                                if (getView() != null && chatModeMessage != null) {
+                                    getView().switchChatMode(chatModeMessage.isChatBan());
+                                }
+                            }
+                            return;
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_CHAT_ROOM_ADD_LIKE_COUNT)) {
+                            //同步点赞消息
+                            RCUserSyncAddLikeCountMessage addLikeMessage = (RCUserSyncAddLikeCountMessage) content;
+                            if (getView() != null) {
+                                getView().onAddLikeMessage(message, addLikeMessage);
+                            }
+                            return;
+                        }
+
+                        if (content instanceof RCChatRoomMemberNumMessage) {
+                            //同步成员数量
+                            if (null != getView()) {
+                                RCChatRoomMemberNumMessage rcChatRoomMemberNumMessage = (RCChatRoomMemberNumMessage) content;
+                                getView().syncMemberCount(rcChatRoomMemberNumMessage.getCount());
+                            }
+                            return;
+                        }
+
+                        if (content instanceof RCUserKickOutMessage) {
+                            //用户被踢出房间消息
+                            if (null != getView()) {
+                                RCUserKickOutMessage userKickOutMessage = (RCUserKickOutMessage) content;
+                                getView().onUserKickOutMsg(userKickOutMessage);
+                            }
+                            return;
+                        }
+
+                        if (content instanceof RCUserSeatResponseMessage) {
+                            //连麦回复消息
+                            if (null != getView()) {
+                                RCUserSeatResponseMessage rcUserSeatResponseMessage = (RCUserSeatResponseMessage) content;
+                                if (rcUserSeatResponseMessage == null || TextUtils.isEmpty(rcUserSeatResponseMessage.getAudienceId())) {
+                                    return;
+                                }
+                                if (TextUtils.equals(rcUserSeatResponseMessage.getAudienceId(), UserHelper.getUserId())) {
+                                    getView().seatResponse(rcUserSeatResponseMessage);
+                                }
+                                return;
+                            }
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_CHAT_ROOM_MIC_APPLY)) {
+                            //主播邀请上麦
+                            RCUserSeatApplyMessage seatApplyMessage = (RCUserSeatApplyMessage) content;
+                            if (getView() != null) {
+                                getView().onInviteSeatMic(seatApplyMessage);
+                            }
+                            return;
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_CHAT_ROOM_UNUSUAL_LOGOUT)) {
+                            //观众异常退出消息
+                            RCUserLogOutUnusualMessage loginOutUnusualMessage = (RCUserLogOutUnusualMessage) content;
+                            if (getView() != null) {
+                                getView().onUserUnusualLogout(loginOutUnusualMessage);
+                            }
+                            return;
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_LIVE_PAUSE)) {
+                            //暂停直播,进行下麦操作
+                            if (getView() != null) {
+                                getView().onLivePause();
+                            }
+                            return;
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_LIVE_ADD_BLACK_USER)) {
+                            //添加黑名单用户
+                            RCLiveBlackUserBlockMessage blackUserBlockMessage = (RCLiveBlackUserBlockMessage) content;
+                            if (getView() != null) {
+                                getView().changeBlackUserStatus(blackUserBlockMessage.getUserId(), true);
+                            }
+                            return;
+                        }
+
+                        if (TextUtils.equals(message.getObjectName(), LiveRoomMsgConstants.TAG_LIVE_REMOVE_BLACK_USER)) {
+                            //解除黑名单用户
+                            RCLiveBlackUserUnBlockMessage userUnBlockMessage = (RCLiveBlackUserUnBlockMessage) content;
+                            if (getView() != null) {
+                                getView().changeBlackUserStatus(userUnBlockMessage.getUserId(), false);
+                            }
+                            return;
+                        }
+                    }
+                });
+        disposablesManager.add(subscribe);
+    }
+
+    /**
+     * 刷新音乐播放的小窗UI
+     *
+     * @param show 是否显示
+     */
+    private void refreshMusicView(boolean show) {
+//        if (show) {
+//            MusicApi.getPlayingMusic(getRoomId(), new IResultBack<MusicBean>() {
+//                @Override
+//                public void onResult(MusicBean musicBean) {
+//                    if (musicBean != null) {
+//                        mView.refreshMusicView(true, musicBean.getNameAndAuthor(), musicBean.getBackgroundUrl());
+//                    } else {
+//                        mView.refreshMusicView(false, "", "");
+//                    }
+//                }
+//            });
+//        } else {
+//            mView.refreshMusicView(false, "", "");
+//        }
+    }
+
+    /**
+     * 获得当前视频流
+     */
+    public void getVideoStream(List<RCRTCVideoOutputStream> outputStreams, List<RCRTCVideoInputStream> inputStreams, List<RCRTCAudioInputStream> audioinputstream) {
+        RCRTCRoom mRtcRoom = LiveEventHelper.getInstance().getRtcRoom();
+        if (mRtcRoom == null) {
+            return;
+        }
+        for (final RCRTCRemoteUser remoteUser : mRtcRoom.getRemoteUsers()) {
+            if (remoteUser.getStreams().size() == 0) {
+                continue;
+            }
+            List<RCRTCInputStream> userStreams = remoteUser.getStreams();
+            for (RCRTCInputStream i : userStreams) {
+                if (i.getMediaType() == RCRTCMediaType.VIDEO) {
+                    inputStreams.add((RCRTCVideoInputStream) i);
+                }
+                if (i.getMediaType() == RCRTCMediaType.AUDIO) {
+                    audioinputstream.add((RCRTCAudioInputStream) i);
+                }
+            }
+        }
+
+        for (RCRTCOutputStream o : mRtcRoom.getLocalUser().getStreams()) {
+            if (o.getMediaType() == RCRTCMediaType.VIDEO) {
+                outputStreams.add((RCRTCVideoOutputStream) o);
+            }
+        }
+    }
+
+
+    /**
+     * 主动订阅远端用户发布的流
+     * 视频流需要用户设置用于显示载体的videoview
+     */
+    public void subscribeAVStream() {
+        RCRTCRoom rcrtcRoom = LiveEventHelper.getInstance().getRtcRoom();
+        if (rcrtcRoom == null) {
+            Log.i("pq", "rcrtcRoom is null");
+            return;
+        }
+        List<RCRTCRemoteUser> remoteUsers = rcrtcRoom.getRemoteUsers();
+        final List<RCRTCInputStream> inputStreams = new ArrayList<>();
+        for (int i = 0; i < remoteUsers.size(); i++) {
+            RCRTCRemoteUser rcrtcRemoteUser = remoteUsers.get(i);
+            List<RCRTCInputStream> streams = rcrtcRemoteUser.getStreams();
+            if (streams == null || streams.size() == 0) {
+                continue;
+            }
+            inputStreams.addAll(streams);
+        }
+        //合流模式,画面会出现问题,画面放大,裁剪,可能是合流模式布局问题
+//        final List<RCRTCInputStream> otherInputStreams = rcrtcRoom.getLiveStreams();
+        if (inputStreams != null && inputStreams.size() != 0) {
+            rcrtcRoom.getLocalUser().subscribeStreams(inputStreams, new IRCRTCResultCallback() {
+                @Override
+                public void onSuccess() {
+                    Log.i("pq", "subscribeStreams onSuccess:" + inputStreams.size());
+                    try {
+                        getView().subscribeAVStreamSuccess(inputStreams);
+                    } catch (IllegalStateException e) {
+                        e.printStackTrace();
+                    }
+                }
+
+                @Override
+                public void onFailed(RTCErrorCode code) {
+                    Log.i("pq", "subscribeStreams code:" + code);
+                    try {
+                        getView().onSubscribeFailed();
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            });
+        } else {
+            Log.i("pq", "当前房间还没有主播");
+            try {
+                getView().showEmptyStatusView();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void detachView() {
+        super.detachView();
+        unInitListener();
+    }
+
+    /**
+     * 回收掉对房间的各种监听
+     */
+    public void unInitListener() {
+        clearDisposables();
+    }
+
+    public void clearDisposables() {
+        for (Disposable disposable : disposablesManager) {
+            Log.i("pq", "disposable" + disposable);
+            disposable.dispose();
+        }
+        disposablesManager.clear();
+    }
+}

+ 1707 - 0
student/src/main/java/com/cooleshow/student/ui/live/LiveRoomActivity.java

@@ -0,0 +1,1707 @@
+package com.cooleshow.student.ui.live;
+
+import android.animation.ObjectAnimator;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.alibaba.android.arouter.launcher.ARouter;
+import com.bumptech.glide.Glide;
+import com.cooleshow.base.data.net.ApiException;
+import com.cooleshow.base.router.RouterPath;
+import com.cooleshow.base.ui.activity.BaseMVPActivity;
+import com.cooleshow.base.utils.AppUtils;
+import com.cooleshow.base.utils.SizeUtils;
+import com.cooleshow.base.utils.SoftKeyboardUtil;
+import com.cooleshow.base.utils.ToastUtil;
+import com.cooleshow.base.utils.UiUtils;
+import com.cooleshow.base.utils.Utils;
+import com.cooleshow.base.widgets.InputBar;
+import com.cooleshow.student.bean.FriendInfoBean;
+import com.cooleshow.student.ui.live.floatPop.FloatWindowHelper;
+import com.cooleshow.student.ui.live.floatPop.FloatingWindowService;
+import com.cooleshow.student.widgets.dialog.LiveRoomCloseTipDialog;
+import com.cooleshow.student.widgets.dialog.OpenOverlayPermissionTipDialog;
+import com.cooleshow.student.widgets.helper.LiveRoomAddLikeHelper;
+import com.cooleshow.base.widgets.dialog.InputBarDialog;
+import com.cooleshow.student.R;
+import com.cooleshow.student.adapter.MessageAdapter;
+import com.cooleshow.student.bean.LiveRoomInfoBean;
+import com.cooleshow.student.contract.LiveRoomContract;
+import com.cooleshow.student.databinding.ActivityLiveroomLayoutBinding;
+import com.cooleshow.student.presenter.live.LiveRoomPresenter;
+import com.cooleshow.student.utils.helper.LiveRTCEngineInitHelper;
+import com.cooleshow.student.widgets.dialog.LiveRoomCloseMicTipDialog;
+import com.cooleshow.student.widgets.dialog.LiveRoomClosePageOnMicTipDialog;
+import com.cooleshow.student.widgets.dialog.LiveRoomInviteSeatMicTipDialog;
+import com.cooleshow.student.widgets.dialog.LiveRoomShopCarDialog;
+import com.cooleshow.student.widgets.helper.LiveRoomAnimatorHelper;
+import com.cooleshow.usercenter.helper.UserHelper;
+import com.rong.io.live.LiveRoomMsgConstants;
+import com.rong.io.live.config.LiveConfig;
+import com.rong.io.live.helper.LiveEventHelper;
+import com.rong.io.live.message.RCUserKickOutMessage;
+import com.rong.io.live.message.RCUserLogOutUnusualMessage;
+import com.rong.io.live.message.RCUserSeatApplyMessage;
+import com.rong.io.live.message.RCUserSeatResponseMessage;
+import com.rong.io.live.message.RCUserSyncAddLikeCountMessage;
+import com.rong.io.live.widget.LiveRoomMicIconView;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
+import androidx.constraintlayout.widget.Group;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import cn.rongcloud.rtc.api.RCRTCAudioRouteManager;
+import cn.rongcloud.rtc.api.RCRTCRemoteUser;
+import cn.rongcloud.rtc.api.RCRTCRoom;
+import cn.rongcloud.rtc.api.RCRTCVideoStream;
+import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoInputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoOutputStream;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
+import cn.rongcloud.rtc.base.RCRTCLiveRole;
+import cn.rongcloud.rtc.base.RCRTCMediaType;
+import cn.rongcloud.rtc.base.RCRTCResourceState;
+import cn.rongcloud.rtc.core.RendererCommon;
+import de.hdodenhof.circleimageview.CircleImageView;
+import io.rong.imkit.IMCenter;
+import io.rong.imlib.IRongCoreCallback;
+import io.rong.imlib.IRongCoreEnum;
+import io.rong.imlib.RongIMClient;
+import io.rong.imlib.model.Message;
+import io.rong.imlib.model.MessageContent;
+import io.rong.imlib.model.UserInfo;
+import io.rong.message.TextMessage;
+
+import com.rong.io.live.helper.VideoViewManager;
+
+/**
+ * Author by pq, Date on 2022/3/29.
+ */
+
+@Route(path = RouterPath.LiveCenter.ACTIVITY_LIVE_ROOM)
+public class LiveRoomActivity extends BaseMVPActivity<ActivityLiveroomLayoutBinding, LiveRoomPresenter> implements View.OnClickListener, LiveRoomContract.view, SoftKeyboardUtil.OnSoftInputChangedListener {
+    public static final int SEND_SHOW_FLOAT_WINDOW_TIME = 1000;//退到后台以后检查是否显示悬浮窗等待时长
+    public static final int SEND_APP_BACKGROUND_MSG = 1001;//退到后台消息
+    public static final int SEND_JUMP_OTHER_PAGE_MSG = 1002;//页面切换消息(购物车详情页等等)
+    public static final int OPEN_SHOP_CAR_DIALOG = 1003;//打开购物车
+    ConstraintLayout content_view;
+    RelativeLayout mFlLiveView;
+    LinearLayout ll_like;
+    RecyclerView mRecyclerMsg;
+    TextView mTvNumPeople;
+    ImageView iv_mic;
+    LiveRoomMicIconView mLlMicContainer;
+    TextView mTvAddLikeCount;
+    CircleImageView mIvAvatar;
+    TextView mTvRoomCreateName;
+    Group mGroupViews;
+    ConstraintLayout mViewLiveStatus;
+    ImageView mIvLiveStatusCenterIcon;
+    TextView mTvLiveStatusTipText;
+    ImageView mIvSwitchVideoOrientation;
+    ImageView mIvSwitchVideoOrientationFull;
+    ConstraintLayout cs_header_info;
+    LottieAnimationView mViewShopCarAnim;
+    ImageView mIvShopCar;
+    ImageView mIvClose;
+    TextView tv_input;
+
+    private LiveRoomInfoBean mRoomInfoBean;
+    private String mRoomId;
+    private MessageAdapter mMessageAdapter;
+    private LinearLayoutManager mLinearLayoutManager;
+    private boolean isEnableChat = false;//默认不禁止
+    private boolean isEnableMic = false;//默认不禁止
+    private boolean isEnableAll = false;//默认不禁止 黑名单状态
+    private InputBarDialog mInputBarDialog;
+    private int currentSeatStatus = LiveRoomMsgConstants.MIC_STATUS_NORMAL;//1未连麦,2连麦中,3连麦成功
+    private LiveRoomCloseMicTipDialog mRoomCloseMicTipDialog;
+    private LiveRoomInviteSeatMicTipDialog mInviteSeatMicTipDialog;
+    private int currentAddLikeCount = 0;//当前点赞数量
+    private boolean creatorIsCloseAudioStream = false;
+    private boolean creatorIsCloseVideoStream = false;
+    private String createRoomId = "";
+    private static final String ROOMID_KEY = "roomid_key";
+    private String mUserId;
+    private boolean connectStatusIsPaused = false;
+    private boolean isNeedRefresh = false;//是否需要重新刷新房间信息
+    private ServiceConnection serviceConnection;
+    private ObjectAnimator hideHeaderInfoAnim;
+    private ObjectAnimator showHeaderInfoAnim;
+    private Handler mHandler = new Handler(Looper.myLooper()) {
+        @Override
+        public void handleMessage(@NonNull android.os.Message msg) {
+            if (msg.what == SEND_APP_BACKGROUND_MSG) {
+                //APP切换后台
+                //开启悬浮窗
+                if (AppUtils.isApplicationInBackground(LiveRoomActivity.this)) {
+                    startFloatWindowService();
+                }
+                return;
+            }
+            if (msg.what == SEND_JUMP_OTHER_PAGE_MSG) {
+                //跳转其他页面时候
+                //开启悬浮窗
+                startFloatWindowService();
+                return;
+            }
+
+            if (msg.what == OPEN_SHOP_CAR_DIALOG) {
+                showShopCarDialog();
+                return;
+            }
+        }
+    };
+    private RongIMClient.ConnectionStatusListener connectStatusListener = new RongIMClient.ConnectionStatusListener() {
+        @Override
+        public void onChanged(ConnectionStatus status) {
+            Log.i("pq", "LiveRoomActivity receive ConnectionStatus:" + status);
+            if (status == ConnectionStatus.KICKED_OFFLINE_BY_OTHER_CLIENT
+                    || status == ConnectionStatus.SIGN_OUT || status == ConnectionStatus.TIMEOUT) {
+                finish();
+            }
+            if (status == ConnectionStatus.CONNECTED) {
+                //IM连接成功
+                if (presenter != null && isNeedRefresh) {
+                    connectStatusIsPaused = false;
+                    presenter.init(mRoomId, false);
+                }
+            } else {
+                //其他状态的时候需要重新刷新房间信息
+                isNeedRefresh = true;
+            }
+            if (status == ConnectionStatus.SUSPEND) {
+                connectStatusIsPaused = true;
+            }
+        }
+    };
+    private LiveRoomClosePageOnMicTipDialog mLiveRoomClosePageOnMicTipDialog;
+    private VideoViewManager mVideoViewManager;
+    private LiveRoomShopCarDialog mShopCarDialog;
+
+    public static void startLiveRoomActivity(Context context, String roomid) {
+        Intent intent = new Intent(context, LiveRoomActivity.class);
+        intent.putExtra(ROOMID_KEY, roomid);
+        context.startActivity(intent);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void initView() {
+        content_view = viewBinding.contentView;
+        mFlLiveView = viewBinding.flLiveView;
+        ll_like = viewBinding.llLike;
+        mRecyclerMsg = viewBinding.recyclerMsg;
+        mTvNumPeople = viewBinding.tvNumPeople;
+        iv_mic = viewBinding.ivMic;
+        mLlMicContainer = viewBinding.llMicContainer;
+        mTvAddLikeCount = viewBinding.tvAddLikeCount;
+        mIvAvatar = viewBinding.ivAvatar;
+        mTvRoomCreateName = viewBinding.tvRoomAuthorName;
+        mGroupViews = viewBinding.groupViews;
+        mViewLiveStatus = viewBinding.viewLiveStatus.csRootLiveStatus;
+        mIvLiveStatusCenterIcon = viewBinding.viewLiveStatus.ivCenterIcon;
+        mTvLiveStatusTipText = viewBinding.viewLiveStatus.tvLiveStatusTipText;
+        mIvSwitchVideoOrientation = viewBinding.ivSwitchVideoOrientation;
+        mIvSwitchVideoOrientationFull = viewBinding.ivSwitchVideoOrientationFull;
+        cs_header_info = viewBinding.csHeaderInfo;
+        mViewShopCarAnim = viewBinding.viewShopCarAnim;
+        mIvShopCar = viewBinding.ivShopCar;
+        mIvClose = viewBinding.ivClose;
+        tv_input = viewBinding.tvInput;
+        initListener();
+    }
+
+    private void initListener() {
+        mIvClose.setOnClickListener(this);
+        mIvSwitchVideoOrientation.setOnClickListener(this);
+        mIvSwitchVideoOrientationFull.setOnClickListener(this);
+        tv_input.setOnClickListener(this);
+        iv_mic.setOnClickListener(this);
+        viewBinding.iconAddLike.setOnClickListener(this);
+        mViewLiveStatus.setOnClickListener(this);
+        mViewShopCarAnim.setOnClickListener(this);
+        mFlLiveView.setOnClickListener(this);
+    }
+
+    @Override
+    protected ActivityLiveroomLayoutBinding getLayoutView() {
+        return ActivityLiveroomLayoutBinding.inflate(getLayoutInflater());
+    }
+
+
+    @Override
+    public void initData() {
+        super.initData();
+        mRoomId = getIntent().getStringExtra(ROOMID_KEY);
+        if (TextUtils.isEmpty(mRoomId)) {
+            ToastUtil.getInstance().show(this, "房间id不可为空");
+            finish();
+            return;
+        }
+        String userToken = UserHelper.getUserToken();
+        if (TextUtils.isEmpty(userToken)) {
+            finish();
+            return;
+        }
+        if (LiveConfig.isNeedReInitRTC) {
+            //检查是否需要重新初始化RTC
+            LiveRTCEngineInitHelper.initRTC();
+        }
+        // 初始化音频路由管理类
+        RCRTCAudioRouteManager.getInstance().init(Utils.getApp());
+        mFlLiveView.post(new Runnable() {
+            @Override
+            public void run() {
+                checkVideoViewManager();
+            }
+        });
+        mUserId = UserHelper.getUserId();
+        mMessageAdapter = new MessageAdapter(this);
+        mLinearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
+        mRecyclerMsg.setLayoutManager(mLinearLayoutManager);
+        mRecyclerMsg.setAdapter(mMessageAdapter);
+        IMCenter.getInstance().addConnectionStatusListener(connectStatusListener);
+        SoftKeyboardUtil.registerSoftInputChangedListener(getWindow(), this);
+        prepareInitRoom();
+    }
+
+    private void prepareInitRoom() {
+        //根据融云的IM连接状态判断是否需要获取房间信息
+        RongIMClient.ConnectionStatusListener.ConnectionStatus currentConnectionStatus = RongIMClient.getInstance().getCurrentConnectionStatus();
+        if (currentConnectionStatus == RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED) {
+            isNeedRefresh = false;
+            if (presenter != null) {
+                presenter.init(mRoomId, false);
+            }
+        } else {
+            //如果IM未连接,等待connectStatusListener回调
+            isNeedRefresh = true;
+        }
+    }
+
+
+    public void onClick(View view) {
+        int id = view.getId();
+        if (id == R.id.view_live_status) {
+            return;
+        }
+        if (id == R.id.iv_close) {
+            if (currentSeatStatus != LiveRoomMsgConstants.MIC_STATUS_NORMAL) {
+                showPageCloseOnMicTipDialog();
+            } else {
+                close();
+            }
+        }
+        if (id == R.id.iv_switch_video_orientation) {
+            //切换横竖屏
+            if (mShopCarDialog != null && mShopCarDialog.isShowing()) {
+                return;
+            }
+            changeOrientation();
+            return;
+        }
+
+        if (id == R.id.iv_switch_video_orientation_full) {
+            //横屏切换竖屏
+            changeOrientation();
+            return;
+        }
+        if (id == R.id.tv_input) {
+            //底部输入框
+            showInputDialog();
+            return;
+        }
+        if (id == R.id.iv_mic) {
+            //连麦
+            if (checkMicMode()) {
+                return;
+            }
+            if (connectStatusIsPaused) {
+                //连接状态异常,暂停连麦
+                return;
+            }
+            if (currentSeatStatus == LiveRoomMsgConstants.MIC_STATUS_NORMAL) {
+                //未连麦状态 申请连麦
+                if (presenter != null) {
+                    presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_SEAT_APPLY);
+                }
+                updateMicIcon(LiveRoomMsgConstants.MIC_STATUS_CONNECTING);
+                ToastUtil.getInstance().show(LiveRoomActivity.this, getString(R.string.seat_apply_str));
+            } else {
+                //取消连麦
+                showCloseMicTipDialog();
+            }
+            return;
+        }
+
+        if (id == R.id.icon_add_like) {
+            if (connectStatusIsPaused) {
+                //连接状态异常,暂停连麦
+                return;
+            }
+            //点赞
+            LiveRoomAddLikeHelper.getInstance().handleClick(new LiveRoomAddLikeHelper.OnAddLikeResultCallBack() {
+                @Override
+                public void onResult(int count) {
+                    if (presenter != null) {
+                        presenter.setAddLikeCount(count);
+                        presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_ADD_LIKE_COUNT);
+                    }
+                }
+            });
+            LiveRoomAnimatorHelper.getInstance().startAddLikeAnimation(LiveRoomActivity.this, content_view);
+            return;
+        }
+
+        if (id == R.id.view_shop_car_anim) {
+            //购物车
+            if (isFullScreen()) {
+                changeOrientation();
+                android.os.Message message = android.os.Message.obtain();
+                message.what = OPEN_SHOP_CAR_DIALOG;
+                mHandler.sendMessageDelayed(message, 500);
+            } else {
+                showShopCarDialog();
+            }
+            return;
+        }
+
+        if (id == R.id.fl_live_view) {
+            //点击隐藏头部信息
+            if (isFullScreen()) {
+                //全屏模式下
+                handleHeaderAnim();
+            }
+            return;
+        }
+    }
+
+
+    private void handleHeaderAnim() {
+        float animOffset = cs_header_info.getTranslationY();
+        if (animOffset == 0) {
+            //隐藏头部信息
+            int bottom = cs_header_info.getBottom();
+            if (hideHeaderInfoAnim == null) {
+                hideHeaderInfoAnim = ObjectAnimator.ofFloat(cs_header_info, "translationY", 0, -bottom);
+                hideHeaderInfoAnim.setDuration(500);
+            }
+            hideHeaderInfoAnim.start();
+        } else {
+            //显示头部信息
+            if (showHeaderInfoAnim == null) {
+                showHeaderInfoAnim = ObjectAnimator.ofFloat(cs_header_info, "translationY", animOffset, 0);
+                showHeaderInfoAnim.setDuration(500);
+            }
+            showHeaderInfoAnim.start();
+        }
+    }
+
+    private void showShopCarDialog() {
+        if (mShopCarDialog == null) {
+            mShopCarDialog = new LiveRoomShopCarDialog(this);
+            mShopCarDialog.setOnEventListener(new LiveRoomShopCarDialog.OnEventListener() {
+                @Override
+                public void onOpenDetail(String url) {
+                    mShopCarDialog.dismiss();
+                    //发送XXX正在抢购消息
+//                    presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_ON_SNAP_UP);
+//                    sendShowFloatWindowAction(SEND_JUMP_OTHER_PAGE_MSG);
+//                    ARouter.getInstance()
+//                            .build(ARouterConstace.ACTIVITY_HTML)
+//                            .withString(ARouterConstace.URL, url)
+//                            .withString(ARouterConstace.TITLE, "商品详情")
+//                            .navigation();
+                }
+            });
+        }
+        if (!mShopCarDialog.isShowing()) {
+            mShopCarDialog.show();
+        }
+        mShopCarDialog.setRoomId(mRoomId);
+    }
+
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    private void showPageCloseOnMicTipDialog() {
+        if (mLiveRoomClosePageOnMicTipDialog == null) {
+            mLiveRoomClosePageOnMicTipDialog = new LiveRoomClosePageOnMicTipDialog(this);
+            mLiveRoomClosePageOnMicTipDialog.setConfirmClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    close();
+                }
+            });
+        }
+        if (!mLiveRoomClosePageOnMicTipDialog.isShowing()) {
+            mLiveRoomClosePageOnMicTipDialog.show();
+        }
+        mLiveRoomClosePageOnMicTipDialog.setTitle("提示");
+        mLiveRoomClosePageOnMicTipDialog.setContent("连麦中,是否退出房间?");
+    }
+
+    private void showCloseMicTipDialog() {
+        if (mRoomCloseMicTipDialog == null) {
+            mRoomCloseMicTipDialog = new LiveRoomCloseMicTipDialog(this);
+            mRoomCloseMicTipDialog.setConfirmClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    handleCloseMicEvent();
+                    mRoomCloseMicTipDialog.dismiss();
+                }
+            });
+        }
+        if (!mRoomCloseMicTipDialog.isShowing()) {
+            mRoomCloseMicTipDialog.show();
+        }
+        mRoomCloseMicTipDialog.setContent(getString(currentSeatStatus == LiveRoomMsgConstants.MIC_STATUS_CONNECTING ? R.string.cancel_seat_on_connecting : R.string.cancel_seat_on_connected));
+    }
+
+    /**
+     * 取消连麦
+     */
+    private void handleCloseMicEvent() {
+        if (currentSeatStatus == LiveRoomMsgConstants.MIC_STATUS_CONNECTING) {
+            //连接中取消连接
+            if (presenter != null) {
+                presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_CANCEL_SEAT_APPLY);
+                updateMicIcon(LiveRoomMsgConstants.MIC_STATUS_NORMAL);
+            }
+        }
+        if (currentSeatStatus == LiveRoomMsgConstants.MIC_STATUS_CONNECT_SUCCESS) {
+            if (presenter != null) {
+                presenter.exitMic();
+            }
+        }
+    }
+
+    private void updateMicIcon(int micStatus) {
+        //主线程更新
+        iv_mic.post(new Runnable() {
+            @Override
+            public void run() {
+                currentSeatStatus = micStatus;
+                if (micStatus == LiveRoomMsgConstants.MIC_STATUS_NORMAL) {
+                    iv_mic.setImageResource(R.drawable.icon_mic_unconnect);
+                }
+                if (micStatus == LiveRoomMsgConstants.MIC_STATUS_CONNECTING) {
+                    iv_mic.setImageResource(R.drawable.icon_mic_connecting);
+                }
+                if (micStatus == LiveRoomMsgConstants.MIC_STATUS_CONNECT_SUCCESS) {
+                    iv_mic.setImageResource(R.drawable.icon_mic_conected);
+                }
+            }
+        });
+    }
+
+    private void showInputDialog() {
+        if (checkChatMode()) return;
+        if (mInputBarDialog == null) {
+            mInputBarDialog = new InputBarDialog(LiveRoomActivity.this, new InputBar.InputBarListener() {
+                @Override
+                public void onClickSend(String message) {
+                    //发送消息
+                    if (TextUtils.isEmpty(message)) {
+                        ToastUtil.getInstance().show(LiveRoomActivity.this, "消息不能为空");
+                        return;
+                    }
+                    sendTextMessage(message);
+                }
+
+
+                @Override
+                public boolean onClickEmoji() {
+                    return false;
+                }
+            });
+
+            mInputBarDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+                @Override
+                public void onShow(DialogInterface dialog) {
+                    if (mInputBarDialog != null) {
+                        mInputBarDialog.showInput();
+                    }
+                }
+            });
+        }
+        if (!mInputBarDialog.isShowing()) {
+            mInputBarDialog.show();
+        }
+    }
+
+    private void sendTextMessage(String message) {
+        if (checkChatMode()) {
+            //禁止聊天模式
+            if (mInputBarDialog != null) {
+                mInputBarDialog.dismiss();
+            }
+            return;
+        }
+        if (presenter != null) {
+            TextMessage textMessage = TextMessage.obtain(message);
+            UserInfo userInfo = new UserInfo(mUserId, UserHelper.getUserName(), null);
+            textMessage.setUserInfo(userInfo);
+            presenter.sendMessage(textMessage);
+        }
+    }
+
+    private void changeOrientation() {
+        int currentOrientation = getCurrentOrientation();
+        boolean isNeedFullScreen = currentOrientation != Configuration.ORIENTATION_LANDSCAPE;
+        if (isNeedFullScreen) {
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+        } else {
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        //改变videoView容器布局尺寸
+        resetVideoContainer(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
+    }
+
+    private void close() {
+        //断开连接,结束页面
+        onBackPressed();
+    }
+
+    @Override
+    protected LiveRoomPresenter createPresenter() {
+        return new LiveRoomPresenter();
+    }
+
+
+    /**
+     * 获取房间信息成功
+     *
+     * @param roomInfoBean
+     */
+    @Override
+    public void getRoomInfoSuccess(LiveRoomInfoBean roomInfoBean) {
+        if (roomInfoBean == null || isFinishing() || isDestroyed()) {
+            return;
+        }
+        boolean isPc = !TextUtils.equals("pc", roomInfoBean.os);
+        resetVideoContainer(isPc);
+        mRoomInfoBean = roomInfoBean;
+        currentAddLikeCount = roomInfoBean.likeNum;
+        if (!TextUtils.isEmpty(roomInfoBean.roomConfig)) {
+            try {
+                JSONObject jsonObject = new JSONObject(roomInfoBean.roomConfig);
+                int chatCtrlMode = jsonObject.optInt("whether_chat", 0);
+                int micCtrlMode = jsonObject.optInt("whether_mic", 0);
+                isEnableChat = chatCtrlMode == 1;
+                isEnableMic = micCtrlMode == 1;
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        //黑名单模式
+        isEnableAll = roomInfoBean.blacklistFlag == 1;//1是黑名单 0否
+        updateInputTip();
+        updateAddLikeCountView();
+
+        if (mTvNumPeople != null) {
+            int peopleCount = roomInfoBean.lookNum + 1;//加上自己
+            mTvNumPeople.setText(peopleCount + "人");
+        }
+
+        if (mIvAvatar != null) {
+            //创建人头像
+            Glide.with(LiveRoomActivity.this).load(roomInfoBean.speakerPic).placeholder(R.drawable.icon_teacher_default_head).error(R.drawable.icon_teacher_default_head).into(mIvAvatar);
+        }
+        if (mTvRoomCreateName != null) {
+            //创建人昵称
+            mTvRoomCreateName.setText(roomInfoBean.speakerName);
+        }
+
+        if (mMessageAdapter != null) {
+            mMessageAdapter.setRoomAuthorId(roomInfoBean.speakerId);
+        }
+        if (presenter != null) {
+            //加入聊天室
+            //加入直播间
+            showLoading();
+            LiveEventHelper.getInstance().register(mRoomInfoBean.roomUid);
+            presenter.leaveRoom(mRoomInfoBean.roomUid, false, true);
+            presenter.joinChartRoom(mRoomInfoBean.roomUid, new IRongCoreCallback.OperationCallback() {
+                @Override
+                public void onSuccess() {
+                    Log.i("pq", "加入聊天房间成功");
+                    if (presenter != null) {
+                        presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_JOIN_ROOM);
+                    }
+                }
+
+                @Override
+                public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) {
+                    Log.i("pq", "加入聊天房间fail:" + coreErrorCode);
+                    Toast.makeText(LiveRoomActivity.this, "加入聊天房间fail:" + coreErrorCode, Toast.LENGTH_SHORT).show();
+                }
+            });
+        }
+    }
+
+    private void updateInputTip() {
+        if (tv_input == null) {
+            return;
+        }
+        if (isEnableAll) {
+            tv_input.setText(getString(R.string.unable_input_tip_str));
+        } else {
+            tv_input.setText(getString(R.string.live_input_tips_str));
+        }
+    }
+
+    @Override
+    public void getRoomInfoError(Throwable t) {
+        if (isDestroyed() || isFinishing()) {
+            return;
+        }
+        if (t instanceof ApiException) {
+            ApiException apiException = (ApiException) t;
+            ToastUtil.getInstance().show(LiveRoomActivity.this, apiException.getErrmsg());
+        }
+        finish();
+    }
+
+    private void resetVideoContainer(boolean isFullScreen) {
+        if (mVideoViewManager != null) {
+            mVideoViewManager.setIsNeedFillScreen(isFullScreen);
+        }
+        if (isFullScreen) {
+            mGroupViews.setVisibility(View.GONE);
+            mIvClose.setVisibility(View.GONE);
+            mIvSwitchVideoOrientation.setVisibility(View.GONE);
+            mIvSwitchVideoOrientationFull.setVisibility(View.VISIBLE);
+            ConstraintSet set = new ConstraintSet();
+            set.clone(content_view);
+            set.clear(mFlLiveView.getId());
+            set.connect(mFlLiveView.getId(), ConstraintSet.TOP, content_view.getId(), ConstraintSet.TOP, 0);
+            set.connect(mFlLiveView.getId(), ConstraintSet.LEFT, content_view.getId(), ConstraintSet.LEFT, 0);
+            set.connect(mFlLiveView.getId(), ConstraintSet.RIGHT, content_view.getId(), ConstraintSet.RIGHT, 0);
+            set.connect(mFlLiveView.getId(), ConstraintSet.BOTTOM, content_view.getId(), ConstraintSet.BOTTOM, 0);
+            set.applyTo(content_view);
+        } else {
+            //pc端直播,控制居中显示,以及videoview容器的宽高
+            if (cs_header_info.getTranslationY() != 0) {
+                //还原显示头部信息
+                handleHeaderAnim();
+            }
+            mGroupViews.setVisibility(View.VISIBLE);
+            mIvClose.setVisibility(View.VISIBLE);
+            mIvSwitchVideoOrientation.setVisibility(View.VISIBLE);
+            mIvSwitchVideoOrientationFull.setVisibility(View.GONE);
+            ConstraintSet set = new ConstraintSet();
+            set.clone(content_view);
+            set.clear(mFlLiveView.getId());
+            set.connect(mFlLiveView.getId(), ConstraintSet.TOP, cs_header_info.getId(), ConstraintSet.BOTTOM, SizeUtils.dp2px(121));
+            set.connect(mFlLiveView.getId(), ConstraintSet.LEFT, content_view.getId(), ConstraintSet.LEFT, 0);
+            set.connect(mFlLiveView.getId(), ConstraintSet.RIGHT, content_view.getId(), ConstraintSet.RIGHT, 0);
+            int maxHeightAtRatio16_9 = UiUtils.getMaxHeightAtRatio16_9(LiveRoomActivity.this);
+            set.constrainHeight(mFlLiveView.getId(), maxHeightAtRatio16_9);
+            set.applyTo(content_view);
+        }
+        changVideoViewSize();
+    }
+
+    public void changVideoViewSize() {
+        int childCount = mFlLiveView.getChildCount();
+        if (childCount == 0) {
+            return;
+        }
+        View childAt = mFlLiveView.getChildAt(0);
+        if (childAt instanceof RCRTCVideoView) {
+            RCRTCVideoView videoView = (RCRTCVideoView) childAt;
+//            mFlLiveView.removeView(videoView);
+//            mFlLiveView.addView(videoView);
+        }
+    }
+
+    @Override
+    public void showFinishView() {
+        //显示结束view
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        Log.i("pq", "加入直播间异常");
+    }
+
+
+    /**
+     * 主讲人的音频状态
+     *
+     * @param isCloseAudioStream
+     */
+    @Override
+    public void syncAudioStatus(boolean isCloseAudioStream) {
+        this.creatorIsCloseAudioStream = isCloseAudioStream;
+        if (creatorIsCloseAudioStream && creatorIsCloseVideoStream) {
+            //如果是关闭音频,同时判断下视频的状态
+            showRestView();
+        }
+    }
+
+    @Override
+    public void showRestView() {
+        showLiveStatusView(true);
+    }
+
+    @Override
+    public void showCloseVideoView() {
+        //关闭了视频
+        creatorIsCloseVideoStream = true;
+        if (creatorIsCloseAudioStream) {
+            //同时音频也关闭了
+            showRestView();
+            return;
+        }
+        showLiveStatusView(false);
+    }
+
+    private void showLiveStatusView(boolean isRestView) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (mViewLiveStatus == null) {
+            return;
+        }
+        //显示视频画面已经关闭页面
+        mViewLiveStatus.post(new Runnable() {
+            @Override
+            public void run() {
+                hideLoading();
+                mViewLiveStatus.setVisibility(View.VISIBLE);
+                if (isRestView) {
+                    mIvLiveStatusCenterIcon.setImageResource(R.drawable.icon_live_room_rest_bg);
+                    mTvLiveStatusTipText.setText("休息一下马上回来!!");
+                } else {
+                    mIvLiveStatusCenterIcon.setImageResource(R.drawable.icon_live_room_close_video);
+                    mTvLiveStatusTipText.setText("主持人已关闭画面!");
+                }
+            }
+        });
+    }
+
+    @Override
+    public void showEmptyStatusView() {
+        //显示老师不在线view
+        showRestView();
+    }
+
+    @Override
+    public View getContentView() {
+        return content_view;
+    }
+
+    @Override
+    public void addMessageList(List<MessageContent> messageContents, boolean isReset) {
+        //添加多条消息至页面
+    }
+
+    @Override
+    public void addMessageContent(Message message, boolean isReset) {
+        //添加单条消息至页面
+        Log.i("pq", "收到需要显示msg:" + message);
+        //只处理直播间消息,以及本直播间消息
+        if (mMessageAdapter != null) {
+            mMessageAdapter.addMessage(message);
+            if (mRecyclerMsg != null && mLinearLayoutManager != null) {
+                mRecyclerMsg.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mRecyclerMsg.scrollToPosition(mMessageAdapter.getItemCount() - 1);
+//                        mRecyclerMsg.scrollToPosition(mMessageAdapter.getItemCount() - 1);
+//                        mLinearLayoutManager.scrollToPositionWithOffset(mMessageAdapter.getItemCount() - 1, 0);
+                    }
+                });
+            }
+        }
+    }
+
+    private void updateAddLikeCountView() {
+        if (mTvAddLikeCount != null) {
+            mTvAddLikeCount.setText(getString(R.string.live_room_add_like_count_str, currentAddLikeCount));
+        }
+    }
+
+    /**
+     * 控制聊天模式
+     *
+     * @param isEnableChat
+     */
+    @Override
+    public void switchChatMode(boolean isEnableChat) {
+        //控制聊天模式
+        Log.i("pq", "聊天禁止:" + isEnableChat);
+        this.isEnableChat = isEnableChat;
+    }
+
+    @Override
+    public void liveRoomOffline() {
+        //关闭直播间
+        ToastUtil.getInstance().show(this, "直播已结束");
+        finish();
+    }
+
+    @Override
+    public void liveGoodsChange(String jsonStr) {
+        //直播间商品发生变化
+        if (isDestroyed() || isFinishing()) {
+            return;
+        }
+        if (mShopCarDialog != null) {
+            mShopCarDialog.changeGoods(jsonStr);
+        }
+    }
+
+    /**
+     * @param rcUserSeatResponseMessage
+     */
+    @Override
+    public void seatResponse(RCUserSeatResponseMessage rcUserSeatResponseMessage) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (rcUserSeatResponseMessage == null || !isOwn(rcUserSeatResponseMessage.getAudienceId())) {
+            return;
+        }
+        if (rcUserSeatResponseMessage != null) {
+            int type = rcUserSeatResponseMessage.getType();
+            if (type == LiveRoomMsgConstants.MIC_RESPONSE_AGREE) {
+                //主播同意
+                if (presenter != null) {
+                    presenter.joinMic();
+                }
+                return;
+            }
+            if (type == LiveRoomMsgConstants.MIC_RESPONSE_DISAGREE) {
+                //主播拒绝
+                ToastUtil.getInstance().show(LiveRoomActivity.this, getString(R.string.create_refuse_seat_tip));
+                return;
+            }
+        }
+    }
+
+    @Override
+    public void onSwitchRole(String userId, RCRTCLiveRole role) {
+        Log.i("pq", "onSwitchRole:" + userId);
+        if (role.getType() == RCRTCLiveRole.AUDIENCE.getType()) {
+            //主播身份切换观众身份 下麦
+            notifyMicContainerDel(userId);
+            return;
+        }
+    }
+
+    @Override
+    public void onUserJoinRoom(RCRTCRemoteUser rcrtcRemoteUser) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        Log.i("pq", "onUserJoinRoom:" + rcrtcRemoteUser.getUserId());
+        if (TextUtils.equals(rcrtcRemoteUser.getUserId(), createRoomId)) {
+            createRoomId = "";//重置一下createRoomId,防止创建者退出又进入,全局控制变量未刷新
+        }
+    }
+
+    @Override
+    public void onUserLeftRoomMic(RCRTCRemoteUser rcrtcRemoteUser) {
+        Log.i("pq", "onUserLeftRoomMic:" + rcrtcRemoteUser.getUserId());
+        if (rcrtcRemoteUser != null) {
+            notifyMicContainerDel(rcrtcRemoteUser.getUserId());
+        }
+    }
+
+    @Override
+    public void onUserOfflineRoomMic(RCRTCRemoteUser rcrtcRemoteUser) {
+        Log.i("pq", "onUserOfflineRoomMic:" + rcrtcRemoteUser.getUserId());
+        if (rcrtcRemoteUser != null) {
+            notifyMicContainerDel(rcrtcRemoteUser.getUserId());
+        }
+    }
+
+    @Override
+    public void syncMemberCount(String count) {
+        //同步成员数量
+        Log.i("pq", "syncMemberCount" + count);
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (mTvNumPeople != null) {
+            mTvNumPeople.setText(count + "人");
+        }
+    }
+
+    @Override
+    public void onUserKickOutMsg(RCUserKickOutMessage userKickOutMessage) {
+        //用户被踢出消息
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (userKickOutMessage == null || !isOwn(userKickOutMessage.getTargetId())) {
+            return;
+        }
+        String targetId = userKickOutMessage.getTargetId();
+        Log.i("pq", "receive kickOut msg targetId:" + targetId);
+        finish();
+    }
+
+    /**
+     * 控制连麦模式
+     *
+     * @param isEnableMic
+     */
+    @Override
+    public void changeMicControlMode(boolean isEnableMic) {
+        //禁止连麦模式
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        Log.i("pq", "receive mic mode control msg 禁麦模式:" + isEnableMic);
+        this.isEnableMic = isEnableMic;
+        if (isEnableMic) {
+            handleCloseMicEvent();
+            if (mLlMicContainer != null) {
+                mLlMicContainer.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mLlMicContainer.delAll();
+                    }
+                });
+            }
+        }
+    }
+
+    private void refresh() {
+        List<RCRTCVideoOutputStream> outputStreams = new ArrayList<>();
+        List<RCRTCVideoInputStream> input = new ArrayList<>();
+        List<RCRTCAudioInputStream> audioinputstream = new ArrayList<>();
+        presenter.getVideoStream(outputStreams, input, audioinputstream);
+        updateVideoView(outputStreams, input, audioinputstream);
+    }
+
+    @Override
+    public void subscribeAVStreamSuccess(List<RCRTCInputStream> inputStreams) {
+        if (inputStreams != null) {
+            refresh();
+        } else {
+            showEmptyStatusView();
+        }
+    }
+
+    @Override
+    public void onSubscribeFailed() {
+        //订阅流失败
+    }
+
+    @Override
+    public void setRoomData(LiveRoomInfoBean roomInfoBean) {
+        //保存房间信息
+        if (presenter != null) {
+            //通知加入房间成功
+            presenter.notifyJoinRoomAction(mRoomId, mUserId);
+        }
+    }
+
+    private void notifyMicContainerAdd(String userId, String userName) {
+        mLlMicContainer.post(new Runnable() {
+            @Override
+            public void run() {
+                String lastName = userName;
+                UserInfo targetUser = mLlMicContainer.getUserInfoIfExist(userId);
+                if (targetUser != null && !TextUtils.equals(targetUser.getName(), LiveRoomMicIconView.DEFAULT_NICK)) {
+                    lastName = targetUser.getName();
+                } else {
+                    if (TextUtils.isEmpty(lastName)) {
+                        //如果昵称为空,查询昵称
+                        if (presenter != null) {
+                            presenter.getUserInfoByUserId(userId);
+                        }
+                    }
+                }
+                mLlMicContainer.addMicUser(new UserInfo(userId, lastName, null));
+            }
+        });
+    }
+
+    private void notifyMicContainerDel(String userId) {
+        mLlMicContainer.post(new Runnable() {
+            @Override
+            public void run() {
+                mLlMicContainer.deleteMicUser(new UserInfo(userId, "", null));
+            }
+        });
+    }
+
+    /**
+     * 连麦成功-身份切换主播成功
+     */
+    @Override
+    public void onSeatMicSuccess() {
+        updateMicIcon(LiveRoomMsgConstants.MIC_STATUS_CONNECT_SUCCESS);
+        notifyMicContainerAdd(mUserId, UserHelper.getUserName());
+    }
+
+    /**
+     * 连麦失败
+     */
+    @Override
+    public void onSeatMicFail() {
+        updateMicIcon(LiveRoomMsgConstants.MIC_STATUS_NORMAL);
+    }
+
+    /**
+     * \
+     * 退出连麦成功
+     */
+    @Override
+    public void onExitSeatMicSuccess() {
+        updateMicIcon(LiveRoomMsgConstants.MIC_STATUS_NORMAL);
+        notifyMicContainerDel(mUserId);
+        if (presenter != null) {
+            presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_DOWN_SEAT_MIC);
+        }
+    }
+
+    /**
+     * 主播邀请上麦
+     *
+     * @param seatApplyMessage
+     */
+    @Override
+    public void onInviteSeatMic(RCUserSeatApplyMessage seatApplyMessage) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (seatApplyMessage == null || !isOwn(seatApplyMessage.getAudienceId())) {
+            return;
+        }
+        if (seatApplyMessage.getType() == LiveRoomMsgConstants.MIC_ACTION_INVITE_SEAT_BY_CREATE) {
+            //主讲人邀请观众上麦
+            showInviteSeatDialog();
+            return;
+
+        }
+        if (seatApplyMessage.getType() == LiveRoomMsgConstants.MIC_ACTION_CANCEL_INVITE_SEAT_BY_CREATE) {
+            //主讲人取消邀请观众上麦
+            if (mInviteSeatMicTipDialog != null) {
+                mInviteSeatMicTipDialog.dismiss();
+            }
+            ToastUtil.getInstance().show(LiveRoomActivity.this, getString(R.string.create_recall_seat_invite_tip));
+            return;
+        }
+
+        if (seatApplyMessage.getType() == LiveRoomMsgConstants.MIC_ACTION_CANCEL_SEAT_BY_CREATE) {
+            //主讲人讲观众抱下麦
+            ToastUtil.getInstance().show(LiveRoomActivity.this, getString(R.string.down_mic_by_create_tip));
+            if (presenter != null) {
+                presenter.exitMic();
+            }
+        }
+    }
+
+    @Override
+    public void onUserUnusualLogout(RCUserLogOutUnusualMessage loginOutUnusualMessage) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (loginOutUnusualMessage == null || !isOwn(loginOutUnusualMessage.getUserId())) {
+            return;
+        }
+        Log.i("pq", "unusual logout");
+        finish();
+    }
+
+    /**
+     * 暂停直播,进行下麦处理
+     */
+    @Override
+    public void onLivePause() {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        ToastUtil.getInstance().show(this, getString(R.string.live_is_pause_str));
+        handleCloseMicEvent();
+    }
+
+    /**
+     * 点赞数量同步
+     *
+     * @param addLikeMessage
+     */
+    @Override
+    public void onAddLikeMessage(Message message, RCUserSyncAddLikeCountMessage addLikeMessage) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (TextUtils.equals(message.getSenderUserId(), mUserId)) {
+            return;
+        }
+        if (addLikeMessage != null) {
+            if (mTvAddLikeCount != null && addLikeMessage != null) {
+//                int counts = addLikeMessage.getCounts();
+//                currentAddLikeCount += counts;
+                currentAddLikeCount = addLikeMessage.getCount();
+                updateAddLikeCountView();
+            }
+        }
+    }
+
+    /**
+     * 获取上麦用户信息成功
+     *
+     * @param friendInfoBean
+     */
+    @Override
+    public void getFriendInfoSuccess(FriendInfoBean friendInfoBean) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (mLlMicContainer != null) {
+            mLlMicContainer.addMicUser(new UserInfo(friendInfoBean.friendId, friendInfoBean.friendNickname, null));
+        }
+    }
+
+    @Override
+    public void onPublishSuccess() {
+        refresh();
+    }
+
+
+    /**
+     * 黑名单状态切换
+     *
+     * @param userId
+     * @param isAddBlack
+     */
+    @Override
+    public void changeBlackUserStatus(String userId, boolean isAddBlack) {
+        if (isFinishing() || isDestroyed()) {
+            return;
+        }
+        if (isOwn(userId)) {
+            isEnableAll = isAddBlack;
+            if (isEnableAll) {
+                //取消连麦
+                if (currentSeatStatus != LiveRoomMsgConstants.MIC_STATUS_NORMAL) {
+                    handleCloseMicEvent();
+                }
+            }
+            updateInputTip();
+        }
+    }
+
+    private boolean isOwn(String targetUserId) {
+        return TextUtils.equals(mUserId, targetUserId);
+    }
+
+    private void showInviteSeatDialog() {
+        if (mInviteSeatMicTipDialog == null) {
+            mInviteSeatMicTipDialog = new LiveRoomInviteSeatMicTipDialog(this);
+            mInviteSeatMicTipDialog.setViewClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (v.getId() == R.id.tv_sure) {
+                        //被邀请连麦->同意连麦
+                        if (presenter != null) {
+                            presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_CANCEL_SEAT_AGREE_RESPONSE);
+                            presenter.joinMic();
+                        }
+                    }
+                    if (v.getId() == R.id.tv_cancel) {
+                        //被邀请连麦->拒绝连麦
+                        if (presenter != null) {
+                            presenter.handleAction(LiveRoomMsgConstants.ACTION_SEND_CANCEL_SEAT_DISAGREE_RESPONSE);
+                        }
+                        //重置一下连麦状态
+                        handleCloseMicEvent();
+                    }
+                    mInviteSeatMicTipDialog.dismiss();
+                }
+            });
+        }
+        if (!mInviteSeatMicTipDialog.isShowing()) {
+            mInviteSeatMicTipDialog.show();
+        }
+        String defaultNick = "主讲人";
+        if (mRoomInfoBean != null && !TextUtils.isEmpty(mRoomInfoBean.speakerName)) {
+            defaultNick = mRoomInfoBean.speakerName;
+        }
+        mInviteSeatMicTipDialog.setContent(defaultNick);
+    }
+
+
+    public void updateVideoView(List<RCRTCVideoOutputStream> outputStreams, List<RCRTCVideoInputStream> inputStreams, List<RCRTCAudioInputStream> audioInputStreams) {
+        mFlLiveView.post(new Runnable() {
+            @Override
+            public void run() {
+                ArrayList<RCRTCVideoStream> videoStreams = new ArrayList<RCRTCVideoStream>();
+                videoStreams.addAll(outputStreams);
+                videoStreams.addAll(inputStreams);
+                ArrayList<RCRTCVideoView> list = new ArrayList<>();
+                ArrayList<String> otherAudioUserIds = new ArrayList<>();
+                boolean isNormalCreateAudioStatus = true;
+
+                //视频流
+                for (int i = 0; i < videoStreams.size(); i++) {
+                    RCRTCVideoStream rcrtcVideoStream = videoStreams.get(i);
+                    RCRTCVideoView rongRTCVideoView = new RCRTCVideoView(LiveRoomActivity.this);
+                    rcrtcVideoStream.setVideoView(rongRTCVideoView);
+                    list.add(rongRTCVideoView);
+                }
+
+                //音频流
+                for (int i = 0; i < audioInputStreams.size(); i++) {
+                    RCRTCAudioInputStream audioInputStream = audioInputStreams.get(i);
+                    if (audioInputStream.getMediaType() == RCRTCMediaType.AUDIO) {
+                        //音频流判断显示上麦用户
+                        String userId = audioInputStream.getUserId();
+                        if (TextUtils.equals(mUserId, userId)) {
+                            continue;
+                        }
+                        if (mRoomInfoBean != null) {
+                            if (!TextUtils.equals(mRoomInfoBean.speakerId, userId)) {
+                                otherAudioUserIds.add(userId);
+                            } else {
+                                //主播的音频流
+                                RCRTCResourceState resourceState = audioInputStream.getResourceState();
+                                isNormalCreateAudioStatus = resourceState == RCRTCResourceState.NORMAL;
+                            }
+                        }
+                    }
+                }
+
+                if (otherAudioUserIds.size() != 0) {
+                    mLlMicContainer.delAllExcludeOwn();
+                    for (int i = 0; i < otherAudioUserIds.size(); i++) {
+                        String onMicUserId = otherAudioUserIds.get(i);
+                        notifyMicContainerAdd(onMicUserId, "");
+                    }
+                } else {
+                    mLlMicContainer.delAllExcludeOwn();
+                }
+                if (list.size() != 0) {
+                    creatorIsCloseVideoStream = false;
+                    mViewLiveStatus.setVisibility(View.GONE);
+                    checkVideoViewManager();
+                    mVideoViewManager.update(list, 0, true);
+                } else {
+                    creatorIsCloseVideoStream = true;
+                    if (isNormalCreateAudioStatus) {
+                        showCloseVideoView();
+                    } else {
+                        //主播关闭了视频流,同时音频流的状态也不是normal状态时
+                        showRestView();
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * 检查VideoViewManager是否未null;
+     */
+    private void checkVideoViewManager() {
+        if (mVideoViewManager == null) {
+            mVideoViewManager = new VideoViewManager(mFlLiveView, mFlLiveView.getWidth(), mFlLiveView.getHeight());
+            mVideoViewManager.setRetryClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (presenter != null) {
+                        //重新订阅房间的流信息
+                        presenter.subscribeAVStream();
+                    }
+                }
+            });
+        }
+    }
+
+    private boolean findMainScreenStreams(String streamUserId, String streamTag) {
+        if (TextUtils.equals("screenshare", streamTag)) {
+            //屏幕共享流
+            return true;
+        }
+        if (TextUtils.equals(mRoomInfoBean.speakerId, streamUserId)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 当远端或本端视频流发生变化时全量更新ui
+     */
+    void updateVideoView(List<RCRTCInputStream> inputStreams) {
+        mFlLiveView.post(new Runnable() {
+            @Override
+            public void run() {
+                hideLoading();
+                ArrayList<RCRTCVideoView> list = new ArrayList<>();
+                ArrayList<String> otherAudioUserIds = new ArrayList<>();
+                boolean isNormalCreateAudioStatus = true;
+                if (null != inputStreams) {
+                    for (RCRTCInputStream i : inputStreams) {
+                        if (i.getMediaType() == RCRTCMediaType.VIDEO) {
+//                            if (mRoomInfoBean != null) {
+//                                if (TextUtils.equals(createRoomId, i.getUserId())) {
+//                                    Log.i("pq","已存在相同的流,无须重复渲染");
+//                                    return;
+//                                }
+//                            }
+                            RCRTCVideoInputStream j = (RCRTCVideoInputStream) i;
+                            RCRTCVideoView rongRTCVideoView = new RCRTCVideoView(LiveRoomActivity.this);
+                            j.setVideoView(rongRTCVideoView);
+                            createRoomId = j.getUserId();
+                            list.add(rongRTCVideoView);
+                        }
+
+                        if (i.getMediaType() == RCRTCMediaType.AUDIO) {
+                            //音频流判断显示上麦用户
+                            String userId = i.getUserId();
+                            if (TextUtils.equals(mUserId, userId)) {
+                                continue;
+                            }
+                            if (mRoomInfoBean != null) {
+                                if (!TextUtils.equals(mRoomInfoBean.speakerId, userId)) {
+                                    otherAudioUserIds.add(userId);
+                                } else {
+                                    //主播的音频流
+                                    RCRTCAudioInputStream rcrtcAudioInputStream = (RCRTCAudioInputStream) i;
+                                    RCRTCResourceState resourceState = rcrtcAudioInputStream.getResourceState();
+                                    isNormalCreateAudioStatus = resourceState == RCRTCResourceState.NORMAL;
+                                }
+                            }
+                        }
+                    }
+                }
+                if (otherAudioUserIds.size() != 0) {
+                    mLlMicContainer.delAllExcludeOwn();
+                    for (int i = 0; i < otherAudioUserIds.size(); i++) {
+                        String onMicUserId = otherAudioUserIds.get(i);
+                        notifyMicContainerAdd(onMicUserId, "");
+                    }
+                } else {
+                    mLlMicContainer.delAllExcludeOwn();
+                }
+                if (list.size() != 0) {
+                    creatorIsCloseVideoStream = false;
+                    mViewLiveStatus.setVisibility(View.GONE);
+                    RCRTCVideoView rcrtcVideoView = list.get(list.size() - 1);
+                    mFlLiveView.removeAllViews();
+//                    mFlLiveView.addView(rcrtcVideoView);
+                    rcrtcVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
+                    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+                    params.addRule(RelativeLayout.CENTER_IN_PARENT);
+                    // 将远端视图添加至布局
+                    mFlLiveView.addView(rcrtcVideoView, params);
+                } else {
+                    creatorIsCloseVideoStream = true;
+                    if (isNormalCreateAudioStatus) {
+                        showCloseVideoView();
+                    } else {
+                        //主播关闭了视频流,同时音频流的状态也不是normal状态时
+                        showRestView();
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        Log.i("LiveRoomActivity", "onSaveInstanceState");
+    }
+
+    @Override
+    public void onBackPressed() {
+        boolean permissionOverlay = FloatWindowHelper.requestOverlayPermission(this);
+        if (!permissionOverlay) {
+            showOpenOverlayPermissionTipDialog();
+        } else {
+            if (isFullScreen()) {
+                changeOrientation();
+            } else {
+                showExitLiveTipDialog();
+            }
+        }
+    }
+
+    /**
+     * 退出直播间提示弹窗
+     */
+    private void showExitLiveTipDialog() {
+        LiveRoomCloseTipDialog closeTipDialog = new LiveRoomCloseTipDialog(this);
+        closeTipDialog.setConfirmClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                finish();
+            }
+        });
+        closeTipDialog.show();
+    }
+
+    private void showOpenOverlayPermissionTipDialog() {
+        OpenOverlayPermissionTipDialog overlayPermissionTipDialog = new OpenOverlayPermissionTipDialog(this);
+        overlayPermissionTipDialog.setConfirmClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                overlayPermissionTipDialog.dismiss();
+                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
+                startActivityForResult(intent, FloatWindowHelper.REQUEST_OVERLAY_CODE);
+            }
+        });
+        overlayPermissionTipDialog.show();
+        overlayPermissionTipDialog.setCancelClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                overlayPermissionTipDialog.dismiss();
+                finish();
+            }
+        });
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+//        String str =   savedInstanceState.getString("key");
+        Log.i("LiveRoomActivity", "onRestoreInstanceState");
+    }
+
+
+    private int getCurrentOrientation() {
+        return getResources().getConfiguration().orientation;
+    }
+
+    private boolean isFullScreen() {
+        return getCurrentOrientation() == Configuration.ORIENTATION_LANDSCAPE;
+    }
+
+
+    private void startFloatWindowService() {
+        boolean hasPermission = FloatWindowHelper.requestOverlayPermission(this);
+        if (hasPermission) {
+            if (mVideoViewManager != null && mVideoViewManager.getAllVideoViews() != null && mVideoViewManager.getAllVideoViews().size() > 0) {
+                Intent intent = new Intent(this, FloatingWindowService.class);
+                initServiceConnection();
+                bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+            }
+        }
+    }
+
+    private void initServiceConnection() {
+        if (serviceConnection == null) {
+            serviceConnection = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    if (service instanceof FloatingWindowService.MyBinder) {
+                        FloatingWindowService.MyBinder mBinder = (FloatingWindowService.MyBinder) service;
+                        if (mVideoViewManager != null) {
+                            ArrayList<RCRTCVideoView> allVideoViews = mVideoViewManager.getAllVideoViews();
+                            mBinder.addVideoView(allVideoViews);
+                        }
+                        mBinder.setOnEventListener(new FloatingWindowService.OnEventListener() {
+                            @Override
+                            public void onServiceDestroy() {
+                                if (mVideoViewManager != null) {
+                                    mVideoViewManager.update(mVideoViewManager.getAllVideoViews(), 0, false);
+                                }
+                            }
+
+                            @Override
+                            public void onUnbindService() {
+                                muteAll(true);
+                                unbindService();
+                            }
+                        });
+                    }
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    if (mVideoViewManager != null) {
+                        mVideoViewManager.update(mVideoViewManager.getAllVideoViews(), 0, false);
+                    }
+                }
+            };
+        }
+    }
+
+    /**
+     * 是否静音全部
+     *
+     * @param isMute
+     */
+    private void muteAll(boolean isMute) {
+        if (LiveEventHelper.getInstance().getRtcRoom() != null) {
+            RCRTCRoom rtcRoom = LiveEventHelper.getInstance().getRtcRoom();
+            if (rtcRoom.getLocalUser() != null) {
+                LiveEventHelper.getInstance().getRtcRoom().muteAllRemoteAudio(isMute);
+            }
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        unbindService();
+        //取消全部静音
+        muteAll(false);
+    }
+
+    /**
+     * 销毁悬浮窗service
+     */
+    private void unbindService() {
+        if (serviceConnection != null) {
+            try {
+                boolean isExist = AppUtils.isServiceWork(this, FloatingWindowService.CLASS_PATH);
+                if (isExist) {
+                    unbindService(serviceConnection);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        sendShowFloatWindowAction(SEND_APP_BACKGROUND_MSG);
+    }
+
+    private void sendShowFloatWindowAction(int what) {
+        android.os.Message message = android.os.Message.obtain();
+        message.what = what;
+        mHandler.sendMessageDelayed(message, SEND_SHOW_FLOAT_WINDOW_TIME);
+    }
+
+    /**
+     * 检查聊天模式
+     */
+    public boolean checkChatMode() {
+        if (isEnableAll) {
+            ToastUtil.getInstance().show(LiveRoomActivity.this, "您已被管理员禁言");
+            return true;
+        }
+        if (isEnableChat) {
+            ToastUtil.getInstance().show(LiveRoomActivity.this, "禁止聊天模式");
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 检查mic模式
+     */
+    public boolean checkMicMode() {
+        if (isEnableAll) {
+            ToastUtil.getInstance().show(LiveRoomActivity.this, "您已被管理员禁言");
+            return true;
+        }
+        if (isEnableMic) {
+            ToastUtil.getInstance().show(LiveRoomActivity.this, getString(R.string.enable_mic_mode_tip));
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onDestroy() {
+        if (presenter != null) {
+            //通知离开房间
+            presenter.notifyLeaveRoomAction();
+        }
+        super.onDestroy();
+        if (connectStatusListener != null) {
+            IMCenter.getInstance().removeConnectionStatusListener(connectStatusListener);
+        }
+        //取消动画
+        if (hideHeaderInfoAnim != null) {
+            hideHeaderInfoAnim.cancel();
+            hideHeaderInfoAnim = null;
+        }
+
+        if (showHeaderInfoAnim != null) {
+            showHeaderInfoAnim.cancel();
+            showHeaderInfoAnim = null;
+        }
+        SoftKeyboardUtil.unregisterSoftInputChangedListener(getWindow());
+        LiveRoomAnimatorHelper.getInstance().releaseAnimator();
+        LiveRoomAddLikeHelper.getInstance().release();
+        LiveEventHelper.getInstance().unRegister();
+        RCRTCAudioRouteManager.getInstance().unInit();
+        if (mHandler != null) {
+            mHandler.removeCallbacksAndMessages(null);
+        }
+        if (mVideoViewManager != null) {
+            mVideoViewManager.onRelease();
+        }
+    }
+
+    @Override
+    public void onSoftInputChanged(int height) {
+        Log.i("pq", "height" + height);
+        if (height == 0) {
+            //软键盘隐藏
+            Log.i("pq", "SoftInput hide");
+            if (mInputBarDialog != null && mInputBarDialog.isShowing()) {
+                mInputBarDialog.dismiss();
+            }
+        } else {
+            //软键盘弹出
+            Log.i("pq", "SoftInput show");
+        }
+    }
+}

+ 302 - 0
student/src/main/java/com/cooleshow/student/ui/live/floatPop/FloatWindowHelper.java

@@ -0,0 +1,302 @@
+package com.cooleshow.student.ui.live.floatPop;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+
+import com.cooleshow.base.common.AppManager;
+import com.cooleshow.base.utils.AppUtils;
+import com.cooleshow.base.utils.UiUtils;
+import com.cooleshow.base.utils.helper.QMUIDisplayHelper;
+import com.cooleshow.base.utils.helper.QMUIStatusBarHelper;
+import com.cooleshow.student.R;
+
+import java.util.List;
+
+import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
+import cn.rongcloud.rtc.core.RendererCommon;
+
+/**
+ * Author by pq, Date on 2022/5/13.
+ * 悬浮窗
+ */
+public class FloatWindowHelper implements View.OnTouchListener {
+    public static final int REQUEST_OVERLAY_CODE = 5000;
+    private Context mContext;
+    private View mContentView;
+    private WindowManager.LayoutParams mFloatParams;
+    private WindowManager mWindowManager;
+    private RelativeLayout mLiveContainer;
+    private int maxWidth;
+    private int maxHeight;
+    private int maxDragX = 0;//控制最大拖拽的坐标
+    private int maxDragY = 0;//控制最大拖拽的坐标
+    private int initX = 0;//初始位置坐标
+    private int initY = 0;//初始位置坐标
+    private OnEventListener mEventListener;
+
+    public FloatWindowHelper(Context context, OnEventListener eventListener) {
+        mContext = context;
+        this.mEventListener = eventListener;
+        int deviceWidth = QMUIDisplayHelper.getScreenWidth(context);
+        int deviceHeight = QMUIDisplayHelper.getScreenHeight(context);
+        int orientation = context.getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            maxWidth = deviceHeight / 2;
+            maxDragX = deviceHeight - maxWidth;
+            maxHeight = UiUtils.getHeightAtRatio16_9(context, maxWidth);
+            int actionBarHeight = QMUIDisplayHelper.getActionBarHeight(context);
+            int statusBarHeight = QMUIStatusBarHelper.getStatusbarHeight(context);
+            maxDragY = deviceWidth - actionBarHeight - statusBarHeight - maxHeight;
+            initX = maxWidth - 50;
+            initY = maxDragY - 300;
+        } else {
+            maxWidth = deviceWidth / 2;
+            maxDragX = deviceWidth - maxWidth;
+            maxHeight = UiUtils.getHeightAtRatio16_9(context, maxWidth);
+            maxDragY = deviceHeight - maxHeight;
+            initX = maxWidth - 50;
+            initY = maxDragY - 300;
+        }
+        initView();
+    }
+
+    /**
+     * 判断是否有悬浮窗权限
+     *
+     * @param activity
+     * @return
+     */
+    public static boolean requestOverlayPermission(Activity activity, int requestCode) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (!Settings.canDrawOverlays(activity)) {
+                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity.getPackageName()));
+                activity.startActivityForResult(intent, requestCode);
+                return false;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断是否有悬浮窗权限
+     *
+     * @param activity
+     * @return
+     */
+    public static boolean requestOverlayPermission(Activity activity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (!Settings.canDrawOverlays(activity)) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void initView() {
+        mContentView = LayoutInflater.from(mContext).inflate(R.layout.view_live_float_window_layout, null);
+        mLiveContainer = mContentView.findViewById(R.id.fl_live_container);
+        ImageView iv_close = mContentView.findViewById(R.id.iv_close);
+        mContentView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                setTopApp(mContext);
+            }
+        });
+        iv_close.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mEventListener != null) {
+                    mEventListener.onClose();
+                }
+            }
+        });
+    }
+
+    public void showFloatingWindowView(Context context) {
+        // 获取系统窗口管理服务
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        // 悬浮窗口参数设置及返回
+        mFloatParams = getParams();
+        // 设置窗口触摸移动事件
+        mContentView.setOnTouchListener(this);
+        // 悬浮窗生成
+        mWindowManager.addView(mContentView, mFloatParams);
+    }
+
+    private WindowManager.LayoutParams getParams() {
+        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        //设置悬浮窗口类型
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        } else {
+            layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+        }
+        //设置悬浮窗口属性
+        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+        //设置悬浮窗口透明
+        layoutParams.format = PixelFormat.TRANSLUCENT;
+        //设置悬浮窗口长宽数据
+        layoutParams.width = maxWidth;
+        layoutParams.height = maxHeight;
+        //设置悬浮窗显示位置
+        layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
+        layoutParams.x = initX;
+        layoutParams.y = initY;
+        return layoutParams;
+    }
+
+    //开始触控的坐标,移动时的坐标(相对于屏幕左上角的坐标)
+    int mTouchStartX = 0;
+    int mTouchStartY = 0;
+    //开始时的坐标和结束时的坐标(相对于自身控件的坐标)
+    int mStartX = 0;
+    int mStartY = 0;
+    //判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件
+    boolean isMove = false;
+
+    @Override
+    public boolean onTouch(View v, MotionEvent motionEvent) {
+        int action = motionEvent.getAction();
+        int x = (int) motionEvent.getX();
+        int y = (int) motionEvent.getY();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                isMove = false;
+                mTouchStartX = (int) motionEvent.getRawX();
+                mTouchStartY = (int) motionEvent.getRawY();
+                mStartX = x;
+                mStartY = y;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                int nowX = (int) motionEvent.getRawX();
+                int nowY = (int) motionEvent.getRawY();
+                Log.i("pq", "now:x=" + nowX + "y=" + nowX);
+                int offsetX = nowX - mTouchStartX;
+                int offsetY = nowY - mTouchStartY;
+                Log.i("pq", "start:x=" + mTouchStartX + "y=" + mTouchStartY);
+                mFloatParams.x += offsetX;
+                mFloatParams.y += offsetY;
+                if (mFloatParams.x < 0) {
+                    mFloatParams.x = 0;
+                }
+                if (mFloatParams.x > maxDragX) {
+                    mFloatParams.x = maxDragX;
+                }
+                if (mFloatParams.y < 0) {
+                    mFloatParams.y = 0;
+                }
+                if (mFloatParams.y > maxDragY) {
+                    mFloatParams.y = maxDragY;
+                }
+
+                Log.i("pq", "move:x=" + offsetX + "y=" + offsetY);
+                Log.i("pq", "moveAfter:x=" + mFloatParams.x + "y=" + mFloatParams.y);
+                mWindowManager.updateViewLayout(mContentView, mFloatParams);
+                mTouchStartX = nowX;
+                mTouchStartY = nowY;
+                float deltaX = x - mStartX;
+                float deltaY = y - mStartY;
+                if (Math.abs(deltaX) >= 5 || Math.abs(deltaY) >= 5) {
+                    isMove = true;
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                break;
+            default:
+                break;
+        }
+        //如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件
+        return isMove;
+    }
+
+    public void dismiss() {
+        if (mContext == null) {
+            return;
+        }
+        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        if (windowManager != null && mContentView != null && mContentView.getParent() != null) {
+            windowManager.removeView(mContentView);
+        }
+        if (mLiveContainer != null) {
+            mLiveContainer.removeAllViews();
+        }
+        this.mContext = null;
+    }
+
+    public void addVideoView(List<RCRTCVideoView> videoViews) {
+        if (videoViews != null && videoViews.size() > 0) {
+            mLiveContainer.removeAllViews();
+            for (int i = 0; i < videoViews.size(); i++) {
+                RCRTCVideoView videoView = videoViews.get(i);
+                ViewGroup parent = (ViewGroup) videoView.getParent();
+                if (parent != null) {
+                    parent.removeView(videoView);
+                }
+                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+                layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+                videoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
+                mLiveContainer.addView(videoView, layoutParams);
+            }
+        }
+    }
+
+    /**
+     * 返回前台
+     *
+     * @param context
+     */
+    public void setTopApp(Context context) {
+        if (AppUtils.isApplicationInBackground(context)) {
+            //获取ActivityManager
+            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+            //获得当前运行的task(任务)
+            List<ActivityManager.RunningTaskInfo> taskInfoList = null;
+            if (activityManager != null) {
+                taskInfoList = activityManager.getRunningTasks(100);
+            }
+            if (taskInfoList != null) {
+                for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) {
+                    //找到本应用的 task,并将它切换到前台
+                    if (taskInfo.topActivity != null && taskInfo.topActivity.getPackageName().equals(context.getPackageName())) {
+                        activityManager.moveTaskToFront(taskInfo.id, 0);
+                        break;
+                    }
+                }
+            }
+        } else {
+            Activity topActivity = AppManager.Companion.getInstance().currentActivity();
+            if (topActivity != null) {
+                topActivity.finish();
+            }
+        }
+    }
+
+    public interface OnEventListener {
+        void onClose();
+    }
+}

+ 92 - 0
student/src/main/java/com/cooleshow/student/ui/live/floatPop/FloatingWindowService.java

@@ -0,0 +1,92 @@
+package com.cooleshow.student.ui.live.floatPop;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.List;
+
+import androidx.annotation.Nullable;
+import cn.rongcloud.rtc.api.stream.RCRTCVideoView;
+
+/**
+ * Author by pq, Date on 2022/5/13.
+ */
+public class FloatingWindowService extends Service implements FloatWindowHelper.OnEventListener {
+    public static final String CLASS_PATH = "com.daya.studaya_android.ui.live.floatPop.FloatingWindowService";
+    private FloatWindowHelper mHelper;
+    private boolean isShowing = false;
+    private MyBinder mBinder;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHelper = new FloatWindowHelper(this, this);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Nullable
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mHelper != null && !isShowing) {
+            mHelper.showFloatingWindowView(this);
+            isShowing = true;
+        }
+        if (mBinder == null) {
+            mBinder = new MyBinder();
+        }
+        return mBinder;
+    }
+
+    @Override
+    public void onDestroy() {
+        // 移除浮动框
+        if (mHelper != null) {
+            mHelper.dismiss();
+        }
+        if (mBinder != null) {
+            if (mBinder.eventListener != null) {
+                mBinder.eventListener.onServiceDestroy();
+            }
+        }
+        super.onDestroy();
+        Log.i("pq", "FloatingWindowService onDestroy");
+    }
+
+    @Override
+    public void onClose() {
+        if (mBinder != null && mBinder.eventListener != null) {
+            mBinder.eventListener.onUnbindService();
+        }
+    }
+
+    public class MyBinder extends Binder {
+        private OnEventListener eventListener;
+
+        public FloatingWindowService getService() {
+            return FloatingWindowService.this;
+        }
+
+        public void addVideoView(List<RCRTCVideoView> videoViews) {
+            if (mHelper != null) {
+                mHelper.addVideoView(videoViews);
+            }
+        }
+
+        public void setOnEventListener(OnEventListener eventListener) {
+            this.eventListener = eventListener;
+        }
+    }
+
+    public interface OnEventListener {
+        void onServiceDestroy();
+
+        void onUnbindService();
+    }
+}

+ 24 - 0
student/src/main/java/com/cooleshow/student/utils/helper/LiveRTCEngineInitHelper.java

@@ -0,0 +1,24 @@
+package com.cooleshow.student.utils.helper;
+
+import com.cooleshow.student.App;
+import com.rong.io.live.config.LiveConfig;
+
+import cn.rongcloud.rtc.api.RCRTCConfig;
+import cn.rongcloud.rtc.api.RCRTCEngine;
+
+/**
+ * Author by pq, Date on 2022/4/12.
+ */
+public class LiveRTCEngineInitHelper {
+
+    public static void initRTC() {
+        RCRTCConfig.Builder rtcConfig = RCRTCConfig.Builder.create();
+        RCRTCEngine.getInstance().enableSpeaker(true);
+        RCRTCEngine.getInstance().init(App.context, rtcConfig.build());
+        LiveConfig.isNeedReInitRTC = false;
+    }
+
+    public static void setRTCSpeakerMode(boolean enable){
+        RCRTCEngine.getInstance().enableSpeaker(enable);
+    }
+}

+ 58 - 0
student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomCloseMicTipDialog.java

@@ -0,0 +1,58 @@
+package com.cooleshow.student.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.cooleshow.student.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class LiveRoomCloseMicTipDialog extends Dialog implements View.OnClickListener {
+
+    private TextView mTvSure;
+    private TextView mTvCancel;
+    private View.OnClickListener confirmClickListener;
+    private TextView mTvTip;
+
+    public LiveRoomCloseMicTipDialog(@NonNull Context context) {
+        super(context, R.style.DialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_room_close_mic_layout);
+        mTvSure = findViewById(R.id.tv_sure);
+        mTvCancel = findViewById(R.id.tv_cancel);
+        mTvTip = findViewById(R.id.tv_tip);
+        mTvCancel.setOnClickListener(this);
+        if (confirmClickListener != null) {
+            mTvSure.setOnClickListener(confirmClickListener);
+        }
+    }
+
+    public void setContent(String content) {
+        if (mTvTip != null) {
+            mTvTip.setText(content);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_cancel:
+                dismiss();
+                break;
+        }
+    }
+
+    public void setConfirmClickListener(View.OnClickListener confirmClickListener) {
+        this.confirmClickListener = confirmClickListener;
+    }
+}

+ 66 - 0
student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomClosePageOnMicTipDialog.java

@@ -0,0 +1,66 @@
+package com.cooleshow.student.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.cooleshow.student.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class LiveRoomClosePageOnMicTipDialog extends Dialog implements View.OnClickListener {
+
+    private TextView mTvSure;
+    private TextView mTvCancel;
+    private View.OnClickListener confirmClickListener;
+    private TextView mTvTip;
+    private TextView mTvContent;
+
+    public LiveRoomClosePageOnMicTipDialog(@NonNull Context context) {
+        super(context, R.style.DialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_room_close_page_layout);
+        mTvSure = findViewById(R.id.tv_sure);
+        mTvCancel = findViewById(R.id.tv_cancel);
+        mTvTip = findViewById(R.id.tv_tip);
+        mTvContent = findViewById(R.id.tv_content);
+        mTvCancel.setOnClickListener(this);
+        if (confirmClickListener != null) {
+            mTvSure.setOnClickListener(confirmClickListener);
+        }
+    }
+
+    public void setTitle(String title) {
+        if (mTvTip != null) {
+            mTvTip.setText(title);
+        }
+    }
+
+    public void setContent(String content) {
+        if (mTvContent != null) {
+            mTvContent.setText(content);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_cancel:
+                dismiss();
+                break;
+        }
+    }
+
+    public void setConfirmClickListener(View.OnClickListener confirmClickListener) {
+        this.confirmClickListener = confirmClickListener;
+    }
+}

+ 58 - 0
student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomCloseTipDialog.java

@@ -0,0 +1,58 @@
+package com.cooleshow.student.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.cooleshow.student.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class LiveRoomCloseTipDialog extends Dialog implements View.OnClickListener {
+
+    private TextView mTvExit;
+    private TextView mTvCancel;
+    private View.OnClickListener confirmClickListener;
+    private TextView mTvTip;
+
+    public LiveRoomCloseTipDialog(@NonNull Context context) {
+        super(context, R.style.DialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_room_close_layout);
+        mTvExit = findViewById(R.id.tv_exit);
+        mTvCancel = findViewById(R.id.tv_cancel);
+        mTvTip = findViewById(R.id.tv_tip);
+        mTvCancel.setOnClickListener(this);
+        if (confirmClickListener != null) {
+            mTvExit.setOnClickListener(confirmClickListener);
+        }
+    }
+
+    public void setContent(String content) {
+        if (mTvTip != null) {
+            mTvTip.setText(content);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_cancel:
+                dismiss();
+                break;
+        }
+    }
+
+    public void setConfirmClickListener(View.OnClickListener confirmClickListener) {
+        this.confirmClickListener = confirmClickListener;
+    }
+}

+ 50 - 0
student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomInviteSeatMicTipDialog.java

@@ -0,0 +1,50 @@
+package com.cooleshow.student.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.cooleshow.student.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class LiveRoomInviteSeatMicTipDialog extends Dialog {
+
+    private TextView mTvSure;
+    private TextView mTvCancel;
+    private View.OnClickListener viewClickListener;
+    private TextView mTvContent;
+
+    public LiveRoomInviteSeatMicTipDialog(@NonNull Context context) {
+        super(context, R.style.DialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_room_invite_mic_layout);
+        mTvSure = findViewById(R.id.tv_sure);
+        mTvCancel = findViewById(R.id.tv_cancel);
+        mTvContent = findViewById(R.id.tv_content);
+        if (viewClickListener != null) {
+            mTvSure.setOnClickListener(viewClickListener);
+            mTvCancel.setOnClickListener(viewClickListener);
+        }
+    }
+
+    public void setContent(String nickName) {
+        if (mTvContent != null) {
+            String content = getContext().getString(R.string.invite_seat_content_tip, nickName);
+            mTvContent.setText(content);
+        }
+    }
+
+    public void setViewClickListener(View.OnClickListener confirmClickListener) {
+        this.viewClickListener = confirmClickListener;
+    }
+}

+ 339 - 0
student/src/main/java/com/cooleshow/student/widgets/dialog/LiveRoomShopCarDialog.java

@@ -0,0 +1,339 @@
+package com.cooleshow.student.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.webkit.GeolocationPermissions;
+import android.webkit.JavascriptInterface;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.TextView;
+
+
+import com.cooleshow.base.common.WebConstants;
+import com.cooleshow.base.utils.LogUtils;
+import com.cooleshow.base.utils.ToastUtil;
+import com.cooleshow.base.utils.ToastUtils;
+import com.cooleshow.student.BuildConfig;
+import com.cooleshow.student.R;
+import com.cooleshow.student.api.APIService;
+import com.cooleshow.usercenter.helper.UserHelper;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import androidx.annotation.NonNull;
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.ObservableEmitter;
+import io.reactivex.rxjava3.core.ObservableOnSubscribe;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+
+/**
+ * Author by pq, Date on 2022/5/16.
+ */
+public class LiveRoomShopCarDialog extends Dialog {
+    public static final String OPEN_DETAIL = "openUrl";
+
+    private WebView mWebView;
+    private String authorization;
+    private TextView mTvTitle;
+    private OnEventListener mEventListener;
+    private String webUrl;
+
+    public LiveRoomShopCarDialog(@NonNull Context context) {
+        super(context, R.style.MyBottomDialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_live_room_shop_car_layout);
+        Window window = getWindow();
+        //设置dialog在屏幕底部
+        window.setGravity(Gravity.BOTTOM);
+        //设置dialog弹出时的动画效果,从屏幕底部向上弹出
+        window.setWindowAnimations(com.cooleshow.base.R.style.BottomAnimation);
+        window.getDecorView().setPadding(0, 0, 0, 0);
+        //获得window窗口的属性
+        WindowManager.LayoutParams lp = window.getAttributes();
+        //设置窗口宽度为充满全屏
+        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+        //设置窗口高度为包裹内容
+        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        lp.horizontalMargin = 0;
+        lp.verticalMargin = 0;
+        //将设置好的属性set回去
+        window.setAttributes(lp);
+
+        mWebView = findViewById(R.id.webView);
+        mTvTitle = findViewById(R.id.tv_title);
+        initWebSetting();
+    }
+
+    public void changeGoods(String str) {
+        JSONObject jsonObject = new JSONObject();
+        try {
+            jsonObject.put("api", "cardChange");
+            JSONArray json = new JSONArray(str);
+            jsonObject.put("content", json);
+            String message = jsonObject.toString();
+            Log.i("LiveRoomShopCarDialog", "jsonObject:" + jsonObject.toString());
+            mWebView.evaluateJavascript("postMessage('" + message + "','*')", new ValueCallback<String>() {
+                @Override
+                public void onReceiveValue(String s) {
+                }
+            });
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void setRoomId(String roomId) {
+        if (TextUtils.isEmpty(webUrl)) {
+            webUrl = WebConstants.STUDENT_LIVE_SHOP_CAR_URL + "?liveId=" + roomId;
+            if (!TextUtils.isEmpty(authorization)) {
+                try {
+                    authorization = URLEncoder.encode(authorization, "UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                }
+                boolean status = webUrl.contains("?");
+                if (status) {
+                    webUrl = (webUrl + "&Authorization=" + authorization);
+                } else {
+                    webUrl = (webUrl + "?Authorization=" + authorization);
+                }
+            }
+            mWebView.loadUrl(webUrl);
+        }
+    }
+
+    private void initWebSetting() {
+        mWebView.addJavascriptInterface(new Object() {
+            @JavascriptInterface
+            public void postMessage(String message) {
+                handleMessage(message);
+            }
+        }, "DAYA");
+        authorization = UserHelper.getUserToken();
+
+        mWebView.setWebViewClient(new WebClient());
+        mWebView.setWebChromeClient(new MyWebChromeClient());
+
+        //声明WebSettings子类
+        WebSettings webSettings = mWebView.getSettings();
+        webSettings.setUserAgentString(webSettings.getUserAgentString() + ";DAYAAPPA");
+        webSettings.setGeolocationDatabasePath(getContext().getFilesDir().getPath());
+        webSettings.setGeolocationEnabled(true);
+        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
+        //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
+        webSettings.setJavaScriptEnabled(true);
+        webSettings.setMediaPlaybackRequiresUserGesture(false);//false允许自动播放音视频
+        //是否启用缓存
+        webSettings.setAppCacheEnabled(true);
+
+        // 开启DOM缓存,默认状态下是不支持LocalStorage的
+        webSettings.setDomStorageEnabled(true);
+        // 开启数据库缓存
+        webSettings.setDatabaseEnabled(true);
+        // 地址跨域导致视频预览图片加载不出来 无法播放:
+        webSettings.setAllowUniversalAccessFromFileURLs(false);
+        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
+
+        //设置自适应屏幕,两者合用
+        webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
+        webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
+        //缩放操作
+        webSettings.setSupportZoom(false); //支持缩放,默认为true。是下面那个的前提。
+        // 设置允许JS弹窗
+        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
+        //其他细节操作
+        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); //关闭webview中缓存
+        webSettings.setAllowFileAccess(true); //设置可以访问文件
+        webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
+        webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
+        webSettings.setDefaultTextEncodingName("UTF-8");//设置编码格式
+
+        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);  //富文本适配
+        webSettings.setAppCacheMaxSize(Long.MAX_VALUE);
+        webSettings.setAppCachePath(getContext().getDir("appcache", 0).getPath());
+        webSettings.setDatabasePath(getContext().getDir("databases", 0).getPath());
+        webSettings.setGeolocationDatabasePath(getContext().getDir("geolocation", 0)
+                .getPath());
+        webSettings.setPluginState(WebSettings.PluginState.ON_DEMAND);
+        if (BuildConfig.DEBUG) {
+            mWebView.setWebContentsDebuggingEnabled(true);
+        }
+        webSettings.setTextZoom(100);//设置字体默认的缩放比例,以避免手机系统的字体修改对页面字体及布局造成影响。
+        mWebView.setHorizontalScrollBarEnabled(false);
+        mWebView.setVerticalScrollBarEnabled(false);
+        mWebView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
+
+        });
+    }
+
+    private void handleMessage(String message) {
+        Observable.create(new ObservableOnSubscribe<String>() {
+            @Override
+            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
+                JSONObject jsonObject = new JSONObject(message);
+                String api = jsonObject.getString("api");
+                if (TextUtils.equals(api, OPEN_DETAIL)) {
+                    JSONObject content = jsonObject.getJSONObject("content");
+                    String url = content.optString("url");
+                    if (!TextUtils.isEmpty(url)) {
+                        emitter.onNext(url);
+                    }
+                }
+            }
+        }).subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Observer<String>() {
+                    @Override
+                    public void onSubscribe(Disposable d) {
+
+                    }
+
+                    @Override
+                    public void onNext(String url) {
+                        if (mEventListener != null) {
+                            mEventListener.onOpenDetail(url);
+                        }
+                    }
+
+                    @Override
+                    public void onError(Throwable e) {
+                        e.printStackTrace();
+                    }
+
+                    @Override
+                    public void onComplete() {
+
+                    }
+                });
+    }
+
+
+    private class WebClient extends WebViewClient {
+        //页面开始载入时调用
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            LogUtils.e("onPageStarted:" + url);
+        }
+
+        //页面载入结束时调用
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            if (!TextUtils.isEmpty(authorization)) {
+                String js = "window.localStorage.setItem('Authorization','" + authorization + "');";
+                String jsUrl = "javascript:(function({var localStorage = window.localStorage; localStorage.setItem('Authorization','" + authorization + "') })()";
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                    view.evaluateJavascript(js, null);
+                } else {
+                    view.loadUrl(jsUrl);
+                    view.reload();
+                }
+            }
+
+            LogUtils.e("onPageFinished:" + url);
+            LogUtils.e("Authorization:" + authorization);
+        }
+
+        //截取url请求,在当前视图加载,避免在跳转到自带浏览器
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView view, String request) {
+            if (!(request.startsWith("http://") || request.startsWith("https://"))) {
+                try {
+                    Intent intent = new Intent();
+                    intent.setAction(Intent.ACTION_VIEW);
+                    intent.setData(Uri.parse(request));
+                    getContext().startActivity(intent);
+                } catch (ActivityNotFoundException e) {
+                    ToastUtil.getInstance().show(getContext(), "未安装该应用");
+                }
+                return true;
+            } else {
+                view.loadUrl(request);
+                return true;
+            }
+        }
+
+        //处理报错信息
+        @Override
+        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+            super.onReceivedError(view, request, error);
+        }
+    }
+
+
+    private class MyWebChromeClient extends WebChromeClient {
+        public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
+            callback.invoke(origin, true, false);
+        }
+
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            LogUtils.e(newProgress + "");
+        }
+
+        @Override
+        public void onReceivedTitle(WebView view, String title) {
+            super.onReceivedTitle(view, title);
+        }
+
+        // Android > 5.0.1
+        public boolean onShowFileChooser(
+                WebView webView, ValueCallback<Uri[]> filePathCallback,
+                FileChooserParams fileChooserParams) {
+            return true;
+        }
+
+
+        // 点击全屏按钮时,调用的方法
+        @Override
+        public void onShowCustomView(View view, CustomViewCallback callback) {
+            super.onShowCustomView(view, callback);
+        }
+
+        // 取消全屏调用的方法
+        @Override
+        public void onHideCustomView() {
+            super.onHideCustomView();
+        }
+    }
+
+
+    public void setOnEventListener(OnEventListener listener) {
+        this.mEventListener = listener;
+    }
+
+    public interface OnEventListener {
+        void onOpenDetail(String url);
+    }
+}

+ 64 - 0
student/src/main/java/com/cooleshow/student/widgets/dialog/OpenOverlayPermissionTipDialog.java

@@ -0,0 +1,64 @@
+package com.cooleshow.student.widgets.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.cooleshow.student.R;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class OpenOverlayPermissionTipDialog extends Dialog implements View.OnClickListener {
+
+    private TextView mTvSure;
+    private TextView mTvCancel;
+    private View.OnClickListener confirmClickListener;
+    private TextView mTvTip;
+
+    public OpenOverlayPermissionTipDialog(@NonNull Context context) {
+        super(context, R.style.DialogStyle);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_open_overlay_permission_tip_layout);
+        mTvSure = findViewById(R.id.tv_sure);
+        mTvCancel = findViewById(R.id.tv_cancel);
+        mTvTip = findViewById(R.id.tv_tip);
+        mTvCancel.setOnClickListener(this);
+        if (confirmClickListener != null) {
+            mTvSure.setOnClickListener(confirmClickListener);
+        }
+    }
+
+    public void setContent(String content) {
+        if (mTvTip != null) {
+            mTvTip.setText(content);
+        }
+    }
+
+    public void setCancelClickListener(View.OnClickListener listener) {
+        if (mTvCancel != null) {
+            mTvCancel.setOnClickListener(listener);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_cancel:
+                dismiss();
+                break;
+        }
+    }
+
+    public void setConfirmClickListener(View.OnClickListener confirmClickListener) {
+        this.confirmClickListener = confirmClickListener;
+    }
+}

+ 61 - 0
student/src/main/java/com/cooleshow/student/widgets/helper/LiveRoomAddLikeHelper.java

@@ -0,0 +1,61 @@
+package com.cooleshow.student.widgets.helper;
+
+import android.os.Handler;
+import android.os.Looper;
+
+/**
+ * Author by pq, Date on 2022/4/11.
+ */
+public class LiveRoomAddLikeHelper {
+    private volatile static LiveRoomAddLikeHelper mHelper;
+    // 两次点击按钮之间的点击间隔不能少于200毫秒
+    private static final int MIN_CLICK_DELAY_TIME = 200;
+    private static Handler sHandler = new Handler(Looper.getMainLooper());
+
+    private LiveRoomAddLikeHelper() {
+
+    }
+
+    public static LiveRoomAddLikeHelper getInstance() {
+        if (mHelper == null) {
+            synchronized (LiveRoomAddLikeHelper.class) {
+                if (mHelper == null) {
+                    mHelper = new LiveRoomAddLikeHelper();
+                }
+            }
+        }
+        return mHelper;
+    }
+
+    private static long lastClickTime;
+    private int tempAddLikeCount = 0;
+
+    public void handleClick(OnAddLikeResultCallBack addLikeResultCallBack) {
+        lastClickTime = System.currentTimeMillis();
+        sHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                long currentTime = System.currentTimeMillis();
+                if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
+                    tempAddLikeCount += 1;
+                    if (addLikeResultCallBack != null) {
+                        addLikeResultCallBack.onResult(tempAddLikeCount);
+                    }
+                    tempAddLikeCount = 0;
+                } else {
+                    tempAddLikeCount += 1;
+                }
+            }
+        }, MIN_CLICK_DELAY_TIME + 10);
+    }
+
+    public interface OnAddLikeResultCallBack {
+        void onResult(int count);
+    }
+
+    public void release() {
+        if (sHandler != null) {
+            sHandler.removeCallbacksAndMessages(null);
+        }
+    }
+}

+ 107 - 0
student/src/main/java/com/cooleshow/student/widgets/helper/LiveRoomAnimatorHelper.java

@@ -0,0 +1,107 @@
+package com.cooleshow.student.widgets.helper;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.LinearInterpolator;
+import android.widget.ImageView;
+
+
+import com.cooleshow.student.R;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+/**
+ * Author by pq, Date on 2022/4/7.
+ */
+public class LiveRoomAnimatorHelper {
+    private volatile static LiveRoomAnimatorHelper mHelper;
+
+    private static final int[] addLikeIcons = new int[]{R.drawable.icon_live_room_add_like_1,
+            R.drawable.icon_live_room_add_like_2, R.drawable.icon_live_room_add_like_3,
+            R.drawable.icon_live_room_add_like_4, R.drawable.icon_live_room_add_like_5,
+            R.drawable.icon_live_room_add_like_6, R.drawable.icon_live_room_add_like_7,
+            R.drawable.icon_live_room_add_like_8};
+    private ArrayList<View> addLikeAnimaViews = new ArrayList<>();
+    private ArrayList<AnimatorSet> addLikeAnimas = new ArrayList<>();
+
+    private LiveRoomAnimatorHelper(){
+
+    }
+
+    public static  LiveRoomAnimatorHelper getInstance(){
+        if(mHelper == null){
+            synchronized (LiveRoomAnimatorHelper.class){
+                if(mHelper == null){
+                    mHelper = new LiveRoomAnimatorHelper();
+                }
+            }
+        }
+        return mHelper;
+    }
+
+    public void startAddLikeAnimation(Context context, ViewGroup viewGroup) {
+        ImageView imageView = new ImageView(context);
+        Random random = new Random();
+        int i = random.nextInt(8);
+        imageView.setImageResource(addLikeIcons[i]);
+        imageView.setId(View.generateViewId());
+        ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
+        View targetView = viewGroup.findViewById(R.id.icon_add_like);
+        layoutParams.leftToLeft = targetView.getId();
+        layoutParams.rightToRight = targetView.getId();
+        layoutParams.bottomToTop = targetView.getId();
+        viewGroup.addView(imageView, layoutParams);
+        addLikeAnimaViews.add(imageView);
+        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 20f, 0f, -20f, 0f, 20f, 0f, -20f);
+        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "translationY", 0f, -600f);
+        ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.2f);
+        AnimatorSet animatorSet = new AnimatorSet();
+        LinearInterpolator linearInterpolator = new LinearInterpolator();
+        animatorSet.setInterpolator(linearInterpolator);
+        animatorSet.play(objectAnimator).with(objectAnimator2).with(objectAnimator3);
+        animatorSet.setDuration(2000);
+        animatorSet.start();
+        addLikeAnimas.add(animatorSet);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                if (viewGroup != null) {
+                    viewGroup.removeView(imageView);
+                }
+                if (addLikeAnimaViews != null) {
+                    addLikeAnimaViews.remove(imageView);
+                }
+                if (addLikeAnimas != null) {
+                    addLikeAnimas.remove(animatorSet);
+                }
+            }
+        });
+    }
+
+    public void releaseAnimator(){
+        if (addLikeAnimaViews != null) {
+            for (int i = 0; i < addLikeAnimaViews.size(); i++) {
+                View view = addLikeAnimaViews.get(i);
+                view.clearAnimation();
+            }
+        }
+        if (addLikeAnimas != null) {
+            for (int i = 0; i < addLikeAnimas.size(); i++) {
+                AnimatorSet animatorSet = addLikeAnimas.get(i);
+                animatorSet.cancel();
+                animatorSet = null;
+            }
+        }
+    }
+
+
+}

BIN
student/src/main/res/drawable-xhdpi/icon_add_like.png


BIN
student/src/main/res/drawable-xhdpi/icon_close_gray.png


BIN
student/src/main/res/drawable-xhdpi/icon_like_num.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_msg_room_author.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_1.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_2.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_3.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_4.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_5.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_6.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_7.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_add_like_8.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_chat_speak.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_close_video.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_number_people.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_room_rest_bg.png


BIN
student/src/main/res/drawable-xhdpi/icon_live_shop_car_header.png


BIN
student/src/main/res/drawable-xhdpi/icon_mic_conected.png


BIN
student/src/main/res/drawable-xhdpi/icon_mic_connecting.png


BIN
student/src/main/res/drawable-xhdpi/icon_mic_unconnect.png


BIN
student/src/main/res/drawable-xhdpi/icon_video_orientation_convert.png


BIN
student/src/main/res/drawable-xxhdpi/icon_add_like.png


BIN
student/src/main/res/drawable-xxhdpi/icon_close_gray.png


BIN
student/src/main/res/drawable-xxhdpi/icon_like_num.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_msg_room_author.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_1.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_2.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_3.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_4.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_5.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_6.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_7.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_add_like_8.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_chat_speak.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_close_video.png


BIN
student/src/main/res/drawable-xxhdpi/icon_live_room_number_people.png


Some files were not shown because too many files changed in this diff