0

我正在开发一个可以记录 Android 设备屏幕内容并将其显示在 SurfaceView 上的应用程序。到目前为止,SurfaceView 是屏幕中间的一个框,当前正在显示整个屏幕的内容,连同它自己,创建一个重复的图像。有没有办法重复隐藏SurfaceView,创建一个虚拟显示,然后用虚拟显示的内容显示SurfaceView?

RecordingSession.java

class RecordingSession
  implements MediaScannerConnection.OnScanCompletedListener {
  static final int VIRT_DISPLAY_FLAGS=
    DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
      DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
  private RecordingConfig config;
  private final File output;
  private final Context ctxt;
  private final ToneGenerator beeper;
  private MediaRecorder recorder;
  private MediaProjection projection;
  private VirtualDisplay vdisplay;
  private Window window;

  RecordingSession(Context ctxt, RecordingConfig config,
                   MediaProjection projection, Window window) {
    this.ctxt=ctxt.getApplicationContext();
    this.window = window;
    this.config=config;
    this.projection=projection;
    this.beeper=new ToneGenerator(
      AudioManager.STREAM_NOTIFICATION, 100);

    output=new File(ctxt.getExternalFilesDir(null), "andcorder.mp4");
    output.getParentFile().mkdirs();
  }

  void start() {

      //this.window.close();
    vdisplay=projection.createVirtualDisplay("andcorder",
            config.width, config.height, config.density,
            VIRT_DISPLAY_FLAGS, this.window.getScreenShot().getHolder().getSurface(), null, null);
    //this.window.open();
    beeper.startTone(ToneGenerator.TONE_PROP_ACK);
  }

  void stop() {
    projection.stop();
    vdisplay.release();
  }

  @Override
  public void onScanCompleted(String path, Uri uri) {
    beeper.startTone(ToneGenerator.TONE_PROP_NACK);
  }
}

窗口.java

public class Window {

    // declaring required variables
    private Context context;
    private View mView;
    private WindowManager.LayoutParams mParams;
    private WindowManager mWindowManager;
    private LayoutInflater layoutInflater;

    public SurfaceView getScreenShot() {
        return screenShot;
    }

    private SurfaceView screenShot;
    private LinearLayout toDisplay;

    public Window(Context context){
        this.context=context;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // set the layout parameters of the window
            mParams = new WindowManager.LayoutParams(
                    // Shrink the window to wrap the content rather
                    // than filling the screen
                    WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
                    // Display it on top of other application windows
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                    // Don't let it grab the input focus
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    // Make the underlying application window visible
                    // through any transparent parts
                    PixelFormat.TRANSLUCENT);

        }
        // getting a LayoutInflater
        layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        // inflating the view with the custom layout we created
        mView = layoutInflater.inflate(R.layout.popup_window, null);
        screenShot= mView.findViewById(R.id.screenShot);
        
        // Define the position of the
        // window within the screen
        mParams.gravity = Gravity.CENTER;
        mWindowManager = (WindowManager)context.getSystemService(WINDOW_SERVICE);
    }

    public void open() {

        try {
            // check if the view is already
            // inflated or present in the window
            if(mView.getWindowToken()==null) {
                if(mView.getParent()==null) {
                    mWindowManager.addView(mView, mParams);
                }
            }
        } catch (Exception e) {
            Log.d("Error1",e.toString());
        }

    }

    public void hide() {
        try {
            mView.setVisibility(View.INVISIBLE);
        } catch (Exception e) {
            Log.d("Error3",e.toString());
        }
    }

    public void show() {
        try {
            mView.setVisibility(View.VISIBLE);
        } catch (Exception e) {
            Log.d("Error4",e.toString());
        }
    }

    public void close() {

        try {
            // remove the view from the window
            ((WindowManager)context.getSystemService(WINDOW_SERVICE)).removeView(mView);
            // invalidate the view
            mView.invalidate();
            // remove all views
            ((ViewGroup)mView.getParent()).removeAllViews();

            // the above steps are necessary when you are adding and removing
            // the view simultaneously, it might give some exceptions
        } catch (Exception e) {
            Log.d("Error2",e.toString());
        }
    }
}

popup_window.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="4dp"
    android:background="@null">

        <SurfaceView
            android:id="@+id/screenShot"
            android:layout_width="match_parent"
            android:layout_height="250dp" />

</RelativeLayout>
4

1 回答 1

0

我玩过我的代码,发现将虚拟显示器的高度和宽度加倍就可以了。我是 android 开发的初学者,因此不知道为什么会这样。如果有人能阐明为什么这个调整会奏效,那就太好了。

vdisplay=projection.createVirtualDisplay("andcorder",
            config.width*2, config.height*2, config.density,
            VIRT_DISPLAY_FLAGS, this.window.getScreenShot().getHolder().getSurface(), null, null);
于 2022-01-12T16:27:16.870 回答