TRTCVideoViewLayout mTRTCVideoViewLayout = Constents.mVideoViewLayout;

TXCloudVideoView mLocalVideoView = mTRTCVideoViewLayout.getCloudVideoViewByUseId(currentBigUserId);

if (mLocalVideoView == null) {

mLocalVideoView = mTRTCVideoViewLayout.getCloudVideoViewByIndex(0);

}

if (ConstData.userid.equals(currentBigUserId)) {

TXCGLSurfaceView mTXCGLSurfaceView = mLocalVideoView.getGLSurfaceView();

if (mTXCGLSurfaceView != null && mTXCGLSurfaceView.getParent() != null) {

((ViewGroup) mTXCGLSurfaceView.getParent()).removeView(mTXCGLSurfaceView);

mTXCloudVideoView.addVideoView(mTXCGLSurfaceView);

}

} else {

TextureView mTextureView = mLocalVideoView.getVideoView();

if (mTextureView != null && mTextureView.getParent() != null) {

((ViewGroup) mTextureView.getParent()).removeView(mTextureView);

mTXCloudVideoView.addVideoView(mTextureView);

}

}

e. 我们上面说到要将服务Service的绑定与解绑与悬浮框的开启和关闭相结合,所以既然我们在服务的onCreate()方法中开启了悬浮框,那么就应该在其onDestroy()方法中对悬浮框进行关闭,关闭悬浮框的本质是将相关View给移除掉,在服务的onDestroy()方法中执行如下代码:

@Override

public void onDestroy() {

super.onDestroy();

if (mFloatingLayout != null) {

// 移除悬浮窗口

mWindowManager.removeView(mFloatingLayout);

mFloatingLayout = null;

Constents.isShowFloatWindow = false;

}

}

f. 服务的绑定方式有bindService和startService两种,使用不同的绑定方式其生命周期也会不一样,已知我们需要让悬浮框在视频通话activity finish掉的时候也顺便关掉,那么理所当然我们就应该采用bind方式来启动服务,让他的生命周期跟随他的开启者,也即是跟随开启它的activity生命周期。

intent = new Intent(this, FloatVideoWindowService.class);//开启服务显示悬浮框

bindService(intent, mVideoServiceConnection, Context.BIND_AUTO_CREATE);

ServiceConnection mVideoServiceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

// 获取服务的操作对象

FloatVideoWindowService.MyBinder binder = (FloatVideoWindowService.MyBinder) service;

binder.getService();

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

Service完整代码如下:

/**

* 视频悬浮窗服务

*/

public class FloatVideoWindowService extends Service {

private WindowManager mWindowManager;

private WindowManager.LayoutParams wmParams;

private LayoutInflater inflater;

private String currentBigUserId;

//浮动布局view

private View mFloatingLayout;

//容器父布局

private TXCloudVideoView mTXCloudVideoView;

@Override

public void onCreate() {

super.onCreate();

initWindow();//设置悬浮窗基本参数(位置、宽高等)

}

@Nullable

@Override

public IBinder onBind(Intent intent) {

currentBigUserId = intent.getStringExtra("userId");

initFloating();//悬浮框点击事件的处理

return new MyBinder();

}

public class MyBinder extends Binder {

public FloatVideoWindowService getService() {

return FloatVideoWindowService.this;

}

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

return super.onStartCommand(intent, flags, startId);

}

@Override

public void onDestroy() {

super.onDestroy();

if (mFloatingLayout != null) {

// 移除悬浮窗口

mWindowManager.removeView(mFloatingLayout);

mFloatingLayout = null;

Constents.isShowFloatWindow = false;

}

}

/**

* 设置悬浮框基本参数(位置、宽高等)

*/

private void initWindow() {

mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

//设置好悬浮窗的参数

wmParams = getParams();

// 悬浮窗默认显示以左上角为起始坐标

wmParams.gravity = Gravity.LEFT | Gravity.TOP;

//悬浮窗的开始位置,因为设置的是从左上角开始,所以屏幕左上角是x=0;y=0

wmParams.x = 70;

wmParams.y = 210;

//得到容器,通过这个inflater来获得悬浮窗控件

inflater = LayoutInflater.from(getApplicationContext());

// 获取浮动窗口视图所在布局

mFloatingLayout = inflater.inflate(R.layout.alert_float_video_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.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;

//设置悬浮窗口长宽数据

wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;

wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

return wmParams;

}

private void initFloating() {

mTXCloudVideoView = mFloatingLayout.findViewById(R.id.float_videoview);

TRTCVideoViewLayout mTRTCVideoViewLayout = Constents.mVideoViewLayout;

TXCloudVideoView mLocalVideoView = mTRTCVideoViewLayout.getCloudVideoViewByUseId(currentBigUserId);

if (mLocalVideoView == null) {

mLocalVideoView = mTRTCVideoViewLayout.getCloudVideoViewByIndex(0);

}

if (ConstData.userid.equals(currentBigUserId)) {

TXCGLSurfaceView mTXCGLSurfaceView = mLocalVideoView.getGLSurfaceView();

if (mTXCGLSurfaceView != null && mTXCGLSurfaceView.getParent() != null) {

((ViewGroup) mTXCGLSurfaceView.getParent()).removeView(mTXCGLSurfaceView);

mTXCloudVideoView.addVideoView(mTXCGLSurfaceView);

}

} else {

TextureView mTextureView = mLocalVideoView.getVideoView();

if (mTextureView != null && mTextureView.getParent() != null) {

((ViewGroup) mTextureView.getParent()).removeView(mTextureView);

mTXCloudVideoView.addVideoView(mTextureView);

}

}

Constents.isShowFloatWindow = true;

//悬浮框触摸事件,设置悬浮框可拖动

mTXCloudVideoView.setOnTouchListener(new FloatingListener());

//悬浮框点击事件

mTXCloudVideoView.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//在这里实现点击重新回到Activity

Intent intent = new Intent(FloatVideoWindowService.this, TRTCVideoCallActivity.class);

startActivity(intent);

}

});

}

//开始触控的坐标,移动时的坐标(相对于屏幕左上角的坐标)

private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY;

//开始时的坐标和结束时的坐标(相对于自身控件的坐标)

private int mStartX, mStartY, mStopX, mStopY;

//判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件

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:

mTouchCurrentX = (int) event.getRawX();

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:

mStopX = (int) event.getX();

mStopY = (int) event.getY();

if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) {

isMove = true;

}

break;

default:

break;

}

//如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件

return isMove;

}

}

}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