Merge "Reduce the window tap exclude region for child above it"
This commit is contained in:
@@ -27,6 +27,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Region;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.hardware.input.InputManager;
|
||||
@@ -46,6 +47,7 @@ import android.view.SurfaceSession;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManagerGlobal;
|
||||
|
||||
@@ -81,6 +83,9 @@ public class ActivityView extends ViewGroup {
|
||||
// Temp container to store view coordinates in window.
|
||||
private final int[] mLocationInWindow = new int[2];
|
||||
|
||||
// The latest tap exclude region that we've sent to WM.
|
||||
private final Region mTapExcludeRegion = new Region();
|
||||
|
||||
private TaskStackListener mTaskStackListener;
|
||||
|
||||
private final CloseGuard mGuard = CloseGuard.get();
|
||||
@@ -279,11 +284,11 @@ public class ActivityView extends ViewGroup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an update of {@link ActivityView}'s location in window to properly set touch exclude
|
||||
* Triggers an update of {@link ActivityView}'s location in window to properly set tap exclude
|
||||
* regions and avoid focus switches by touches on this view.
|
||||
*/
|
||||
public void onLocationChanged() {
|
||||
updateLocation();
|
||||
updateTapExcludeRegion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,15 +296,38 @@ public class ActivityView extends ViewGroup {
|
||||
mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
|
||||
}
|
||||
|
||||
/** Send current location and size to the WM to set tap exclude region for this view. */
|
||||
private void updateLocation() {
|
||||
@Override
|
||||
public boolean gatherTransparentRegion(Region region) {
|
||||
// The tap exclude region may be affected by any view on top of it, so we detect the
|
||||
// possible change by monitoring this function.
|
||||
updateTapExcludeRegion();
|
||||
return super.gatherTransparentRegion(region);
|
||||
}
|
||||
|
||||
/** Compute and send current tap exclude region to WM for this view. */
|
||||
private void updateTapExcludeRegion() {
|
||||
if (!isAttachedToWindow()) {
|
||||
return;
|
||||
}
|
||||
if (!canReceivePointerEvents()) {
|
||||
cleanTapExcludeRegion();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
getLocationInWindow(mLocationInWindow);
|
||||
final int x = mLocationInWindow[0];
|
||||
final int y = mLocationInWindow[1];
|
||||
mTapExcludeRegion.set(x, y, x + getWidth(), y + getHeight());
|
||||
|
||||
// There might be views on top of us. We need to subtract those areas from the tap
|
||||
// exclude region.
|
||||
final ViewParent parent = getParent();
|
||||
if (parent instanceof ViewGroup) {
|
||||
((ViewGroup) parent).subtractObscuredTouchableRegion(mTapExcludeRegion, this);
|
||||
}
|
||||
|
||||
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
|
||||
mLocationInWindow[0], mLocationInWindow[1], getWidth(), getHeight());
|
||||
mTapExcludeRegion);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
@@ -322,7 +350,7 @@ public class ActivityView extends ViewGroup {
|
||||
mVirtualDisplay.setDisplayState(true);
|
||||
}
|
||||
|
||||
updateLocation();
|
||||
updateTapExcludeRegion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,7 +358,7 @@ public class ActivityView extends ViewGroup {
|
||||
if (mVirtualDisplay != null) {
|
||||
mVirtualDisplay.resize(width, height, getBaseDisplayDensity());
|
||||
}
|
||||
updateLocation();
|
||||
updateTapExcludeRegion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -460,13 +488,14 @@ public class ActivityView extends ViewGroup {
|
||||
|
||||
/** Report to server that tap exclude region on hosting display should be cleared. */
|
||||
private void cleanTapExcludeRegion() {
|
||||
if (!isAttachedToWindow()) {
|
||||
if (!isAttachedToWindow() || mTapExcludeRegion.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Update tap exclude region with an empty rect to clean the state on server.
|
||||
// Update tap exclude region with a null region to clean the state on server.
|
||||
try {
|
||||
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
|
||||
0 /* left */, 0 /* top */, 0 /* width */, 0 /* height */);
|
||||
null /* region */);
|
||||
mTapExcludeRegion.setEmpty();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
|
||||
@@ -255,12 +255,11 @@ interface IWindowSession {
|
||||
void updatePointerIcon(IWindow window);
|
||||
|
||||
/**
|
||||
* Update a tap exclude region with a rectangular area identified by provided id in the window.
|
||||
* Touches on this region will not switch focus to this window. Passing an empty rect will
|
||||
* remove the area from the exclude region of this window.
|
||||
* Update a tap exclude region identified by provided id in the window. Touches on this region
|
||||
* will neither be dispatched to this window nor change the focus to this window. Passing an
|
||||
* invalid region will remove the area from the exclude region of this window.
|
||||
*/
|
||||
void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
|
||||
int height);
|
||||
void updateTapExcludeRegion(IWindow window, int regionId, in Region region);
|
||||
|
||||
/**
|
||||
* Called when the client has changed the local insets state, and now the server should reflect
|
||||
|
||||
@@ -13910,6 +13910,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
.getAccessibilityFocusedHost() == this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this view can receive pointer events.
|
||||
*
|
||||
* @return {@code true} if this view can receive pointer events.
|
||||
* @hide
|
||||
*/
|
||||
protected boolean canReceivePointerEvents() {
|
||||
return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the touch event to apply security policies.
|
||||
*
|
||||
|
||||
@@ -2011,7 +2011,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
|
||||
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
if (!child.canReceivePointerEvents()
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2094,7 +2094,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
childrenCount, i, customOrder);
|
||||
final View child = getAndVerifyPreorderedView(
|
||||
preorderedList, children, childIndex);
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
if (!child.canReceivePointerEvents()
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2314,7 +2314,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
|
||||
final View child =
|
||||
getAndVerifyPreorderedView(preorderedList, children, childIndex);
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
if (!child.canReceivePointerEvents()
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2500,7 +2500,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
|
||||
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
if (!child.canReceivePointerEvents()
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2680,7 +2680,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
i = childrenCount - 1;
|
||||
}
|
||||
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
if (!child.canReceivePointerEvents()
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
ev.setTargetAccessibilityFocus(false);
|
||||
continue;
|
||||
@@ -2970,15 +2970,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a child view can receive pointer events.
|
||||
* @hide
|
||||
*/
|
||||
private static boolean canViewReceivePointerEvents(@NonNull View child) {
|
||||
return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|
||||
|| child.getAnimation() != null;
|
||||
}
|
||||
|
||||
private float[] getTempPoint() {
|
||||
if (mTempPoint == null) {
|
||||
mTempPoint = new float[2];
|
||||
@@ -7199,6 +7190,46 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
|
||||
final int childrenCount = mChildrenCount;
|
||||
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
|
||||
final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
|
||||
final View[] children = mChildren;
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
|
||||
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
|
||||
if (child == view) {
|
||||
// We've reached the target view.
|
||||
break;
|
||||
}
|
||||
if (!child.canReceivePointerEvents()) {
|
||||
// This child cannot be touched. Skip it.
|
||||
continue;
|
||||
}
|
||||
applyOpToRegionByBounds(touchableRegion, child, Region.Op.DIFFERENCE);
|
||||
}
|
||||
|
||||
// The touchable region should not exceed the bounds of its container.
|
||||
applyOpToRegionByBounds(touchableRegion, this, Region.Op.INTERSECT);
|
||||
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.subtractObscuredTouchableRegion(touchableRegion, this);
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
|
||||
final int[] locationInWindow = new int[2];
|
||||
view.getLocationInWindow(locationInWindow);
|
||||
final int x = locationInWindow[0];
|
||||
final int y = locationInWindow[1];
|
||||
region.op(x, y, x + view.getWidth(), y + view.getHeight(), op);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
|
||||
insets = super.dispatchApplyWindowInsets(insets);
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.view;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Bundle;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
@@ -660,4 +661,17 @@ public interface ViewParent {
|
||||
* @return true if the action was consumed by this ViewParent
|
||||
*/
|
||||
public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
|
||||
|
||||
/**
|
||||
* Given a touchable region of a child, this method reduces region by the bounds of all views on
|
||||
* top of the child for which {@link View#canReceivePointerEvents} returns {@code true}. This
|
||||
* applies recursively for all views in the view hierarchy on top of this one.
|
||||
*
|
||||
* @param touchableRegion The touchable region we want to modify.
|
||||
* @param view A child view of this ViewGroup which indicates the z-order of the touchable
|
||||
* region.
|
||||
* @hide
|
||||
*/
|
||||
default void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user