android MediaRecorder realizes recording function when recording screen

  • 2021-12-04 11:02:01
  • OfStack

Let's talk about android

Will you also encounter the function of recording screen recording in the demand recently, and it is also encountered recently. Now finish the record 1

First of all, the recording screen needs permission to post a dynamic permission class first


public class TalAllow {
  /**
   * RECORD_AUDIO      Audio permissions 
   * WRITE_EXTERNAL_STORAGE  Write permission 
   * CAMERA         Camera permissions 
   */
  public static void requestPermissions(Context context,int allowCode) {
    ArrayList<String> ps = new ArrayList<>();
    int per = ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.RECORD_AUDIO);
    }
    per = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    per = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.CAMERA);
    }
    per = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.READ_PHONE_STATE);
    }
    Log.d(TAG, "requestPermissions:ps=" + ps.size());
    if (!ps.isEmpty()) {
      String[] ps3 = new String[ps.size()];
      ps.toArray(ps3);
      ActivityCompat.requestPermissions((Activity) context, ps3, allowCode);
    }
  }
}

If there is a need to judge the authority, insert a link (the above class code code is 100)
Determine whether you have permission

Here comes the key point

First of all, explain that this recording screen and recording are done in the service, so paste a service class
This code definitely has quality and has done a lot of processing. The following one line and one line will be interpreted


//首先呢实现的是Handle.Callback接口 主要是做时间及计时时间回调的,会重新写HandleMessage方法,其实我个觉得跟在括号{} 里面重写没啥区别就是简洁页面
public class TalScreenRecordService extends Service implements Handler.Callback {
//这个就不解释了吧 log
  private static final String TAG = "TalScreenRecordService";
  //这个类是管理类拿到服务后会通过下面的类申请录屏,点击允许,
  //其中会回调两个参数,code码 和 data,都在ActivityForResult中进行判断code
  private MediaProjectionManager mProjectionManager;
 //这个会拿到申请的结果
  private MediaProjection mMediaProjection;
  //这个类就是我们主要的录屏录音的类啦
  private MediaRecorder mMediaRecorder;
  //这个就是我们要获取录制屏幕的大小,像素,等等1些数据
  //关于这类更详细的介绍https://blog.csdn.net/qq_16628781/article/details/62038163
  private VirtualDisplay mVirtualDisplay;
 //是否正在录制 false 没有录制
  private boolean mIsRunning;
  //获取屏幕的宽高和像素密度 稍后贴类
  private int mRecordWidth = TalScreenParams.getScreenWidth();
  private int mRecordHeight = TalScreenParams.getScreenWidth();
  private int mScreenDpi = TalScreenParams.getScreenDpi();
 //code data 就是上面说的允许后回调
  private int mResultCode;
  private Intent mResultData;
  //录屏文件的保存地址
  private String mRecordFilePath;
  private Handler mHandler;
  //已经录制多少秒了
  private int mRecordSeconds = 0;
  //handle发送消息时的what
  private static final int MSG_TYPE_COUNT_DOWN = 110;
 //这个是继承Service 必须重写的方法 这是使用的BindService(生命周期的长短跟activity1致)
  @Override
  public IBinder onBind(Intent intent) {
    return new RecordBinder();
  }
 //说1说这个返回值的问题吧
 // START_STICKY 粘性返回 ,1次失败,多次启动,不保留Intent对象
 //关于返回值问题https://blog.csdn.net/github_37663523/article/details/78811539
 @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    return START_STICKY;
  }
  @Override
  public void onCreate() {
    super.onCreate();
    //没有录制
    mIsRunning = false;
    //创建对象 在create方法里只执行1次
    mMediaRecorder = new MediaRecorder();
    // 由于实现了CallBack接口,在这里注册1下接口(个人觉得高大的写法,简洁)
    mHandler = new Handler(Looper.getMainLooper(), this);
  }
  @Override
  public void onDestroy() {
    super.onDestroy();
  }
 //数据不为空
  public boolean isReady() {
    return mMediaProjection != null && mResultData != null;
  }
 //清除的方法 避免内存泄漏 相信都看得懂
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public void clearRecordElement() {
    clearAll();
    if (mMediaRecorder != null) {
      mMediaRecorder.reset();
      mMediaRecorder.release();
      mMediaRecorder = null;
    }
    mResultData = null;
    //不执行的时候false
    mIsRunning = false;
  }
 //这个就是给是否正在录屏提供1个get方法
  public boolean ismIsRunning() {
    return mIsRunning;
  }
 //这个就是设置数据的方法在ActivityForResult中设置数据,说明是允许录屏的
  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public void setResultData(int resultCode, Intent resultData) {
    mResultCode = resultCode;
    mResultData = resultData;
 //拿到这个管理,看不懂跟上面注释结合看
    mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    //getMediaProjection(code,data)不知道这样写看不看的董 
    //说白了MediaProjectionManager是申请权限 MediaProjection是获取申请结果,防止别人调取隐私
    //再通过上面的setResultData方法获取到ActivityForResult中的code,data
    if (mProjectionManager != null) {
      mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData);
    }
  }
 //开始录制了
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public boolean startRecord() {
  //代码执行顺序(false,目前没录屏)
    if (mIsRunning) {
      return false;
    }
    //再次创建,防止异常
    if (mMediaProjection == null) {
      mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData);
    }
 //关于文件路径还有录屏的1些参数问题
    setUpMediaRecorder();
    //关于获取录制屏幕的大小,像素,等等1些数据
    createVirtualDisplay();
    //开始录制
    mMediaRecorder.start();
 //稍后贴类 监听录制情况
    TalScreenUtils.startRecord();
    //最多录制3分钟
    mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN, 1000);
    //录制时为true
    mIsRunning = true;
    Log.d(TAG, "startRecord ");
    return true;
  }
 //停止的方法
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public boolean stopRecord(String tip) {
    Log.d(TAG, "stopRecord: first ");
    //mIsRunning 默认值为false !mIsRunning 就是true。。
    if (!mIsRunning) {
      return false;
    }
    mIsRunning = false;
    Log.w(TAG, "stopRecord middle");
    try {
    //停止抓取异常,该置空的为空
      mMediaRecorder.stop();
      mMediaRecorder.reset();
      mMediaRecorder = null;
      mVirtualDisplay.release();
      mMediaProjection.stop();
      Log.w(TAG, "stopRecord ");
    } catch (Exception e) {
      e.printStackTrace();
      mMediaRecorder.release();
      mMediaRecorder = null;
      Log.w(TAG, "stopRecord exception");
    }
    mMediaProjection = null;
 //停止时移出这条消息what 
    mHandler.removeMessages(MSG_TYPE_COUNT_DOWN);
    //停止的监听 tip 是处理1些突发情况 比如内存不足
    TalScreenUtils.stopRecord(tip);
    Log.i(TAG, "stopRecord: " + mRecordFilePath);
    //录制时间不到两秒就删除录制文件
    if (mRecordSeconds <= 2) {
      TalFileUtils.deleteSDFile(mRecordFilePath);
    } else {
    //录制的视频库,将数据添加到媒体库
    //这个算是应用程序之间共享数据,把自己应用的数据添加到手机的媒体库ContentResolver
    //举个例子,代码添加手机联系人到自己的联系人列表,或者代码添加图片到自己的图库,还有不懂得,贴个链接
    //https://blog.csdn.net/bzlj2912009596/article/details/80248272
      TalFileUtils.fileScanVideo(this, mRecordFilePath, 1280, 720, mRecordSeconds);
    }
//    mRecordFilePath = null;
    mRecordSeconds = 0;
    return true;
  }
 //下面是关于处理在1些activity or fragment中生命周期的做法
  public void pauseRecord() {
    if (mMediaRecorder != null) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mMediaRecorder.pause();
      }
    }
  }
  public void resumeRecord() {
    if (mMediaRecorder != null) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mMediaRecorder.resume();
      }
    }
  }
 //这个就是刚才讲过的 绘制窗口大小,dpi问题 VirtualDisplay
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  private void createVirtualDisplay() {
    mVirtualDisplay = mMediaProjection.createVirtualDisplay("MainScreen", 1280, 720, mScreenDpi,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
  }
 //这个主要是路径,还有设置1些录制视频参数问题separator 为字节,占位用
  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  private void setUpMediaRecorder() {
    mRecordFilePath = getSaveDirectory() + File.separator + System.currentTimeMillis() + ".mp4";
    Log.i(TAG, "setUpMediaRecorder: " + mRecordFilePath);
    if (mMediaRecorder == null) {
      mMediaRecorder = new MediaRecorder();
    }
    //设置音频源
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 //设置视频源    
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
 //设置输出的编码格式 
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    if (mRecordFilePath != null) {
      mMediaRecorder.setOutputFile(mRecordFilePath);
    } else if (mRecordFilePath == null) {
      mMediaRecorder.setOutputFile(mRecordFilePath);
    }
    //设置录屏时屏幕大小,这个可跟mVirtualDisplay 1起控制屏幕大小
    //mVirtualDisplay 是将屏幕设置成多大多小,setVideoSize是输出文件时屏幕多大多小
    mMediaRecorder.setVideoSize(1280, 720);
     //图像编码 H264较好还有其他选择
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
  //音频编码    
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    //设置码率 高清的话的要数越大
    mMediaRecorder.setVideoEncodingBitRate((int) (1280 * 720 * 2.6));
    //设置帧率,该帧率必须是硬件支持的,可以通过Camera.CameraParameter.getSupportedPreviewFpsRange()方法获取相机支持的帧率
    mMediaRecorder.setVideoFrameRate(20);
    try {
    //准备
      mMediaRecorder.prepare();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public void clearAll() {
    if (mMediaProjection != null) {
      mMediaProjection.stop();
      mMediaProjection = null;
    }
  }
 //路径
  public String getRecordFilePath() {
    return mRecordFilePath;
  }
 //sd下绝对路径,先判断sd卡是否挂载
  public String getSaveDirectory() {
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
      return Environment.getExternalStorageDirectory().getAbsolutePath();
    } else {
      return null;
    }
  }
  //这是实现了Handle.CallBack中重写方法 handleMessage
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  @Override
  public boolean handleMessage(Message msg) {
    switch (msg.what) {
      case MSG_TYPE_COUNT_DOWN: {
        String str = null;
        //这是内存
        boolean enough = TalFileUtils.getSDFreeMemory() / (1024 * 1024) < 4;
        if (enough) {
          //空间不足,停止录屏
          str = "空间不足";
          //停止录屏时 通过接口回调1个信息,是因为什么停止录屏的
          stopRecord(str);
          mRecordSeconds = 0;
          break;
        }
        mRecordSeconds++;
        int minute = 0, second = 0;
        if (mRecordSeconds >= 60) {
          minute = mRecordSeconds / 60;
          second = mRecordSeconds % 60;
        } else {
          second = mRecordSeconds;
        }
        TalScreenUtils.onRecording("0" + minute + ":" + (second < 10 ? "0" + second : second + ""));
        if (mRecordSeconds < 5 * 60) {
          mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN, 1000);
        } else if (mRecordSeconds == 5 * 60) {
          str = "录制已到限定时长";
          stopRecord(str);
          mRecordSeconds = 0;
        }
        break;
      }
    }
    return true;
  }
  public class RecordBinder extends Binder {
    public TalScreenRecordService getRecordService() {
      return TalScreenRecordService.this;
    }
  }
}

