Android 带有悬浮计时器的录屏实现

MediaRecorder

/**
 * Used to record audio and video. The recording control is based on a
 * simple state machine (see below).
 *
 * <p><img src="{@docRoot}images/mediarecorder_state_diagram.gif" border="0" />
 * </p>
 *
 * <p>A common case of using MediaRecorder to record audio works as follows:
 *
 * <pre>MediaRecorder recorder = new MediaRecorder();
 * recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 * recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
 * recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 * recorder.setOutputFile(PATH_NAME);
 * recorder.prepare();
 * recorder.start();   // Recording is now started
 * ...
 * recorder.stop();
 * recorder.reset();   // You can reuse the object by going back to setAudioSource() step
 * recorder.release(); // Now the object cannot be reused
 * </pre>
 *
 * <p>Applications may want to register for informational and error
 * events in order to be informed of some internal update and possible
 * runtime errors during recording. Registration for such events is
 * done by setting the appropriate listeners (via calls
 * (to {@link #setOnInfoListener(OnInfoListener)}setOnInfoListener and/or
 * {@link #setOnErrorListener(OnErrorListener)}setOnErrorListener).
 * In order to receive the respective callback associated with these listeners,
 * applications are required to create MediaRecorder objects on threads with a
 * Looper running (the main UI thread by default already has a Looper running).
 *
 * <p><strong>Note:</strong> Currently, MediaRecorder does not work on the emulator.
 *
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <p>For more information about how to use MediaRecorder for recording video, read the
 * <a href="{@docRoot}guide/topics/media/camera.html#capture-video">Camera</a> developer guide.
 * For more information about how to use MediaRecorder for recording sound, read the
 * <a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a> developer guide.</p>
 * </div>
 */
public class MediaRecorder implements AudioRouting

 

本文录屏实现 SDK必须大于或等于 Build.VERSION_CODES.LOLLIPOP;

 

权限申请

悬浮框权限申请:

    @RequiresApi(api = Build.VERSION_CODES.M)
    private fun checkSystemAlertPermission() {
        if (Build.VERSION.SDK_INT >= 23) { // Android6.0及以后需要动态申请权限
            if (!Settings.canDrawOverlays(this)) {
                //启动Activity让用户授权
                val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName"))
                startActivityForResult(intent, 1010)
            } else {
                // 弹出悬浮窗
                hasSystemAlertPermission = true
            }
        } else {
            // 弹出悬浮窗
            hasSystemAlertPermission = true
        }
    }

存储,音频权限申请:
 

   @RequiresApi(api = Build.VERSION_CODES.M)
    private fun permissions() {
        val permissionList = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO)
        val needList: MutableList<String> = ArrayList()
        for (i in permissionList.indices) {
            val checkPermission = checkSelfPermission(permissionList[i])
            if (checkPermission != PackageManager.PERMISSION_GRANTED) {
                needList.add(permissionList[i])
            }
        }
        if (needList.isEmpty()) {
            requestRecord()
        } else {
            val permissionArray = needList.toTypedArray()
            ActivityCompat.requestPermissions(this, permissionArray, REQUEST_PERMISSION)
        }
    }

 

开启录屏

 

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private fun requestRecord() {
        val metrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(metrics)
        mScreenWidth = metrics.widthPixels
        mScreenHeight = metrics.heightPixels
        mScreenDensity = metrics.densityDpi
        val projectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        startActivityForResult(projectionManager.createScreenCaptureIntent(), REQUEST_RECORD)
    }

 

启动服务

Service提供主要功能包含

  弹出悬浮计时框

    public void showRecordView() {
        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        params = new WindowManager.LayoutParams();
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        //设置效果为背景透明.
        params.format = PixelFormat.RGBA_8888;
        //设置flags.不可聚焦及不可使用按钮对悬浮窗进行操控.
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        //设置窗口初始停靠位置.
        params.gravity = Gravity.LEFT | Gravity.BOTTOM;
        params.x = (int) context.getResources().getDimension(R.dimen.dip200);
        params.y = statusBarHeight;
        //设置悬浮窗口长宽数据.
        params.width = (int) context.getResources().getDimension(R.dimen.dip180);
        params.height = (int) context.getResources().getDimension(R.dimen.dip60);

        LayoutInflater inflater = LayoutInflater.from(context);
        recordView = inflater.inflate(R.layout.layout_record, null);
        windowManager.addView(recordView, params);
        btnStop = recordView.findViewById(R.id.btn_stop);
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (recordListener != null) {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            windowManager.removeView(recordView);
                        }
                    });
                    recordStatus = RecordStateManager.STOP;
                    recordListener.stop();
                }
            }
        });
        tv_time = recordView.findViewById(R.id.tv_time);
        tv_time.setText(sdf.format(calendar.getTime()));
        timeCounter();
        drag();
    }
  1. 开始录屏
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private fun startRecord() {
        try {
            initRecorder()
            mediaProjection = createMediaProjection()
            virtualDisplay = mediaProjection!!.createVirtualDisplay("MainScreen",
                    mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    mediaRecorder!!.surface, null, null)
            mediaRecorder!!.start()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

   注册广播监听

 

 

监听广播

class RecordReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (PathConfig.ACTION_RECORD_SCREEN_STATE == intent.action) {
            return
        }
        val state = intent.getIntExtra("state", -1)
        RecordStateManager.instance.setRecordState(state)
    }
}

由于屏幕录制需要在各个Activity 页面都允许,所以Service不能使用bindService启动,因此需要使用广播来监听录屏的状态。来通知页面变化。

 

GitHub 地址 :https://github.com/freemanDing/ScreenRecord

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值