Pregunta de internauta de Zhihu: ¿Cómo permite la ventana flotante de Android que la ventana responda a eventos y al mismo tiempo permite que el lugar detrás de ella reciba eventos?

Pregunta: ¿Cómo permite la ventana flotante de Android que la ventana responda a los eventos y al mismo tiempo permite que el lugar detrás de ella reciba eventos?

Haga clic en la ventana flotante, puede recibir el evento usted mismo, y el área detrás de usted también puede recibir el evento, cómo lograrlo, volver falso no es válido

El mecanismo nativo de Android no admite el motivo:

Este problema no se puede resolver sin modificar el sistema.En primer lugar, según el hecho de que
la ventana flotante también es una ventana,
el área detrás de la ventana es generalmente una Actividad o solo una ventana, y la esencia también es una ventana.

El proceso de distribución de inputdispatcher también atravesará todas las capas dibujadas actualmente para la distribución, como la siguiente situación de capa:
a través de la entrada de dumpsys, se puede obtener lo siguiente:


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 buscará una ventana adecuada de arriba a abajo para enviar. Una vez que se envíe la ventana superior, no enviará el evento a la ventana inferior. Por lo tanto, su ventana superior ha sido procesada y desea pasarla a la ventana inferior. ventana de procesamiento. de

Soluciones posibles:

Se ha explicado anteriormente que los eventos no se pueden transmitir directamente a dos ventanas, pero el sistema Android también proporciona otro tipo de soluciones. Por ejemplo, la escena clásica es: los fondos de pantalla dinámicos pueden aceptar eventos táctiles, y el Lanzador en el fondo de pantalla también puede aceptar eventos táctiles.
Esta escena es clásica. El fondo de pantalla pertenece a una capa de ventana separada y a la capa inferior. El lanzador es una actividad y una capa de ventana separada.
El escritorioinserte la descripción de la imagen aquí
y el fondo de pantalla pertenecen a dos capas de ventanas, pero obviamente ambas ventanas pueden responder a los eventos táctiles correspondientes.

Es decir, este lugar se da cuenta de que un evento se puede pasar a dos, entonces, ¿cuál es el principio aquí?

De hecho, el fondo de pantalla aquí implementa un InputMonitor similar en WallpaperService, es decir, puede ser responsable de recibir todos los eventos del sistema, no importa si el evento táctil se envía a cualquier ventana, puede recibirlo, es decir, monitorea todos los eventos táctiles del sistema de forma global.

De hecho, este tipo de curso de entrada también se ha explicado en el curso de entrada del profesor Qianlima en el aula de Tencent. También se puede ver en la entrada de dumpsys utilizada anteriormente:

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

Además del fondo de pantalla, también hay muchas implementaciones de este monitor, como la pista táctil que se muestra en la pantalla, los gestos de systemui, los gestos multitarea de escritorio, etc. /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();
    }

inserte la descripción de la imagen aquí

Luego puede aceptar eventos en el onInputEvent correspondiente:

inserte la descripción de la imagen aquí

Esto requiere que la aplicación tenga los permisos pertinentes:

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

Je suppose que tu aimes

Origine blog.csdn.net/learnframework/article/details/131348365
conseillé
Classement