The following is a class about mobile phone pixels and dpi


public class TalScreenParams {
  private static int mScreenWidth;
  private static int mScreenHeight;
  private static int mScreenDpi;

  public static void init(Activity activity){
    Display display = activity.getWindowManager().getDefaultDisplay();
    DisplayMetrics metrics = new DisplayMetrics();
    display.getMetrics(metrics);
    mScreenWidth = metrics.widthPixels;
    mScreenHeight = metrics.heightPixels;
    mScreenDpi = metrics.densityDpi;
  }

  public static int getScreenWidth(){
    return mScreenWidth;
  }

  public static int getScreenHeight(){
    return mScreenHeight;
  }

  public static int getScreenDpi(){
    return mScreenDpi;
  }

The following is a post about deleting files, and the classes added to the media library use ContentResolver here


public class TalFileUtils {
  /**
   *  Delete SD Files or directories in the card 
   *
   * @param path
   * @return
   */
  public static boolean deleteSDFile(String path) {
    return deleteSDFile(path, false);
  }

  /**
   *  Delete SD Files or directories in the card 
   *
   * @param path
   * @param deleteParent true To delete the parent directory 
   * @return
   */
  public static boolean deleteSDFile(String path, boolean deleteParent) {
    if (TextUtils.isEmpty(path)) {
      return false;
    }

    File file = new File(path);
    if (!file.exists()) {
      // Nonexistent 
      return true;
    }
    return deleteFile(file, deleteParent);
  }

