SurfaceFlinger-Input: Ignore invisible layers for occlusion detection
For legacy compatibility reasons, we allow apps to receive input prior
to submitting their first buffer, and for this reason we check
canReceiveInput() to populate InputWindowInfo#visible, rather than
directly calling isVisible(). However, in the case of layers which
can't receive input (!hasInputInfo()) and are exclusively being used
for occlusion detection we have no such legacy requirement and so we can just
directly check the visibility value. Obviously this doesn't
cause any problems with occlusion detection, since if the layer
isn't being drawn it can't occlude anything. This semantic is
very useful as it allows BufferLayers which no buffer drawn to be used
as ContainerLayers, as we frequently use SurfaceView for.
Bug: 157772682
Test: Existing tests pass.
Change-Id: Iadcd5d8fc4016ee1f88480a50bb3555797830560
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3255aac..c146315 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2408,7 +2408,15 @@
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
- info.visible = canReceiveInput();
+ // For compatibility reasons we let layers which can receive input
+ // receive input before they have actually submitted a buffer. Because
+ // of this we use canReceiveInput instead of isVisible to check the
+ // policy-visibility, ignoring the buffer state. However for layers with
+ // hasInputInfo()==false we can use the real visibility state.
+ // We are just using these layers for occlusion detection in
+ // InputDispatcher, and obviously if they aren't visible they can't occlude
+ // anything.
+ info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {