Usage of Android VirtualDisplay and click event problems encountered

preface

Recently, I was looking at the problems related to Android multi screen, and initially came into contact with some things of DisplayManager. Android supports multiple screen displays. The screen of the mobile phone is the main screen, and the screen connected through HDMI, usb and wifi is the external display. Another is the Api provided by Android system, namely VirtualDisplay.

I. MediaRouter or DisplayManager

There are two ways for Android to obtain the auxiliary screen (i.e. explicit display), MediaRouter or DisplayManager. Android 4.2 phones have the function of simulating the auxiliary screen in the development options. We select a resolution and open it to simulate an external screen. This screen is created by the developer's option, so it does not really exist. It is simulated (for debugging). If the mobile phone is connected to an auxiliary screen, the real screen is the auxiliary screen of the mobile phone.

1,MediaRouter

MediaRouter is used to interact with MediaRouterService to manage the playback behavior of multimedia and maintain the currently paired remote display devices, including WiFi play, Bluetooth A2DP device and Google Cast device

Android media routing framework provides two types of playback output: remote playback and auxiliary output.

Remote playback type} refers to the auxiliary device processing the reception, decoding and playback of media content, while Android devices only play the role of remote control, such as Google Cast.

The auxiliary output type {is that the application itself processes media content, including the export and processing of media content, and directly presents and streams the processing results to the auxiliary receiving device. The auxiliary receiving device only presents the final content after media processing. For example, this method is used in Android system to support Wireless Display output. Isn't this a projection?

The media application uses the media routing framework through a MediaRouter object (an object provided by the media routing framework) to select the media route, and connects to the selected final receiving device through the route of the media routing framework.

The way to get a MediaRouter object is

MediaRouter mediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);

The following methods are commonly used in MediaRouter:

RouterInfo is the information class of the remote device.

//Get an instance of RouterInfo

MediaRouter.RouteInfo localRouteInfo = 
mediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
display = localRouteInfo != null ? localRouteInfo.getPresentationDisplay() : null;
if (display != null) {
    showPresentation(display);
}
Presentation
presentation Is a special dialog ,The purpose is to show different internal on the auxiliary screen
presentation It's a dialog
 From the perspective of biogenetics,presentation No matter what it is described as,It is also a dialog. presentation The purpose is to display on the auxiliary screen.

2,DisplayManager

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);

(1) Get the currently existing Displays

Display[] arrayOfDisplay = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);// Get secondary screen only

If (arrayofdisplay. Length > 0) {showpresentation (arrayofdisplay [0]); / / use the first split screen} or Display [] displays = displaymanager getDisplays();// Get all the displays of the system, including the Display where the desktop itself is located

if (displays.length > 1) {

 presentation2 = new MyPresentation2(getApplicationContext(), presentationDisplays[1]);       presentation2.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); presentation2.show();

}

(2) Create a virtual Display containing a real Display object

int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; // Create public display displaymanager createVirtualDisplay("displayName", width, height, densityDpi, mSurface, flags);

There are width, height and screen density in the createVirtualDisplay() method
densityDpi: screen density, generally 320480960, etc. different values have different effects. Take a closer look when using. I chose 480 in the project.

mSurface: the Surface on which the VirtualDisplay depends to be created. One is obtained from the SurfaceView and the other is obtained from the ImageReader. SurfaceView is a subclass of view and does not implement the ViewGroup class. You cannot add other controls on SurfaceView. SurfaceView provides direct access to a paintable interface, which can control the sub view layer at the top of the interface. SurfaceView is provided for pixels that need to be drawn directly instead of using
Used by the application of the form part. An important concept and clue in Android graphics system is surface. View and its subclasses (such as textview and button) should be painted on the surface. Each surface creates a Canvas object (but its properties change from time to time) to manage the drawing operations of the view on the surface, such as drawing dots and lines.

flags: are some flag bits for creating virtual screen.     

(3)VirtualDisplay presentation content

(a) present a Presentation

As mentioned earlier, Presentation is essentially a Dialog. In VirtualDisplay, the way to display the View with Presentation is to customize a Presentation subclass MainPresentation, setContentView()xml file. Then create a Presentation instance

