android视频通话悬浮窗的适配

前序

按项目交互要求,需要把视频通话界面,缩小至悬浮窗显示,基本实现思路这个比较好想,就是启用一个service,在里面用WindowManager去addView来展示悬浮窗画面。基本效果是有了,但填坑之路才刚开始。。

坑一:WindowManager.LayoutParam.type的选取

选择TYPE_TOAST,如果期间有toast弹出,在android7.1.1会崩溃

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

注意:在android9.0以上就算按照上面方法设置,如果不提前授予悬浮窗权限,也会崩溃

坑二:SingleInstance和onActivityResult搭配问题

当处于悬浮窗口时,此时通话界面会推到后台,要调用moveTaskToBack(true),如果通话的Activity的启动模式不设置为SingleInstance,就会导致整个应用退到后台,不是我们想要的效果,为了只把VIdeoCallActivity(通话界面)退到后台,那么此界面就必须得在单独的一个栈里,所以要设置为SingleInstance。
用一个启动模式为SingleInstance的Activity去打开一个界面,在onActivityResult是拿不到结果的,所以只能用startActivity,然后再VIdeoCallActivity判断悬浮是否已打开,如果打开,则悬浮显示。

坑三:跳转开启悬浮窗设置界面的机型适配问题

适配了市面上大部分厂商机型,小米、华为、魅族、oppo、vivo、360、锤子
跳转开启权限工具类

悬浮窗服务FloatVideoWindowService

 FloatVideoWindowService extends Service {

    private static final String TAG = "FloatVideoWindowService";

    private WindowManager mWindowManager;
    private WindowManager.LayoutParams wmParams;

    private View mFloatingLayout;
    private RelativeLayout smallSizePreviewLayout;

    private BaseVCManager mVCManager;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public class MyBinder extends Binder {
        public FloatVideoWindowService getService() {
            return FloatVideoWindowService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initWindow();//设置悬浮窗基本参数(位置、宽高等)
        initFloating();//悬浮框点击事件的处理
        mVCManager = VideoChatStateManager.getInstance().getManager();
        initSurface();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        LogUtil.d(TAG, "onDestroy");
        if (mFloatingLayout != null) {
            // 移除悬浮窗口
            mWindowManager.removeView(mFloatingLayout);
        }
    }

    /**
     * 初始化预览窗口
     */
    private synchronized void initSurface() {
        if (mVCManager != null) {
            mVCManager.switchToFloatWindow(this, smallSizePreviewLayout);
        }
    }

    /**
     * 设置悬浮框基本参数(位置、宽高等)
     */
    private void initWindow() {
        mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        wmParams = getParams();
        // 悬浮窗默认显示以左上角为起始坐标
        wmParams.gravity = Gravity.RIGHT | Gravity.TOP;
        //悬浮窗的开始位置,因为设置的是从左上角开始,所以屏幕左上角是x=0;y=0
        wmParams.x = AndroidUtil.dpToPx(this, 10);
        wmParams.y = 110;
        //得到容器,通过这个inflater来获得悬浮窗控件
        LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
        // 获取浮动窗口视图所在布局
        mFloatingLayout = inflater.inflate(R.layout.view_videochat_services_float_layout, null);
        // 添加悬浮窗的视图
        mWindowManager.addView(mFloatingLayout, wmParams);
    }


    private WindowManager.LayoutParams getParams() {
        wmParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        //wmParams.windowAnimations = R.style.default_style;
        //设置可以显示在状态栏上
        wmParams.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;

        int fullCropWidth = ScreenUtil.getPxWidth(this);
        int cropHeight = fullCropWidth * 4 / 3;

        //设置悬浮窗口长宽数据
        wmParams.width = (int) (fullCropWidth * 0.26);
        wmParams.height = (int) (cropHeight * 0.26);
        return wmParams;
    }

    private void initFloating() {
        smallSizePreviewLayout = mFloatingLayout.findViewById(R.id.small_size_preview);

        //悬浮框点击事件
        smallSizePreviewLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //HomeApi.startHomeActivity(FloatVideoWindowService.this);
                Intent intent = new Intent(new Intent(FloatVideoWindowService.this, VideoChatActivity.class));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            }
        });

        //悬浮框触摸事件,设置悬浮框可拖动
        smallSizePreviewLayout.setOnTouchListener(new FloatingListener());
    }

    /**
     * 开始触控的坐标,移动时的坐标(相对于屏幕左上角的坐标)
     */
    private int mTouchStartX;
    private int mTouchStartY;
    /**
     * 开始时的坐标和结束时的坐标(相对于自身控件的坐标)
     */
    private int mStartX;
    private int mStartY;
    /**
     * 判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件
     */
    private boolean isMove;

    private class FloatingListener implements View.OnTouchListener {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    isMove = false;
                    mTouchStartX = (int) event.getRawX();
                    mTouchStartY = (int) event.getRawY();
                    mStartX = (int) event.getX();
                    mStartY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int mTouchCurrentX = (int) event.getRawX();
                    int mTouchCurrentY = (int) event.getRawY();
                    wmParams.x -= mTouchCurrentX - mTouchStartX;
                    wmParams.y += mTouchCurrentY - mTouchStartY;
                    mWindowManager.updateViewLayout(mFloatingLayout, wmParams);

                    mTouchStartX = mTouchCurrentX;
                    mTouchStartY = mTouchCurrentY;
                    break;
                case MotionEvent.ACTION_UP:
                    int mStopX = (int) event.getX();
                    int mStopY = (int) event.getY();
                    if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) {
                        isMove = true;
                    }
                    break;
                default:
                    LogUtil.d(TAG, "onTouch: other");
            }

            //如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件
            return isMove;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容