Android Presentation realizes double screen differential display

  • 2021-11-14 07:13:30
  • OfStack

1. Overview

Now more and more Android devices have multiple screens, The most common application scenario of dual-screen differential display should be the device similar to cash register platform. On the main screen, the clerk can select and enter the items, while the secondary screen is the bill details displayed to us. However, it only realizes the function of dual-screen differential display through one software system, and Presentation is the key.

2. Presentation analysis

1. Brief introduction: First of all, from its inheritance relationship, Presentation inherits from Dialog, that is to say, it is actually a special Dialog for displaying content on the second screen. When it is created, it will be associated with its target display screen, including its context and some configuration parameters.

2. Context: However, the context mentioned here will be different from the context in which its container is located. It will use its own context to load the layout and related resources of presentation to ensure that the correct size can be displayed on the target screen and the appropriate screen density can be obtained.

3. Automatic removal: Although presentation is different from context of its associated Activity, they are not completely separated. When the screen associated with presentation is removed, presentation will be automatically removed, so Presentation also needs to pay special attention to the state of the currently displayed content when Activity is in the state of pause and resume.

4. Screen selection: Because sometimes our Android device has multiple screens, it is very important to choose the right screen to display, so when we display Presentation, we need to let our system choose the right screen to display. Here are two ways to choose a suitable screen.

This is the easiest way for us to show presentation. media router is a system-level service, It can track all available audio and video route in the system. When a path is selected or unselected, And when route changes when it is suitable for display with presentation, it will send a notification. Then the application itself will monitor this notification and automatically select the display or hiding of presentation. The recommended presentation display here is actually only recommended by media router. If our application needs to be displayed on the second screen, it will be used, and if not, it will be displayed locally.

Use media router to select the display screen of presentation
Use display manager to select the display screen of persentation

DisplayManager can monitor all connected display devices in our system, However, not all devices are suitable for displaying content as secondary screens. For example, when an Activity wants to display an presentation on the main screen, the effect will be equivalent to displaying a special Dialog in the main Activity. Therefore, when we choose this way to select Presentation for display, we must bind it with an available display.

3. Source code analysis

First, look at its constructor


public Presentation(Context outerContext, Display display, int theme) {
 super(createPresentationContext(outerContext, display, theme), theme, false);
 
 mDisplay = display;
 mDisplayManager = (DisplayManager)getContext().getSystemService(DISPLAY_SERVICE);
 
 final Window w = getWindow();
 final WindowManager.LayoutParams attr = w.getAttributes();
 attr.token = mToken;
 w.setAttributes(attr);
 w.setGravity(Gravity.FILL);
 w.setType(TYPE_PRESENTATION);
 setCanceledOnTouchOutside(false);
 }

The first Context parameter in its formal parameters is very important. This is an context that the application is showing presentation, and it is an context created by Presentation itself. Based on this context, the appropriate information can be correctly displayed on the screen associated with it. Then the related attributes of window are set in the code.

Then let's look at the creation of its own Context


private static Context createPresentationContext(
 Context outerContext, Display display, int theme) {
 // First judge the incoming context And display Whether it is empty or not, if it is empty, an exception will be thrown 
 if (outerContext == null) {
 throw new IllegalArgumentException("outerContext must not be null");
 }
 if (display == null) {
 throw new IllegalArgumentException("display must not be null");
 }
 
 Context displayContext = outerContext.createDisplayContext(display);
 
 // Here is the judgment of its theme, for 0 Is the default theme 
 if (theme == 0) {
 TypedValue outValue = new TypedValue();
 displayContext.getTheme().resolveAttribute(
  com.android.internal.R.attr.presentationTheme, outValue, true);
 theme = outValue.resourceId;
 }
 
 // Derive the display's window manager from the outer window manager.
 // We do this because the outer window manager have some extra information
 // such as the parent window, which is important if the presentation uses
 // an application window type.
 final WindowManagerImpl outerWindowManager =
 (WindowManagerImpl)outerContext.getSystemService(WINDOW_SERVICE);
 final WindowManagerImpl displayWindowManager =
 outerWindowManager.createPresentationWindowManager(displayContext);
 
 // Because ContextThemeWrapper The parent class of is ours Context
 // So what finally returns here is Presentation Create a good one for us Context
 return new ContextThemeWrapper(displayContext, theme) {
 
 // What is returned in this method is Object Object 
 @Override
 public Object getSystemService(String name) {
 if (WINDOW_SERVICE.equals(name)) {
  return displayWindowManager;
  // If it is related to this incoming name The same words return the above windowManager Created WindowManager Adj. 1 Specific implementation 
 }
 // Otherwise, what is returned is Context In this abstract class 1 Kinds of service types 
 return super.getSystemService(name);
 }
 };
 }

Next, we continue to look at Presentation's listening for screen additions, removals and changes


private final DisplayListener mDisplayListener = new DisplayListener() {
 @Override
 public void onDisplayAdded(int displayId) {
 }
 
 @Override
 public void onDisplayRemoved(int displayId) {
 if (displayId == mDisplay.getDisplayId()) {
 handleDisplayRemoved();
 }
 }
 
 @Override
 public void onDisplayChanged(int displayId) {
 if (displayId == mDisplay.getDisplayId()) {
 handleDisplayChanged();
 }
 }
 };

Here we see that it does not deal with add, so let's go one step further and look at the implementation of the key handlerDisplayRemoved in onDisplayRemoved and the core handlerDisplayChanged in onDisplayChanged

handlerDisplayChanged:


private void handleDisplayChanged() {
 onDisplayChanged();
 
 // We currently do not support configuration changes for presentations
 // (although we could add that feature with a bit more work).
 // If the display metrics have changed in any way then the current configuration
 // is invalid and the application must recreate the presentation to get
 // a new context.
 if (!isConfigurationStillValid()) {
 Log.i(TAG, "Presentation is being dismissed because the "
  + "display metrics have changed since it was created.");
 cancel();
 }
 }

In this method, we regret to find that the Google programmer did not do special treatment after the current screen configuration changed, so when our screen size and other information changed, our presentation must re-Create to re-obtain context, and then re-display.


@Override
 protected void onStart() {
 super.onStart();
 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
 
 // Since we were not watching for display changes until just now, there is a
 // chance that the display metrics have changed. If so, we will need to
 // dismiss the presentation immediately. This case is expected
 // to be rare but surprising, so we'll write a log message about it.
 if (!isConfigurationStillValid()) {
 Log.i(TAG, "Presentation is being dismissed because the "
  + "display metrics have changed since it was created.");
 mHandler.sendEmptyMessage(MSG_CANCEL);
 }
 }

At the same time, we can also find in onStart that it has not monitored display change for the time being, and it may change here, so in this case, it printed an log to notify 1.

handlerDisplayRemoved This method is the system automatically to send a message, and then call the presentation automatically canceled.

4. Summary

After the basic analysis of Presentation, we should mainly pay attention to its Context and the binding relationship with Activity. In fact, from a simple point of view, it is an Dialog, but it can be displayed on multiple screens. Of course, the depth of the above analysis is still shallow, and a deeper understanding and some problems should be used more in the follow-up work before continuing to observe.


Related articles: