Merge "Let the activity embedded in ActivityView can be directly touched"
This commit is contained in:
@@ -28,15 +28,12 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceSession;
|
||||
@@ -51,9 +48,7 @@ import dalvik.system.CloseGuard;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity container that allows launching activities into itself and does input forwarding.
|
||||
* <p>Creation of this view is only allowed to callers who have
|
||||
* {@link android.Manifest.permission#INJECT_EVENTS} permission.
|
||||
* Activity container that allows launching activities into itself.
|
||||
* <p>Activity launching into this container is restricted by the same rules that apply to launching
|
||||
* on VirtualDisplays.
|
||||
* @hide
|
||||
@@ -76,9 +71,8 @@ public class ActivityView extends ViewGroup {
|
||||
private StateCallback mActivityViewCallback;
|
||||
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
private IInputForwarder mInputForwarder;
|
||||
// Temp container to store view coordinates on screen.
|
||||
private final int[] mLocationOnScreen = new int[2];
|
||||
// Temp container to store view coordinates in window.
|
||||
private final int[] mLocationInWindow = new int[2];
|
||||
|
||||
private TaskStackListener mTaskStackListener;
|
||||
|
||||
@@ -280,7 +274,7 @@ public class ActivityView extends ViewGroup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an update of {@link ActivityView}'s location on screen to properly set touch exclude
|
||||
* Triggers an update of {@link ActivityView}'s location in window to properly set touch exclude
|
||||
* regions and avoid focus switches by touches on this view.
|
||||
*/
|
||||
public void onLocationChanged() {
|
||||
@@ -295,45 +289,14 @@ public class ActivityView extends ViewGroup {
|
||||
/** Send current location and size to the WM to set tap exclude region for this view. */
|
||||
private void updateLocation() {
|
||||
try {
|
||||
getLocationOnScreen(mLocationOnScreen);
|
||||
getLocationInWindow(mLocationInWindow);
|
||||
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
|
||||
mLocationOnScreen[0], mLocationOnScreen[1], getWidth(), getHeight());
|
||||
mLocationInWindow[0], mLocationInWindow[1], getWidth(), getHeight());
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return injectInputEvent(event) || super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
|
||||
if (injectInputEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
private boolean injectInputEvent(MotionEvent event) {
|
||||
if (mInputForwarder != null) {
|
||||
try {
|
||||
// The touch event that the ActivityView gets is in View space, but the event needs
|
||||
// to get forwarded in screen space. This offsets the touch event by the location
|
||||
// the ActivityView is on screen and sends it to the input forwarder.
|
||||
getLocationOnScreen(mLocationOnScreen);
|
||||
event.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
|
||||
return mInputForwarder.forwardEvent(event);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class SurfaceCallback implements SurfaceHolder.Callback {
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder surfaceHolder) {
|
||||
@@ -416,7 +379,6 @@ public class ActivityView extends ViewGroup {
|
||||
}
|
||||
|
||||
mTmpTransaction.show(mRootSurfaceControl).apply();
|
||||
mInputForwarder = InputManager.getInstance().createInputForwarder(displayId);
|
||||
mTaskStackListener = new TaskStackListenerImpl();
|
||||
try {
|
||||
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
|
||||
@@ -432,9 +394,6 @@ public class ActivityView extends ViewGroup {
|
||||
|
||||
mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
|
||||
|
||||
if (mInputForwarder != null) {
|
||||
mInputForwarder = null;
|
||||
}
|
||||
cleanTapExcludeRegion();
|
||||
|
||||
if (mTaskStackListener != null) {
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
|
||||
import android.graphics.Region;
|
||||
import android.os.IBinder;
|
||||
import android.view.IWindow;
|
||||
import android.view.InputChannel;
|
||||
|
||||
/**
|
||||
* Functions as a handle for a window that can receive input.
|
||||
@@ -94,6 +94,10 @@ public final class InputWindowHandle {
|
||||
// Display this input is on.
|
||||
public int displayId;
|
||||
|
||||
// If this value is set to a valid display ID, it indicates this window is a portal which
|
||||
// transports the touch of this window to the display indicated by portalToDisplayId.
|
||||
public int portalToDisplayId = INVALID_DISPLAY;
|
||||
|
||||
private native void nativeDispose();
|
||||
|
||||
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
|
||||
|
||||
@@ -55,6 +55,7 @@ static struct {
|
||||
jfieldID ownerUid;
|
||||
jfieldID inputFeatures;
|
||||
jfieldID displayId;
|
||||
jfieldID portalToDisplayId;
|
||||
} gInputWindowHandleClassInfo;
|
||||
|
||||
static Mutex gHandleMutex;
|
||||
@@ -154,6 +155,8 @@ bool NativeInputWindowHandle::updateInfo() {
|
||||
gInputWindowHandleClassInfo.inputFeatures);
|
||||
mInfo.displayId = env->GetIntField(obj,
|
||||
gInputWindowHandleClassInfo.displayId);
|
||||
mInfo.portalToDisplayId = env->GetIntField(obj,
|
||||
gInputWindowHandleClassInfo.portalToDisplayId);
|
||||
|
||||
jobject inputApplicationHandleObj = env->GetObjectField(obj,
|
||||
gInputWindowHandleClassInfo.inputApplicationHandle);
|
||||
@@ -307,6 +310,9 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
|
||||
|
||||
GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
|
||||
"displayId", "I");
|
||||
|
||||
GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz,
|
||||
"portalToDisplayId", "I");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.FLAG_PRIVATE;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.InsetsState.TYPE_IME;
|
||||
import static android.view.Surface.ROTATION_0;
|
||||
import static android.view.Surface.ROTATION_180;
|
||||
@@ -43,6 +44,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
|
||||
import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
|
||||
@@ -140,9 +142,11 @@ import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.Region.Op;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.os.Binder;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
@@ -157,6 +161,7 @@ import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputWindowHandle;
|
||||
import android.view.InsetsState.InternalInsetType;
|
||||
import android.view.MagnificationSpec;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
@@ -515,6 +520,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
|
||||
private final InsetsStateController mInsetsStateController;
|
||||
|
||||
private SurfaceControl mParentSurfaceControl;
|
||||
private InputWindowHandle mPortalWindowHandle;
|
||||
|
||||
// Last systemUiVisibility we received from status bar.
|
||||
private int mLastStatusBarVisibility = 0;
|
||||
// Last systemUiVisibility we dispatched to windows.
|
||||
@@ -2410,10 +2418,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
win.getTouchableRegion(mTmpRegion);
|
||||
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
|
||||
}
|
||||
for (int i = mTapExcludeProvidingWindows.size() - 1; i >= 0; i--) {
|
||||
final WindowState win = mTapExcludeProvidingWindows.valueAt(i);
|
||||
win.amendTapExcludeRegion(mTouchExcludeRegion);
|
||||
}
|
||||
amendWindowTapExcludeRegion(mTouchExcludeRegion);
|
||||
// TODO(multi-display): Support docked stacks on secondary displays.
|
||||
if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStack() != null) {
|
||||
mDividerControllerLocked.getTouchRegion(mTmpRect);
|
||||
@@ -2425,6 +2430,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Union the region with all the tap exclude region provided by windows on this display.
|
||||
*
|
||||
* @param inOutRegion The region to be amended.
|
||||
*/
|
||||
void amendWindowTapExcludeRegion(Region inOutRegion) {
|
||||
for (int i = mTapExcludeProvidingWindows.size() - 1; i >= 0; i--) {
|
||||
final WindowState win = mTapExcludeProvidingWindows.valueAt(i);
|
||||
win.amendTapExcludeRegion(inOutRegion);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void switchUser() {
|
||||
super.switchUser();
|
||||
@@ -3586,6 +3603,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
private void updateBounds() {
|
||||
calculateBounds(mDisplayInfo, mTmpBounds);
|
||||
setBounds(mTmpBounds);
|
||||
if (mPortalWindowHandle != null && mParentSurfaceControl != null) {
|
||||
mPortalWindowHandle.touchableRegion.getBounds(mTmpRect);
|
||||
if (!mTmpBounds.equals(mTmpRect)) {
|
||||
mPortalWindowHandle.touchableRegion.set(mTmpBounds);
|
||||
mPendingTransaction.setInputWindowInfo(mParentSurfaceControl, mPortalWindowHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determines the current display bounds based on the current state
|
||||
@@ -4830,15 +4854,43 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
|| mWmService.mForceDesktopModeOnExternalDisplays;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Re-parent the DisplayContent's top surfaces, {@link #mWindowingLayer} and
|
||||
* {@link #mOverlayLayer} to the specified surfaceControl.
|
||||
*
|
||||
* @param surfaceControlHandle The new SurfaceControl, where the DisplayContent's
|
||||
* surfaces will be re-parented to.
|
||||
* @param sc The new SurfaceControl, where the DisplayContent's surfaces will be re-parented to.
|
||||
*/
|
||||
void reparentDisplayContent(SurfaceControl sc) {
|
||||
mPendingTransaction.reparent(mWindowingLayer, sc)
|
||||
.reparent(mOverlayLayer, sc);
|
||||
mParentSurfaceControl = sc;
|
||||
if (mPortalWindowHandle == null) {
|
||||
mPortalWindowHandle = createPortalWindowHandle(sc.toString());
|
||||
}
|
||||
mPendingTransaction.setInputWindowInfo(sc, mPortalWindowHandle)
|
||||
.reparent(mWindowingLayer, sc).reparent(mOverlayLayer, sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a portal window handle for input. This window transports any touch to the display
|
||||
* indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window.
|
||||
*
|
||||
* @param name The name of the portal window handle.
|
||||
* @return the new portal window handle.
|
||||
*/
|
||||
private InputWindowHandle createPortalWindowHandle(String name) {
|
||||
// Let surface flinger to set the display ID of this input window handle because we don't
|
||||
// know which display the parent surface control is on.
|
||||
final InputWindowHandle portalWindowHandle = new InputWindowHandle(
|
||||
null /* inputApplicationHandle */, null /* clientWindow */, INVALID_DISPLAY);
|
||||
portalWindowHandle.name = name;
|
||||
portalWindowHandle.token = new Binder();
|
||||
portalWindowHandle.layoutParamsFlags =
|
||||
FLAG_SPLIT_TOUCH | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL;
|
||||
getBounds(mTmpBounds);
|
||||
portalWindowHandle.touchableRegion.set(mTmpBounds);
|
||||
portalWindowHandle.scaleFactor = 1f;
|
||||
portalWindowHandle.ownerPid = Process.myPid();
|
||||
portalWindowHandle.ownerUid = Process.myUid();
|
||||
portalWindowHandle.portalToDisplayId = mDisplayId;
|
||||
return portalWindowHandle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,9 @@ class TapExcludeRegionHolder {
|
||||
void amendRegion(Region region, Rect boundingRegion) {
|
||||
for (int i = mTapExcludeRects.size() - 1; i>= 0 ; --i) {
|
||||
final Rect rect = mTapExcludeRects.valueAt(i);
|
||||
rect.intersect(boundingRegion);
|
||||
if (boundingRegion != null) {
|
||||
rect.intersect(boundingRegion);
|
||||
}
|
||||
region.union(rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,18 @@ public class TaskTapPointerEventListener implements PointerEventListener {
|
||||
// method target window will lose the focus.
|
||||
return;
|
||||
}
|
||||
final Region windowTapExcludeRegion = Region.obtain();
|
||||
mDisplayContent.amendWindowTapExcludeRegion(windowTapExcludeRegion);
|
||||
if (windowTapExcludeRegion.contains(x, y)) {
|
||||
windowTapExcludeRegion.recycle();
|
||||
// The user is tapping on the window tap exclude region. We don't move this
|
||||
// display to top. A window tap exclude region, for example, may be set by an
|
||||
// ActivityView, and the region would match the bounds of both the ActivityView
|
||||
// and the virtual display in it. In this case, we would take the tap that is on
|
||||
// the embedded virtual display instead of this display.
|
||||
return;
|
||||
}
|
||||
windowTapExcludeRegion.recycle();
|
||||
WindowContainer parent = mDisplayContent.getParent();
|
||||
if (parent != null && parent.getTopChild() != mDisplayContent) {
|
||||
parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
|
||||
@@ -81,9 +93,6 @@ public class TaskTapPointerEventListener implements PointerEventListener {
|
||||
|
||||
@Override
|
||||
public void onPointerEvent(MotionEvent motionEvent) {
|
||||
if (motionEvent.getDisplayId() != getDisplayId()) {
|
||||
return;
|
||||
}
|
||||
switch (motionEvent.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
final int x = (int) motionEvent.getX();
|
||||
|
||||
@@ -6532,8 +6532,13 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
/**
|
||||
* Update a tap exclude region with a rectangular area in the window identified by the provided
|
||||
* id. 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.
|
||||
* id. Touches down on this region will not:
|
||||
* <ol>
|
||||
* <li>Switch focus to this window.</li>
|
||||
* <li>Move the display of this window to top.</li>
|
||||
* <li>Send the touch events to this window.</li>
|
||||
* </ol>
|
||||
* Passing an empty rect will remove the area from the exclude region of this window.
|
||||
*/
|
||||
void updateTapExcludeRegion(IWindow client, int regionId, int left, int top, int width,
|
||||
int height) {
|
||||
|
||||
@@ -536,7 +536,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
private final Point mSurfacePosition = new Point();
|
||||
|
||||
/**
|
||||
* A region inside of this window to be excluded from touch-related focus switches.
|
||||
* A region inside of this window to be excluded from touch.
|
||||
*/
|
||||
private TapExcludeRegionHolder mTapExcludeRegionHolder;
|
||||
|
||||
@@ -2168,6 +2168,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
region.set(mTmpRect);
|
||||
cropRegionToStackBoundsIfNeeded(region);
|
||||
subtractTouchExcludeRegionIfNeeded(region);
|
||||
} else if (modal && mTapExcludeRegionHolder != null) {
|
||||
final Region touchExcludeRegion = Region.obtain();
|
||||
amendTapExcludeRegion(touchExcludeRegion);
|
||||
if (!touchExcludeRegion.isEmpty()) {
|
||||
// Remove touch modal because there are some areas that cannot be touched.
|
||||
flags |= FLAG_NOT_TOUCH_MODAL;
|
||||
// Give it a large touchable region at first because it was touch modal. The window
|
||||
// might be moved on the display, so the touchable region should be large enough to
|
||||
// ensure it covers the whole display, no matter where it is moved.
|
||||
getDisplayContent().getBounds(mTmpRect);
|
||||
final int dw = mTmpRect.width();
|
||||
final int dh = mTmpRect.height();
|
||||
region.set(-dw, -dh, dw + dw, dh + dh);
|
||||
// Subtract the area that cannot be touched.
|
||||
region.op(touchExcludeRegion, Region.Op.DIFFERENCE);
|
||||
}
|
||||
touchExcludeRegion.recycle();
|
||||
} else {
|
||||
// Not modal or full screen modal
|
||||
getTouchableRegion(region);
|
||||
@@ -2837,6 +2855,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
}
|
||||
cropRegionToStackBoundsIfNeeded(outRegion);
|
||||
subtractTouchExcludeRegionIfNeeded(outRegion);
|
||||
}
|
||||
|
||||
private void cropRegionToStackBoundsIfNeeded(Region region) {
|
||||
@@ -2854,6 +2873,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
region.op(mTmpRect, Region.Op.INTERSECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this window has areas that cannot be touched, we subtract those areas from its touchable
|
||||
* region.
|
||||
*/
|
||||
private void subtractTouchExcludeRegionIfNeeded(Region touchableRegion) {
|
||||
if (mTapExcludeRegionHolder == null) {
|
||||
return;
|
||||
}
|
||||
final Region touchExcludeRegion = Region.obtain();
|
||||
amendTapExcludeRegion(touchExcludeRegion);
|
||||
if (!touchExcludeRegion.isEmpty()) {
|
||||
touchableRegion.op(touchExcludeRegion, Region.Op.DIFFERENCE);
|
||||
}
|
||||
touchExcludeRegion.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a focus change. Must be called with no locks held, and consistently
|
||||
* from the same serialized thread (such as dispatched from a handler).
|
||||
@@ -4728,11 +4763,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
mTapExcludeRegionHolder.updateRegion(regionId, left, top, width, height);
|
||||
// Trigger touch exclude region update on current display.
|
||||
currentDisplay.updateTouchExcludeRegion();
|
||||
// Trigger touchable region update for this window.
|
||||
currentDisplay.getInputMonitor().updateInputWindowsLw(true /* force */);
|
||||
}
|
||||
|
||||
/** Union the region with current tap exclude region that this window provides. */
|
||||
/**
|
||||
* Union the region with current tap exclude region that this window provides.
|
||||
*
|
||||
* @param region The region to be amended. It is on the screen coordinates.
|
||||
*/
|
||||
void amendTapExcludeRegion(Region region) {
|
||||
mTapExcludeRegionHolder.amendRegion(region, getBounds());
|
||||
final Region tempRegion = Region.obtain();
|
||||
mTmpRect.set(mWindowFrames.mFrame);
|
||||
mTmpRect.offsetTo(0, 0);
|
||||
mTapExcludeRegionHolder.amendRegion(tempRegion, mTmpRect);
|
||||
// The region held by the holder is on the window coordinates. We need to translate it to
|
||||
// the screen coordinates.
|
||||
tempRegion.translate(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top);
|
||||
region.op(tempRegion, Region.Op.UNION);
|
||||
tempRegion.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user