  /**
   * @param file
   * @param deleteParent true To delete the parent directory 
   * @return
   */
  public static boolean deleteFile(File file, boolean deleteParent) {
    boolean flag = false;
    if (file == null) {
      return flag;
    }
    if (file.isDirectory()) {
      // Is a folder 
      File[] files = file.listFiles();
      if (files.length > 0) {
        for (int i = 0; i < files.length; i++) {
          flag = deleteFile(files[i], true);
          if (!flag) {
            return flag;
          }
        }
      }
      if (deleteParent) {
        flag = file.delete();
      }
    } else {
      flag = file.delete();
    }
    file = null;
    return flag;
  }

  /**
   *  Add to Media Database 
   *
   * @param context  Context 
   */
  public static Uri fileScanVideo(Context context, String videoPath, int videoWidth, int videoHeight,
                  int videoTime) {
    File file = new File(videoPath);
    if (file.exists()) {
      Uri uri = null;
      long size = file.length();
      String fileName = file.getName();
      long dateTaken = System.currentTimeMillis();
      ContentValues values = new ContentValues(11);
      values.put(MediaStore.Video.Media.DATA, videoPath); //  Path ;
      values.put(MediaStore.Video.Media.TITLE, fileName); //  Title ;
      values.put(MediaStore.Video.Media.DURATION, videoTime * 1000); //  Duration 
      values.put(MediaStore.Video.Media.WIDTH, videoWidth); //  Video width 
      values.put(MediaStore.Video.Media.HEIGHT, videoHeight); //  Video height 
      values.put(MediaStore.Video.Media.SIZE, size); //  Video size ;
      values.put(MediaStore.Video.Media.DATE_TAKEN, dateTaken); //  Insertion time ;
      values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);//  Filename ;
      values.put(MediaStore.Video.Media.DATE_MODIFIED, dateTaken / 1000);//  Modification time ;
      values.put(MediaStore.Video.Media.DATE_ADDED, dateTaken / 1000); //  Adding time ;
      values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");

      ContentResolver resolver = context.getContentResolver();

      if (resolver != null) {
        try {
          uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
        } catch (Exception e) {
          e.printStackTrace();
          uri = null;
        }
      }

      if (uri == null) {
        MediaScannerConnection.scanFile(context, new String[]{videoPath}, new String[]{"video/*"}, new MediaScannerConnection.OnScanCompletedListener() {
          @Override
          public void onScanCompleted(String path, Uri uri) {

          }
        });
      }

      return uri;
    }

    return null;
  }

  /**
   * SD The card exists and can be used 
   */
  public static boolean isSDExists() {
    return Environment.getExternalStorageState().equals(
        Environment.MEDIA_MOUNTED);
  }

