Native input dispatch rewrite work in progress.
The old dispatch mechanism has been left in place and continues to
be used by default for now. To enable native input dispatch,
edit the ENABLE_NATIVE_DISPATCH constant in WindowManagerPolicy.
Includes part of the new input event NDK API. Some details TBD.
To wire up input dispatch, as the ViewRoot adds a window to the
window session it receives an InputChannel object as an output
argument. The InputChannel encapsulates the file descriptors for a
shared memory region and two pipe end-points. The ViewRoot then
provides the InputChannel to the InputQueue. Behind the
scenes, InputQueue simply attaches handlers to the native PollLoop object
that underlies the MessageQueue. This way MessageQueue doesn't need
to know anything about input dispatch per-se, it just exposes (in native
code) a PollLoop that other components can use to monitor file descriptor
state changes.
There can be zero or more targets for any given input event. Each
input target is specified by its input channel and some parameters
including flags, an X/Y coordinate offset, and the dispatch timeout.
An input target can request either synchronous dispatch (for foreground apps)
or asynchronous dispatch (fire-and-forget for wallpapers and "outside"
targets). Currently, finding the appropriate input targets for an event
requires a call back into the WindowManagerServer from native code.
In the future this will be refactored to avoid most of these callbacks
except as required to handle pending focus transitions.
End-to-end event dispatch mostly works!
To do: event injection, rate limiting, ANRs, testing, optimization, etc.
Change-Id: I8c36b2b9e0a2d27392040ecda0f51b636456de25
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ac5e3f1..9bc3931 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -101,6 +101,9 @@
import android.view.IWindow;
import android.view.IWindowManager;
import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InputQueue;
+import android.view.InputTarget;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RawInputEvent;
@@ -157,6 +160,8 @@
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;
+ static final boolean ENABLE_NATIVE_INPUT_DISPATCH =
+ WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH;
static private LatencyTimer lt;
static final boolean PROFILE_ORIENTATION = false;
@@ -497,10 +502,12 @@
final KeyWaiter mKeyWaiter = new KeyWaiter();
final KeyQ mQueue;
+ final InputManager mInputManager;
final InputDispatcherThread mInputThread;
// Who is holding the screen on.
Session mHoldingScreenOn;
+ PowerManager.WakeLock mHoldingScreenWakeLock;
boolean mTurnOnScreen;
@@ -650,8 +657,16 @@
}
mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
- mQueue = new KeyQ();
+ mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+ "KEEP_SCREEN_ON_FLAG");
+ mHoldingScreenWakeLock.setReferenceCounted(false);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ mInputManager = new InputManager(context, this, mPolicy, pmc, mPowerManager);
+ } else {
+ mInputManager = null;
+ }
+ mQueue = new KeyQ();
mInputThread = new InputDispatcherThread();
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
@@ -666,7 +681,11 @@
}
}
- mInputThread.start();
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ mInputManager.start();
+ } else {
+ mInputThread.start();
+ }
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
@@ -1859,7 +1878,7 @@
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
- Rect outContentInsets) {
+ Rect outContentInsets, InputChannel outInputChannel) {
int res = mPolicy.checkAddPermission(attrs);
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
@@ -1878,7 +1897,12 @@
mDisplay = wm.getDefaultDisplay();
mInitialDisplayWidth = mDisplay.getWidth();
mInitialDisplayHeight = mDisplay.getHeight();
- mQueue.setDisplay(mDisplay);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ mInputManager.setDisplaySize(0,
+ mInitialDisplayWidth, mInitialDisplayHeight);
+ } else {
+ mQueue.setDisplay(mDisplay);
+ }
reportNewConfig = true;
}
@@ -1971,6 +1995,17 @@
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
}
+
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ if (outInputChannel != null) {
+ String name = win.makeInputChannelName();
+ InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
+ win.mInputChannel = inputChannels[0];
+ inputChannels[1].transferToBinderOutParameter(outInputChannel);
+
+ mInputManager.registerInputChannel(win.mInputChannel);
+ }
+ }
// From now on, no exceptions or errors allowed!
@@ -4354,7 +4389,11 @@
"getSwitchState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return KeyInputQueue.getSwitchState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getSwitchState(sw);
+ } else {
+ return KeyInputQueue.getSwitchState(sw);
+ }
}
public int getSwitchStateForDevice(int devid, int sw) {
@@ -4362,7 +4401,11 @@
"getSwitchStateForDevice()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return KeyInputQueue.getSwitchState(devid, sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getSwitchState(devid, sw);
+ } else {
+ return KeyInputQueue.getSwitchState(devid, sw);
+ }
}
public int getScancodeState(int sw) {
@@ -4370,7 +4413,11 @@
"getScancodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getScancodeState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getScancodeState(sw);
+ } else {
+ return mQueue.getScancodeState(sw);
+ }
}
public int getScancodeStateForDevice(int devid, int sw) {
@@ -4378,7 +4425,11 @@
"getScancodeStateForDevice()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getScancodeState(devid, sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getScancodeState(devid, sw);
+ } else {
+ return mQueue.getScancodeState(devid, sw);
+ }
}
public int getTrackballScancodeState(int sw) {
@@ -4386,7 +4437,11 @@
"getTrackballScancodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getTrackballScancodeState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getTrackballScancodeState(sw);
+ } else {
+ return mQueue.getTrackballScancodeState(sw);
+ }
}
public int getDPadScancodeState(int sw) {
@@ -4394,7 +4449,11 @@
"getDPadScancodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getDPadScancodeState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getDPadScancodeState(sw);
+ } else {
+ return mQueue.getDPadScancodeState(sw);
+ }
}
public int getKeycodeState(int sw) {
@@ -4402,7 +4461,11 @@
"getKeycodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getKeycodeState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getKeycodeState(sw);
+ } else {
+ return mQueue.getKeycodeState(sw);
+ }
}
public int getKeycodeStateForDevice(int devid, int sw) {
@@ -4410,7 +4473,11 @@
"getKeycodeStateForDevice()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getKeycodeState(devid, sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getKeycodeState(devid, sw);
+ } else {
+ return mQueue.getKeycodeState(devid, sw);
+ }
}
public int getTrackballKeycodeState(int sw) {
@@ -4418,7 +4485,11 @@
"getTrackballKeycodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getTrackballKeycodeState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getTrackballKeycodeState(sw);
+ } else {
+ return mQueue.getTrackballKeycodeState(sw);
+ }
}
public int getDPadKeycodeState(int sw) {
@@ -4426,11 +4497,19 @@
"getDPadKeycodeState()")) {
throw new SecurityException("Requires READ_INPUT_STATE permission");
}
- return mQueue.getDPadKeycodeState(sw);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.getDPadKeycodeState(sw);
+ } else {
+ return mQueue.getDPadKeycodeState(sw);
+ }
}
public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
- return KeyInputQueue.hasKeys(keycodes, keyExists);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ return mInputManager.hasKeys(keycodes, keyExists);
+ } else {
+ return KeyInputQueue.hasKeys(keycodes, keyExists);
+ }
}
public void enableScreenAfterBoot() {
@@ -4575,7 +4654,11 @@
mLayoutNeeded = true;
startFreezingDisplayLocked();
Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
- mQueue.setOrientation(rotation);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ mInputManager.setDisplayOrientation(0, rotation);
+ } else {
+ mQueue.setOrientation(rotation);
+ }
if (mDisplayEnabled) {
Surface.setOrientation(0, rotation, animFlags);
}
@@ -4906,7 +4989,11 @@
if (mDisplay == null) {
return false;
}
- mQueue.getInputConfiguration(config);
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ mInputManager.getInputConfiguration(config);
+ } else {
+ mQueue.getInputConfiguration(config);
+ }
// Use the effective "visual" dimensions based on current rotation
final boolean rotated = (mRotation == Surface.ROTATION_90
@@ -4989,6 +5076,291 @@
// -------------------------------------------------------------
// Input Events and Focus Management
// -------------------------------------------------------------
+
+ public void getKeyEventTargets(InputTargetList inputTargets,
+ KeyEvent event, int nature, int policyFlags) {
+ if (DEBUG_INPUT) Slog.v(TAG, "Dispatch key: " + event);
+
+ // TODO what do we do with mDisplayFrozen?
+ // TODO what do we do with focus.mToken.paused?
+
+ WindowState focus = getFocusedWindow();
+ wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
+
+ addInputTarget(inputTargets, focus, InputTarget.FLAG_SYNC);
+ }
+
+ // Target of Motion events
+ WindowState mTouchFocus;
+
+ // Windows above the target who would like to receive an "outside"
+ // touch event for any down events outside of them.
+ // (This is a linked list by way of WindowState.mNextOutsideTouch.)
+ WindowState mOutsideTouchTargets;
+
+ private void clearTouchFocus() {
+ mTouchFocus = null;
+ mOutsideTouchTargets = null;
+ }
+
+ public void getMotionEventTargets(InputTargetList inputTargets,
+ MotionEvent event, int nature, int policyFlags) {
+ if (nature == InputQueue.INPUT_EVENT_NATURE_TRACKBALL) {
+ // More or less the same as for keys...
+ WindowState focus = getFocusedWindow();
+ wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
+
+ addInputTarget(inputTargets, focus, InputTarget.FLAG_SYNC);
+ return;
+ }
+
+ int action = event.getAction();
+
+ // TODO detect cheek presses somewhere... either here or in native code
+
+ final boolean screenWasOff = (policyFlags & WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
+
+ WindowState target = mTouchFocus;
+
+ if (action == MotionEvent.ACTION_UP) {
+ // let go of our target
+ mPowerManager.logPointerUpEvent();
+ clearTouchFocus();
+ } else if (action == MotionEvent.ACTION_DOWN) {
+ // acquire a new target
+ mPowerManager.logPointerDownEvent();
+
+ synchronized (mWindowMap) {
+ if (mTouchFocus != null) {
+ // this is weird, we got a pen down, but we thought it was
+ // already down!
+ // XXX: We should probably send an ACTION_UP to the current
+ // target.
+ Slog.w(TAG, "Pointer down received while already down in: "
+ + mTouchFocus);
+ clearTouchFocus();
+ }
+
+ // ACTION_DOWN is special, because we need to lock next events to
+ // the window we'll land onto.
+ final int x = (int) event.getX();
+ final int y = (int) event.getY();
+
+ final ArrayList windows = mWindows;
+ final int N = windows.size();
+ WindowState topErrWindow = null;
+ final Rect tmpRect = mTempRect;
+ for (int i=N-1; i>=0; i--) {
+ WindowState child = (WindowState)windows.get(i);
+ //Slog.i(TAG, "Checking dispatch to: " + child);
+ final int flags = child.mAttrs.flags;
+ if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
+ if (topErrWindow == null) {
+ topErrWindow = child;
+ }
+ }
+ if (!child.isVisibleLw()) {
+ //Slog.i(TAG, "Not visible!");
+ continue;
+ }
+ if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ //Slog.i(TAG, "Not touchable!");
+ if ((flags & WindowManager.LayoutParams
+ .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
+ child.mNextOutsideTouch = mOutsideTouchTargets;
+ mOutsideTouchTargets = child;
+ }
+ continue;
+ }
+ tmpRect.set(child.mFrame);
+ if (child.mTouchableInsets == ViewTreeObserver
+ .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
+ // The touch is inside of the window if it is
+ // inside the frame, AND the content part of that
+ // frame that was given by the application.
+ tmpRect.left += child.mGivenContentInsets.left;
+ tmpRect.top += child.mGivenContentInsets.top;
+ tmpRect.right -= child.mGivenContentInsets.right;
+ tmpRect.bottom -= child.mGivenContentInsets.bottom;
+ } else if (child.mTouchableInsets == ViewTreeObserver
+ .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
+ // The touch is inside of the window if it is
+ // inside the frame, AND the visible part of that
+ // frame that was given by the application.
+ tmpRect.left += child.mGivenVisibleInsets.left;
+ tmpRect.top += child.mGivenVisibleInsets.top;
+ tmpRect.right -= child.mGivenVisibleInsets.right;
+ tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
+ }
+ final int touchFlags = flags &
+ (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ if (tmpRect.contains(x, y) || touchFlags == 0) {
+ //Slog.i(TAG, "Using this target!");
+ if (!screenWasOff || (flags &
+ WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
+ mTouchFocus = child;
+ } else {
+ //Slog.i(TAG, "Waking, skip!");
+ mTouchFocus = null;
+ }
+ break;
+ }
+
+ if ((flags & WindowManager.LayoutParams
+ .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
+ child.mNextOutsideTouch = mOutsideTouchTargets;
+ mOutsideTouchTargets = child;
+ //Slog.i(TAG, "Adding to outside target list: " + child);
+ }
+ }
+
+ // if there's an error window but it's not accepting
+ // focus (typically because it is not yet visible) just
+ // wait for it -- any other focused window may in fact
+ // be in ANR state.
+ if (topErrWindow != null && mTouchFocus != topErrWindow) {
+ mTouchFocus = null;
+ }
+ }
+
+ target = mTouchFocus;
+ }
+
+ if (target != null) {
+ wakeupIfNeeded(target, eventType(event));
+ }
+
+ int targetFlags = 0;
+ if (target == null) {
+ // In this case we are either dropping the event, or have received
+ // a move or up without a down. It is common to receive move
+ // events in such a way, since this means the user is moving the
+ // pointer without actually pressing down. All other cases should
+ // be atypical, so let's log them.
+ if (action != MotionEvent.ACTION_MOVE) {
+ Slog.w(TAG, "No window to dispatch pointer action " + action);
+ }
+ } else {
+ if ((target.mAttrs.flags &
+ WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
+ //target wants to ignore fat touch events
+ boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(event);
+ //explicit flag to return without processing event further
+ boolean returnFlag = false;
+ if((action == MotionEvent.ACTION_DOWN)) {
+ mFatTouch = false;
+ if(cheekPress) {
+ mFatTouch = true;
+ returnFlag = true;
+ }
+ } else {
+ if(action == MotionEvent.ACTION_UP) {
+ if(mFatTouch) {
+ //earlier even was invalid doesnt matter if current up is cheekpress or not
+ mFatTouch = false;
+ returnFlag = true;
+ } else if(cheekPress) {
+ //cancel the earlier event
+ targetFlags |= InputTarget.FLAG_CANCEL;
+ action = MotionEvent.ACTION_CANCEL;
+ }
+ } else if(action == MotionEvent.ACTION_MOVE) {
+ if(mFatTouch) {
+ //two cases here
+ //an invalid down followed by 0 or moves(valid or invalid)
+ //a valid down, invalid move, more moves. want to ignore till up
+ returnFlag = true;
+ } else if(cheekPress) {
+ //valid down followed by invalid moves
+ //an invalid move have to cancel earlier action
+ targetFlags |= InputTarget.FLAG_CANCEL;
+ action = MotionEvent.ACTION_CANCEL;
+ if (DEBUG_INPUT) Slog.v(TAG, "Sending cancel for invalid ACTION_MOVE");
+ //note that the subsequent invalid moves will not get here
+ mFatTouch = true;
+ }
+ }
+ } //else if action
+ if(returnFlag) {
+ return;
+ }
+ } //end if target
+ }
+
+ synchronized (mWindowMap) {
+ if (target != null && ! target.isVisibleLw()) {
+ target = null;
+ }
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ while (mOutsideTouchTargets != null) {
+ addInputTarget(inputTargets, mOutsideTouchTargets,
+ InputTarget.FLAG_OUTSIDE | targetFlags);
+ mOutsideTouchTargets = mOutsideTouchTargets.mNextOutsideTouch;
+ }
+ }
+
+ // If we sent an initial down to the wallpaper, then continue
+ // sending events until the final up.
+ // Alternately if we are on top of the wallpaper, then the wallpaper also
+ // gets to see this movement.
+ if (mSendingPointersToWallpaper ||
+ (target != null && action == MotionEvent.ACTION_DOWN
+ && mWallpaperTarget == target
+ && target.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD)) {
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if ((wallpaper.mAttrs.flags &
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ continue;
+ }
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mSendingPointersToWallpaper = true;
+ break;
+ case MotionEvent.ACTION_UP:
+ mSendingPointersToWallpaper = false;
+ break;
+ }
+
+ addInputTarget(inputTargets, wallpaper, targetFlags);
+ }
+ }
+ }
+
+ if (target != null) {
+ addInputTarget(inputTargets, target, InputTarget.FLAG_SYNC | targetFlags);
+ }
+ }
+ }
+
+ private void addInputTarget(InputTargetList inputTargets, WindowState window, int flags) {
+ if (window.mInputChannel == null) {
+ return;
+ }
+
+ long timeoutNanos = -1;
+ IApplicationToken appToken = window.getAppToken();
+
+ if (appToken != null) {
+ try {
+ timeoutNanos = appToken.getKeyDispatchingTimeout() * 1000000;
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Could not get key dispatching timeout.", ex);
+ }
+ }
+
+ inputTargets.add(window.mInputChannel, flags, timeoutNanos,
+ - window.mFrame.left, - window.mFrame.top);
+ }
private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
long curTime = SystemClock.uptimeMillis();
@@ -5499,10 +5871,18 @@
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
- final int result = dispatchKey(newEvent, pid, uid);
- if (sync) {
- mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+
+ final int result;
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ result = mInputManager.injectKeyEvent(newEvent,
+ InputQueue.INPUT_EVENT_NATURE_KEY, sync, pid, uid);
+ } else {
+ result = dispatchKey(newEvent, pid, uid);
+ if (sync) {
+ mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+ }
}
+
Binder.restoreCallingIdentity(ident);
switch (result) {
case INJECT_NO_PERMISSION:
@@ -5527,10 +5907,18 @@
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
- final int result = dispatchPointer(null, ev, pid, uid);
- if (sync) {
- mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+
+ final int result;
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ result = mInputManager.injectMotionEvent(ev,
+ InputQueue.INPUT_EVENT_NATURE_TOUCH, sync, pid, uid);
+ } else {
+ result = dispatchPointer(null, ev, pid, uid);
+ if (sync) {
+ mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+ }
}
+
Binder.restoreCallingIdentity(ident);
switch (result) {
case INJECT_NO_PERMISSION:
@@ -5555,10 +5943,18 @@
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
- final int result = dispatchTrackball(null, ev, pid, uid);
- if (sync) {
- mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+
+ final int result;
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ result = mInputManager.injectMotionEvent(ev,
+ InputQueue.INPUT_EVENT_NATURE_TRACKBALL, sync, pid, uid);
+ } else {
+ result = dispatchTrackball(null, ev, pid, uid);
+ if (sync) {
+ mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+ }
}
+
Binder.restoreCallingIdentity(ident);
switch (result) {
case INJECT_NO_PERMISSION:
@@ -6326,14 +6722,8 @@
private class KeyQ extends KeyInputQueue
implements KeyInputQueue.FilterCallback {
- PowerManager.WakeLock mHoldingScreen;
-
KeyQ() {
super(mContext, WindowManagerService.this);
- PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
- "KEEP_SCREEN_ON_FLAG");
- mHoldingScreen.setReferenceCounted(false);
}
@Override
@@ -6445,21 +6835,6 @@
return FILTER_KEEP;
}
}
-
- /**
- * Must be called with the main window manager lock held.
- */
- void setHoldScreenLocked(boolean holding) {
- boolean state = mHoldingScreen.isHeld();
- if (holding != state) {
- if (holding) {
- mHoldingScreen.acquire();
- } else {
- mPolicy.screenOnStoppedLw();
- mHoldingScreen.release();
- }
- }
- }
}
public boolean detectSafeMode() {
@@ -6788,8 +7163,14 @@
}
public int add(IWindow window, WindowManager.LayoutParams attrs,
+ int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
+ return addWindow(this, window, attrs, viewVisibility, outContentInsets,
+ outInputChannel);
+ }
+
+ public int addWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, Rect outContentInsets) {
- return addWindow(this, window, attrs, viewVisibility, outContentInsets);
+ return addWindow(this, window, attrs, viewVisibility, outContentInsets, null);
}
public void remove(IWindow window) {
@@ -7158,6 +7539,9 @@
int mSurfaceLayer;
float mSurfaceAlpha;
+ // Input channel
+ InputChannel mInputChannel;
+
WindowState(Session s, IWindow c, WindowToken token,
WindowState attachedWindow, WindowManager.LayoutParams a,
int viewVisibility) {
@@ -8182,6 +8566,15 @@
// Ignore if it has already been removed (usually because
// we are doing this as part of processing a death note.)
}
+
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ if (mInputChannel != null) {
+ mInputManager.unregisterInputChannel(mInputChannel);
+
+ mInputChannel.dispose();
+ mInputChannel = null;
+ }
+ }
}
private class DeathRecipient implements IBinder.DeathRecipient {
@@ -8424,6 +8817,11 @@
pw.print(" mWallpaperYStep="); pw.println(mWallpaperYStep);
}
}
+
+ String makeInputChannelName() {
+ return Integer.toHexString(System.identityHashCode(this))
+ + " " + mAttrs.getTitle();
+ }
@Override
public String toString() {
@@ -9275,7 +9673,8 @@
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
- return new Session(client, inputContext);
+ Session session = new Session(client, inputContext);
+ return session;
}
public boolean inputMethodClientHasFocus(IInputMethodClient client) {
@@ -10773,7 +11172,7 @@
if (DEBUG_FREEZE) Slog.v(TAG, "Layout: mDisplayFrozen=" + mDisplayFrozen
+ " holdScreen=" + holdScreen);
if (!mDisplayFrozen) {
- mQueue.setHoldScreenLocked(holdScreen != null);
+ setHoldScreenLocked(holdScreen != null);
if (screenBrightness < 0 || screenBrightness > 1.0f) {
mPowerManager.setScreenBrightnessOverride(-1);
} else {
@@ -10804,6 +11203,21 @@
// be enabled, because the window obscured flags have changed.
enableScreenIfNeededLocked();
}
+
+ /**
+ * Must be called with the main window manager lock held.
+ */
+ void setHoldScreenLocked(boolean holding) {
+ boolean state = mHoldingScreenWakeLock.isHeld();
+ if (holding != state) {
+ if (holding) {
+ mHoldingScreenWakeLock.acquire();
+ } else {
+ mPolicy.screenOnStoppedLw();
+ mHoldingScreenWakeLock.release();
+ }
+ }
+ }
void requestAnimationLocked(long delay) {
if (!mAnimationPending) {
@@ -11138,8 +11552,13 @@
return;
}
- pw.println("Input State:");
- mQueue.dump(pw, " ");
+ if (ENABLE_NATIVE_INPUT_DISPATCH) {
+ pw.println("Input Dispatcher State:");
+ mInputManager.dump(pw);
+ } else {
+ pw.println("Input State:");
+ mQueue.dump(pw, " ");
+ }
pw.println(" ");
synchronized(mWindowMap) {