From ca9bc702df5c14a89c9b8b0109a05894bf74962e Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 11 Feb 2014 14:32:56 -0800 Subject: [PATCH] Add support for injecting events into ActivityContainers. Modified ActivityView to inject touch events it receives back into its activity container. The container then injects the event into the input system along with the display id of the underlying virtual display. Change-Id: I23d018a2f7dd30f1f833f522eb7f143b43d8e637 --- core/java/android/app/ActivityView.java | 26 +++++++++++++++++ core/java/android/app/IActivityContainer.aidl | 2 ++ .../hardware/input/InputManagerInternal.java | 3 ++ .../server/am/ActivityStackSupervisor.java | 29 +++++++++++++++++-- .../server/input/InputManagerService.java | 16 ++++++++-- ...droid_server_input_InputManagerService.cpp | 8 ++--- 6 files changed, 74 insertions(+), 10 deletions(-) diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 8acd19beea015..48ec420bb435f 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -27,6 +27,9 @@ import android.os.RemoteException; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.TextureView.SurfaceTextureListener; @@ -112,6 +115,29 @@ public class ActivityView extends ViewGroup { } } + private boolean injectInputEvent(InputEvent event) { + try { + return mActivityContainer != null && mActivityContainer.injectEvent(event); + } catch (RemoteException e) { + return false; + } + } + + @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); + } + public boolean isAttachedToDisplay() { return mSurface != null; } diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl index abd296a20b9f6..5b80e06e1611b 100644 --- a/core/java/android/app/IActivityContainer.aidl +++ b/core/java/android/app/IActivityContainer.aidl @@ -20,6 +20,7 @@ import android.app.IActivityContainerCallback; import android.content.Intent; import android.content.IIntentSender; import android.os.IBinder; +import android.view.InputEvent; import android.view.Surface; /** @hide */ @@ -30,4 +31,5 @@ interface IActivityContainer { int startActivity(in Intent intent); int startActivityIntentSender(in IIntentSender intentSender); int getDisplayId(); + boolean injectEvent(in InputEvent event); } diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java index ecd32ea8b41cf..8be94d0f7e850 100644 --- a/core/java/android/hardware/input/InputManagerInternal.java +++ b/core/java/android/hardware/input/InputManagerInternal.java @@ -17,6 +17,7 @@ package android.hardware.input; import android.hardware.display.DisplayViewport; +import android.view.InputEvent; /** * Input manager local system service interface. @@ -30,4 +31,6 @@ public abstract class InputManagerInternal { */ public abstract void setDisplayViewports(DisplayViewport defaultViewport, DisplayViewport externalTouchViewport); + + public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 8f8b2a27ad6ac..6ed30d9e0c095 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -61,6 +61,8 @@ import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.VirtualDisplay; +import android.hardware.input.InputManager; +import android.hardware.input.InputManagerInternal; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -81,9 +83,11 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.view.Display; import android.view.DisplayInfo; +import android.view.InputEvent; import android.view.Surface; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.os.TransferPipe; +import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService.PendingActivityLaunch; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.wm.WindowManagerService; @@ -225,6 +229,8 @@ public final class ActivityStackSupervisor implements DisplayListener { /** Mapping from displayId to display current state */ private SparseArray mActivityDisplays = new SparseArray(); + InputManagerInternal mInputManagerInternal; + public ActivityStackSupervisor(ActivityManagerService service) { mService = service; PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); @@ -255,6 +261,8 @@ public final class ActivityStackSupervisor implements DisplayListener { createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); + + mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } } @@ -2941,7 +2949,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void attachToDisplay(int displayId) throws RemoteException { + public void attachToDisplay(int displayId) { synchronized (mService) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); if (activityDisplay == null) { @@ -2952,13 +2960,28 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public int getDisplayId() throws RemoteException { + public int getDisplayId() { if (mActivityDisplay != null) { return mActivityDisplay.mDisplayId; } return -1; } + @Override + public boolean injectEvent(InputEvent event) { + final long origId = Binder.clearCallingIdentity(); + try { + if (mActivityDisplay != null) { + return mInputManagerInternal.injectInputEvent(event, + mActivityDisplay.mDisplayId, + InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + } + return false; + } finally { + Binder.restoreCallingIdentity(origId); + } + } + private void detachLocked() { if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); @@ -2972,7 +2995,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void detachFromDisplay() throws RemoteException { + public void detachFromDisplay() { synchronized (mService) { detachLocked(); } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 1522fd130750b..3aa38510072d8 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -16,6 +16,7 @@ package com.android.server.input; +import android.view.Display; import com.android.internal.R; import com.android.internal.util.XmlUtils; import com.android.server.DisplayThread; @@ -170,7 +171,7 @@ public class InputManagerService extends IInputManager.Stub InputWindowHandle inputWindowHandle, boolean monitor); private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); - private static native int nativeInjectInputEvent(long ptr, InputEvent event, + private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags); private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles); @@ -509,6 +510,10 @@ public class InputManagerService extends IInputManager.Stub @Override // Binder call public boolean injectInputEvent(InputEvent event, int mode) { + return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); + } + + private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) { if (event == null) { throw new IllegalArgumentException("event must not be null"); } @@ -523,7 +528,7 @@ public class InputManagerService extends IInputManager.Stub final long ident = Binder.clearCallingIdentity(); final int result; try { - result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, + result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode, INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); } finally { Binder.restoreCallingIdentity(ident); @@ -1588,7 +1593,7 @@ public class InputManagerService extends IInputManager.Stub synchronized (mInputFilterLock) { if (!mDisconnected) { - nativeInjectInputEvent(mPtr, event, 0, 0, + nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, policyFlags | WindowManagerPolicy.FLAG_FILTERED); } @@ -1685,5 +1690,10 @@ public class InputManagerService extends IInputManager.Stub DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { setDisplayViewportsInternal(defaultViewport, externalTouchViewport); } + + @Override + public boolean injectInputEvent(InputEvent event, int displayId, int mode) { + return injectInputEventInternal(event, displayId, mode); + } } } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 321776c32bc99..9fe00826a6b4a 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1153,7 +1153,7 @@ static void nativeSetInputFilterEnabled(JNIEnv* env, jclass clazz, } static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, - jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid, + jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid, jint syncMode, jint timeoutMillis, jint policyFlags) { NativeInputManager* im = reinterpret_cast(ptr); @@ -1166,7 +1166,7 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, } return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( - & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis, + & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj); @@ -1176,7 +1176,7 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, } return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( - motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis, + motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else { jniThrowRuntimeException(env, "Invalid input event type."); @@ -1336,7 +1336,7 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) nativeUnregisterInputChannel }, { "nativeSetInputFilterEnabled", "(JZ)V", (void*) nativeSetInputFilterEnabled }, - { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I", + { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I", (void*) nativeInjectInputEvent }, { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V", (void*) nativeSetInputWindows },