Presentation presentation = new TestPresentation(this, mDisplay.getDisplay());              
presentation.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
presentation.show();

(b) Show an Activity (how to start an Activity on a secondary screen)

 ActivityOptions options = null;
 if (mDisplay != null) {
     options = ActivityOptions.makeBasic();
     options.setLaunchDisplayId(mDisplay.getDisplay().getDisplayId());
  }
  Intent i = new Intent();
  i.setClassName(getPackageName(), getPackageName()+ ".SecondActivity");
  i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
  if (options != null) {
      startActivity(i, options.toBundle());
  }

It is worth noting that when displaying an Activity on the secondary screen, you need to start it explicitly. The target Activity to start is in androidmanifest Declare the attribute android:exported = true in XML

2, Problems encountered with click events

I defined a SurfaceView in the Activity. After creating it, I created a VirtualDisplay with the Surface of SurfaceView as the parameter, and then displayed a presentation on the VirtualDisplay (with layout file built in).

public class VirtualDisplayActivity extends AppCompatActivity {
    private SurfaceView mSurfaceView;
    private DisplayManager mDisplayManager;
    private SurfaceHolder mSurfaceHolder;
    private mWidth;
    private mHeight;
    private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback(){
        @Override
        public void surfaceCreated(@NonNull SurfaceHolder holder) {
            mSurface = mSurfaceHolder.getSurface();
        }

        @Override
        public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
            mWidth = width;
            mHeight = height;
            createVirtualAndShowPresentation();
        }

        @Override
        public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
          
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.act_vir);
        mSurfaceView = findViewById(R.id.surface);
        mSurfaceHolder = mSurfaceView.getHolder();
        mDisplayManager = (DisplayManager) getSystemService(DISPLAY_SERVICE);
        getSupportActionBar().setTitle("Lala Lala");
    }
    private void createVirtualAndShowPresentation() {
        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
        mDisplay = mDisplayManager.createVirtualDisplay("maomao",mWidth, mHeight, 480, mSurface,flags);
        Presentation presentation = new TestPresentation(this, mDisplay.getDisplay());
        presentation.getWindow().
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
        presentation.show();
        
    }
}
public class TestPresentation extends Presentation {
    Button button;
    int conut = 0;
    public TestPresentation(Context outerContext, Display display) {
        super(outerContext, display);
        setContentView(R.layout.layout_presentation);
        button = findViewById(R.id.clickBtn);
        button.setOnClickListener(v -> {
            button.setText(String.valueOf(conut));
            conut++;
            Log.e("maomao","I got it event Yes click Presentation = " + conut);
        });
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("maomao"," dispatchTouchEvent I got it event Did you?");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("maomao"," onTouchEvent I got it event Did you?");
        return super.onTouchEvent(event);
    }
}

The final running effect is

So here comes the question.... The control click event in the Presentation does not respond. Even the entire interface of VirtualDisplay does not respond to touch events. The outermost layer that can respond to touch events is SurfaceView. Rewriting onTouchEvent() of SurfaceView can receive touch events, but the Presentation can't receive touch events.

I did the following experiments,

(1) if the background color red is set for the SurfaceView, the layout of the Presentation will not be displayed. Whether it is displayed on the Surface Presentation or on the Surface Presentation in the Surface View.

(2) Set the window where VirtualDisplayActivity is located to be pierced by click events. What I do is

 WindowManager.LayoutParams mLayoutParams = getWindow().getAttributes();
 mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 getWindow().setAttributes(mLayoutParams);

Then it is found that the SurfaceView cannot receive the touch event, and the Presentation control still doesn't respond when clicked.  

(3) I displayed the Presentation in getDisplay() of getWindow() of the Activity and found that it was OK to click.

So I made my reasoning: SurfaceView is a subclass of view. The events it receives will not be distributed to itself. As for VirtualDisplay and the Presentation it displays are painted on its internal Surface, how can it receive touch events?? Therefore, the pages in the VirtualDisplay displayed by the Surface in the SurfaceView cannot be clicked!! I don't know if my analysis is right. See the students give advice ah ~

 

 

 

 

 

 

 

 

 

 

 

Keywords: Java Android

Added by NeoPuma on Tue, 01 Feb 2022 16:31:55 +0200