  /**
   *  Get SD The remaining capacity of the card in Byte
   *
   * @return
   */
  public static long getSDFreeMemory() {
    try {
      if (isSDExists()) {
        File pathFile = Environment.getExternalStorageDirectory();
        // Retrieve overall information about the space on a filesystem.
        // This is a Wrapper for Unix statfs().
        StatFs statfs = new StatFs(pathFile.getPath());
        //  Get SDCard Upper-per 1 A block Adj. SIZE
        long nBlockSize = statfs.getBlockSize();
        //  Object available to the program Block Quantity of 
        // long nAvailBlock = statfs.getAvailableBlocksLong();
        long nAvailBlock = statfs.getAvailableBlocks();
        //  Calculation SDCard Residual size Byte
        long nSDFreeSize = nAvailBlock * nBlockSize;
        return nSDFreeSize;
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return 0;
  }
  public static long getFreeMem(Context context) {
    ActivityManager manager = (ActivityManager) context.getApplicationContext().getSystemService(Activity.ACTIVITY_SERVICE);
    if (manager != null) {
      ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
      if (info != null) {
        manager.getMemoryInfo(info);
        //  Unit Byte
        return info.availMem / 1024 / 1024;
      }
    }
    return 0;
  }
}

There is also a class that provides convenient access to the whole Service, and puts a few changes in listening service into the collection to do it


public class TalScreenUtils {
  private static TalScreenRecordService s_ScreenRecordService;
  private static List<RecordListener> s_RecordListener = new ArrayList<>();
  private static List<OnPageRecordListener> s_PageRecordListener = new ArrayList<>();
  //true, The prompt for the end of recording is being displayed 
  public static boolean s_IsRecordingTipShowing = false;
  /**
   *  Screen recording function  5.0+  You can only use your mobile phone 
   * @return
   */
  public static boolean isScreenRecordEnable(){
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ;
  }
  public static void setScreenService(TalScreenRecordService screenService){
    s_ScreenRecordService = screenService;
  }
  public static void clear(){
    if ( isScreenRecordEnable() && s_ScreenRecordService != null){
      s_ScreenRecordService.clearAll();
      s_ScreenRecordService = null;
    }
    if (s_RecordListener != null && s_RecordListener.size() > 0){
      s_RecordListener.clear();
    }
    if (s_PageRecordListener != null && s_PageRecordListener.size() > 0 ){
      s_PageRecordListener.clear();
    }
  }
  /**
   *  Start recording 
   */
  public static void startScreenRecord(Activity activity, int requestCode) {
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null && !s_ScreenRecordService.ismIsRunning()){
        if (!s_ScreenRecordService.isReady()){
          MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity.
              getSystemService(Context.MEDIA_PROJECTION_SERVICE);
          if (mediaProjectionManager != null){
            Intent intent = mediaProjectionManager.createScreenCaptureIntent();
            PackageManager packageManager = activity.getPackageManager();
            if (packageManager.resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY) != null){
              // With screen recording authorization Activity
              activity.startActivityForResult(intent,requestCode);
            }else {
              Toast.makeText(activity, " Can't record ", Toast.LENGTH_SHORT).show();
            }
          }
        } else {
          s_ScreenRecordService.startRecord();
        }
      }
    }
  }
  /**
   *  After obtaining the user's permission to record the screen, set the necessary data 
   * @param resultCode
   * @param resultData
   */
  public static void setUpData(int resultCode,Intent resultData) throws Exception{
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null && !s_ScreenRecordService.ismIsRunning()){
        s_ScreenRecordService.setResultData(resultCode,resultData);
        s_ScreenRecordService.startRecord();
      }
    }
  }
  /**
   *  Stop recording 
   */
  public static void stopScreenRecord(Context context){
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null && s_ScreenRecordService.ismIsRunning()){
        String str = " Stop recording ";
        s_ScreenRecordService.stopRecord(str);
      }
    }
  }
  /**
   *  Get the recorded file address 
   * @return
   */
  public static String getScreenRecordFilePath(){
    if (isScreenRecordEnable() && s_ScreenRecordService!= null) {
      return s_ScreenRecordService.getRecordFilePath();
    }
    return null;
  }
  /**
   *  Determine whether you are currently recording 
   * @return
   */
  public static boolean isCurrentRecording(){
    if (isScreenRecordEnable() && s_ScreenRecordService!= null) {
      return s_ScreenRecordService.ismIsRunning();
    }
    return false;
  }
  /**
   * true, The prompt for the end of recording is being displayed 
   * @return
   */
  public static boolean isRecodingTipShow(){
    return s_IsRecordingTipShowing;
  }
  public static void setRecordingStatus(boolean isShow){
    s_IsRecordingTipShowing = isShow;
  }
  /**
   *  The system is recording the screen, app  There will be conflicts in the recording screen, clean it up 1 Some data 
   */
  public static void clearRecordElement(){
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null ){
        s_ScreenRecordService.clearRecordElement();
      }
    }
  }
  public static void addRecordListener(RecordListener listener){
    if (listener != null && !s_RecordListener.contains(listener)){
      s_RecordListener.add(listener);
    }
  }
  public static void removeRecordListener(RecordListener listener){
    if (listener != null && s_RecordListener.contains(listener)){
      s_RecordListener.remove(listener);
    }
  }
  public static void addPageRecordListener( OnPageRecordListener listener){
    if (listener != null && !s_PageRecordListener.contains(listener)){
      s_PageRecordListener.add(listener);
    }
  }
  public static void removePageRecordListener( OnPageRecordListener listener){
    if (listener != null && s_PageRecordListener.contains(listener)){
      s_PageRecordListener.remove(listener);
    }
  }
  public static void onPageRecordStart(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onStartRecord();
      }
    }
  }
  public static void onPageRecordStop(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onStopRecord();
      }
    }
  }
  public static void onPageBeforeShowAnim(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onBeforeShowAnim();
      }
    }
  }
  public static void onPageAfterHideAnim(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onAfterHideAnim();
      }
    }
  }
  public static void startRecord(){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onStartRecord();
        Log.i("xxx", "startRecord: ");
      }
    }
  }
  public static void pauseRecord(){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onPauseRecord();
      }
    }
  }
  public static void resumeRecord(){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onResumeRecord();
      }
    }
  }
  public static void onRecording(String timeTip){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onRecording(timeTip);
      }
    }
  }
  public static void stopRecord(String stopTip){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onStopRecord( stopTip);
      }
    }
  }
  public interface RecordListener{
    void onStartRecord();
    void onPauseRecord();
    void onResumeRecord();
    void onStopRecord(String stopTip);
    void onRecording(String timeTip);
  }
  public interface OnPageRecordListener {
    void onStartRecord();
    void onStopRecord();
    void onBeforeShowAnim();
    void onAfterHideAnim();
  }
}

At the end of the day, it is the content of 1 call


public class MainActivity extends AppCompatActivity {
  private static final String TAG = MainActivity.class.getSimpleName();
  private Button mBtn;
  private final int REQUEST_ALLOW = 100;
  private Button mButton;
  //bindService Need to create a connection 
  private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      // Start service
      TalScreenRecordService.RecordBinder recordBinder = (TalScreenRecordService.RecordBinder) service;
      TalScreenRecordService recordService = recordBinder.getRecordService();
      // This is actually used by passing values activity Get in Service
      TalScreenUtils.setScreenService(recordService);
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
  };
 // Open service, Intention to jump to service, Don't forget AndroidManifest You need to register this inside service Oh 
  private void startService() {
    Intent intent = new Intent(MainActivity.this, TalScreenRecordService.class);
    bindService(intent, mConnection, BIND_AUTO_CREATE);
  }
  @Override
  protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mBtn = findViewById(R.id.btn);
    mButton = findViewById(R.id.button2);
    initView();
    // Two buttons  1 A beginning  1 End of  xml Don't post it 
    mBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if (TalFileUtils.getFreeMem(MainActivity.this) < 100) {
          Toast.makeText(MainActivity.this, " Out of memory on mobile phone , Please clean up before recording the screen ", Toast.LENGTH_SHORT).show();
          return;
        }
        // Start recording screen recording 
        TalScreenUtils.startScreenRecord(MainActivity.this, REQUEST_ALLOW);
      }
    });
    mButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        stop();
        Log.i(TAG, "onClick: " + stop());
      }
  // Stop screen recording and return path 
      private String stop() {
        TalScreenUtils.stopScreenRecord(MainActivity.this);// Stop 
        return TalScreenUtils.getScreenRecordFilePath();
      }
    });
  }
  @Override
  protected void onStart() {
    super.onStart();

  }

  private void initView() {
    // Authority application 
    TalAllow.requestPermissions(this, REQUEST_ALLOW);
    // Get screen size   In onCreate You can get it by initialization inside 
    TalScreenParams.init(this);
    startService();
  }

  @Override
  protected void onStop() {
    super.onStop();
    // Prevent exceptions when it is visible to users that they cannot interact with each other 
    TalScreenUtils.clear();
  }
 // Print Permission Acquisition Log 
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Toast.makeText(this, permissions[0] + "\n" + grantResults[0], Toast.LENGTH_SHORT).show();
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  }
 // After the user allows the recording screen to get a certain code  Follow data
  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_ALLOW && data != null) {
      try {
      // Set the data, after the user allows it   Called the method to start recording screen 
        TalScreenUtils.setUpData(resultCode, data);
        // Get the path 
        String screenRecordFilePath = TalScreenUtils.getScreenRecordFilePath();
        if (screenRecordFilePath == null) {
          Toast.makeText(this, " Empty ", Toast.LENGTH_SHORT).show();
        }
        Toast.makeText(MainActivity.this, "" + screenRecordFilePath, Toast.LENGTH_SHORT).show();
        Log.i("zlq", "onClick: " + screenRecordFilePath);
      } catch (Exception e) {
        e.printStackTrace();
      }
    } else {
      Toast.makeText(this, " Disable screen recording ", Toast.LENGTH_SHORT).show();
    }
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    unbindService(mConnection);
  }
}

So far, a relatively complete recording screen recording function can be realized. Please criticize and correct the shortcomings

Summarize


Related articles: