Zhihu netizen question: How does the Android floating window allow the window to respond to events and at the same time allow the place behind it to receive events?

Question: How does the Android floating window allow the window to respond to events and at the same time allow the place behind it to receive events?

Click on the floating window, you can receive the event yourself, and the area blocked behind can also receive the event, how to achieve it, return. false is invalid

Native android mechanism does not support reason:

This problem cannot be solved without modifying the system. First of all, according to the fact that
the floating window is also a window,
the area behind the window is generally an Activity or only a window, and the essence is also a window.

The distribution process of inputdispatcher will also traverse all the layers currently drawn for distribution, such as the following layer situation:
through dumpsys input, the following can be obtained:


Windows:
      0: name='WindowManager', id=142, displayId=0, inputConfig=NOT_VISIBLE | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=WindowManager, applicationInfo.token=0x73b2aa4d1d90, touchableRegion=<empty>, ownerPid=562, ownerUid=1000, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      1: name='StrictModeFlash', id=88, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=0, ownerUid=0, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      2: name='d4f3e23 NavigationBar0', id=78, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH | SLIPPERY, alpha=1.00, frame=[0,2792][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[166,2792][442,2960]|[580,2792][860,2960]|[996,2792][1273,2960], ownerPid=747, ownerUid=10099, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -0.0000
            0.0000  1.0000  -2792.0000
            0.0000  0.0000  1.0000
      3: name='affdd80 StatusBar', id=79, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,84], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1440,84], ownerPid=747, ownerUid=10099, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      4: name='recents_animation_input_consumer', id=96, displayId=0, inputConfig=NOT_VISIBLE | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=recents_animation_input_consumer, applicationInfo.token=0x73b2aa4c04b0, touchableRegion=[0,0][1440,2960], ownerPid=562, ownerUid=1000, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      5: name='7c9d48b com.example.myapplication11/com.example.myapplication11.MainActivity', id=552, displayId=0, inputConfig=0x0, alpha=1.00, frame=[360,84][1080,972], globalScale=1.000000, applicationInfo.name=ActivityRecord{
    
    c71b56 u0 com.example.myapplication11/.MainActivity} t458}, applicationInfo.token=0x73b2aa4c5490, touchableRegion=[308,32][1133,1025], ownerPid=4415, ownerUid=10116, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            2.0000  -0.0000  -720.0000
            -0.0000  2.0000  -168.0000
            0.0000  0.0000  1.0000
      6: name='SurfaceView[com.example.myapplication11/com.example.myapplication11.MainActivity](BLAST)#576', id=576, displayId=0, inputConfig=NO_INPUT_CHANNEL, alpha=1.00, frame=[360,256][360,256], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=4415, ownerUid=10116, dispatchingTimeout=5000ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            2.0000  -0.0000  -720.0000
            -0.0000  2.0000  -512.0000
            0.0000  0.0000  1.0000
      7: name='7b00af5 ActivityRecordInputSink com.example.myapplication11/.MainActivity', id=550, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE, alpha=1.00, frame=[360,84][360,84], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[360,84][1080,972], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            2.0000  -0.0000  -720.0000
            -0.0000  2.0000  -168.0000
            0.0000  0.0000  1.0000
      8: name='ed3ad5e ActivityRecordInputSink com.android.documentsui/.files.FilesActivity', id=481, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      9: name='a9d0b01 ActivityRecordInputSink com.android.traceur/.MainActivity', id=321, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      10: name='f3f7d36 ActivityRecordInputSink com.android.settings/.SubSettings', id=306, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1440,2960], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      11: name='3053a19 ActivityRecordInputSink com.android.settings/.SubSettings', id=289, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1440,2960], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      12: name='b298a7e ActivityRecordInputSink com.android.settings/.homepage.SettingsHomepageActivity', id=271, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1440,2960], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      13: name='36c3662 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher', id=565, displayId=0, inputConfig=DUPLICATE_TOUCH_TO_WALLPAPER, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{
    
    f1bea28 u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t452}, applicationInfo.token=0x73b2aa4b1390, touchableRegion=[0,0][1440,2960], ownerPid=1067, ownerUid=10095, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      14: name='1ceec09 ActivityRecordInputSink com.android.launcher3/.uioverrides.QuickstepLauncher', id=102, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=562, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      15: name='Wallpaper BBQ wrapper#75', id=75, displayId=0, inputConfig=NO_INPUT_CHANNEL, alpha=1.00, frame=[-71,-147][2860,3108], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=747, ownerUid=10099, dispatchingTimeout=5000ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            0.3145  -0.0000  22.6451
            -0.0000  0.3145  46.5455
            0.0000  0.0000  1.0000
      16: name='7ee1983 com.android.systemui.ImageWallpaper', id=74, displayId=0, inputConfig=NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | IS_WALLPAPER, alpha=1.00, frame=[-71,-147][-71,-147], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=747, ownerUid=10099, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            0.3145  -0.0000  22.6451
            -0.0000  0.3145  46.5455
            0.0000  0.0000  1.0000

inputdispatch will search for a suitable window from top to bottom to dispatch. Once the upper window is dispatched, it will not dispatch the event to the lower window. Therefore, your upper window has been processed, and you want to pass it to the lower window for processing. of

Possible solutions:

It has been explained above that events cannot be directly transmitted to two windows, but the android system also provides other types of solutions. For example, the classic scene is: dynamic wallpapers can accept touch events, and the Launcher on the wallpaper can also accept touch events.
This The scene is classic, Wallpaper belongs to a separate window layer and the bottom layer, Launcher is an Activiyt and a separate window layer L is located on the upper layer of Wallpaper, but when you touch the desktop, you find that the wallpaper below can also receive related touch events.
​Desktopinsert image description here
and wallpaper belong to two window layers, but obviously both windows can respond to corresponding touch events.

That is, this place realizes that one event can be passed to two, so what is the principle here?

In fact, the wallpaper here implements a similar InputMonitor in WallpaperService, that is, it can be responsible for receiving all events of the system, no matter the touch event is dispatched to any window, it can receive it, that is, it monitors all the touch events of the system globally.

In fact, this kind of input course has also been explained in the input course of Teacher Qianlima in the Tencent classroom. It can also be seen from the dumpsys input used earlier:

Global monitors on display 0:
    0: 'PointerEventDispatcher0 (server)', 

In addition to the wallpaper, there are also many implementations of this monitor, such as the touch track displayed on the screen, systemui gestures, desktop multitasking gestures, etc. There are such implementations. The specific implementation: packages/apps/Launcher3/quickstep/
src
/ com/android/quickstep/TouchInteractionService.java

  private void initInputMonitor(String reason) {
    
    
        disposeEventHandlers("Initializing input monitor due to: " + reason);

        if (mDeviceState.isButtonNavMode()) {
    
    
            return;
        }

        mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
        mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
                mMainChoreographer, this::onInputEvent);

        mRotationTouchHelper.updateGestureTouchRegions();
    }

insert image description here

Then you can accept events in the corresponding onInputEvent:

insert image description here

This requires the app to have relevant permissions:

  if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
                "monitorGestureInput()")) {
    
    
            throw new SecurityException("Requires MONITOR_INPUT permission");
        }

Guess you like

Origin blog.csdn.net/learnframework/article/details/131348365