am 46b9ac0a: Native input dispatch rewrite work in progress.
Merge commit '46b9ac0ae2162309774a7478cd9d4e578747bfc2' into gingerbread * commit '46b9ac0ae2162309774a7478cd9d4e578747bfc2': Native input dispatch rewrite work in progress.
This commit is contained in:
460
services/java/com/android/server/InputManager.java
Normal file
460
services/java/com/android/server/InputManager.java
Normal file
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.server.KeyInputQueue.VirtualKey;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Environment;
|
||||
import android.os.LocalPowerManager;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputTarget;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.RawInputEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManagerPolicy;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/*
|
||||
* Wraps the C++ InputManager and provides its callbacks.
|
||||
*
|
||||
* XXX Tempted to promote this to a first-class service, ie. InputManagerService, to
|
||||
* improve separation of concerns with respect to the window manager.
|
||||
*/
|
||||
public class InputManager {
|
||||
static final String TAG = "InputManager";
|
||||
|
||||
private final Callbacks mCallbacks;
|
||||
private final Context mContext;
|
||||
private final WindowManagerService mWindowManagerService;
|
||||
private final WindowManagerPolicy mWindowManagerPolicy;
|
||||
private final PowerManager mPowerManager;
|
||||
private final PowerManagerService mPowerManagerService;
|
||||
|
||||
private int mTouchScreenConfig;
|
||||
private int mKeyboardConfig;
|
||||
private int mNavigationConfig;
|
||||
|
||||
private static native void nativeInit(Callbacks callbacks);
|
||||
private static native void nativeStart();
|
||||
private static native void nativeSetDisplaySize(int displayId, int width, int height);
|
||||
private static native void nativeSetDisplayOrientation(int displayId, int rotation);
|
||||
|
||||
private static native int nativeGetScanCodeState(int deviceId, int deviceClasses,
|
||||
int scanCode);
|
||||
private static native int nativeGetKeyCodeState(int deviceId, int deviceClasses,
|
||||
int keyCode);
|
||||
private static native int nativeGetSwitchState(int deviceId, int deviceClasses,
|
||||
int sw);
|
||||
private static native boolean nativeHasKeys(int[] keyCodes, boolean[] keyExists);
|
||||
private static native void nativeRegisterInputChannel(InputChannel inputChannel);
|
||||
private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
|
||||
|
||||
// Device class as defined by EventHub.
|
||||
private static final int CLASS_KEYBOARD = 0x00000001;
|
||||
private static final int CLASS_ALPHAKEY = 0x00000002;
|
||||
private static final int CLASS_TOUCHSCREEN = 0x00000004;
|
||||
private static final int CLASS_TRACKBALL = 0x00000008;
|
||||
private static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
|
||||
private static final int CLASS_DPAD = 0x00000020;
|
||||
|
||||
public InputManager(Context context,
|
||||
WindowManagerService windowManagerService,
|
||||
WindowManagerPolicy windowManagerPolicy,
|
||||
PowerManager powerManager,
|
||||
PowerManagerService powerManagerService) {
|
||||
this.mContext = context;
|
||||
this.mWindowManagerService = windowManagerService;
|
||||
this.mWindowManagerPolicy = windowManagerPolicy;
|
||||
this.mPowerManager = powerManager;
|
||||
this.mPowerManagerService = powerManagerService;
|
||||
|
||||
this.mCallbacks = new Callbacks();
|
||||
|
||||
mTouchScreenConfig = Configuration.TOUCHSCREEN_NOTOUCH;
|
||||
mKeyboardConfig = Configuration.KEYBOARD_NOKEYS;
|
||||
mNavigationConfig = Configuration.NAVIGATION_NONAV;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
Slog.i(TAG, "Initializing input manager");
|
||||
nativeInit(mCallbacks);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
Slog.i(TAG, "Starting input manager");
|
||||
nativeStart();
|
||||
}
|
||||
|
||||
public void setDisplaySize(int displayId, int width, int height) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
throw new IllegalArgumentException("Invalid display id or dimensions.");
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
|
||||
nativeSetDisplaySize(displayId, width, height);
|
||||
}
|
||||
|
||||
public void setDisplayOrientation(int displayId, int rotation) {
|
||||
if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) {
|
||||
throw new IllegalArgumentException("Invalid rotation.");
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Setting display #" + displayId + " orientation to " + rotation);
|
||||
nativeSetDisplayOrientation(displayId, rotation);
|
||||
}
|
||||
|
||||
public void getInputConfiguration(Configuration config) {
|
||||
if (config == null) {
|
||||
throw new IllegalArgumentException("config must not be null.");
|
||||
}
|
||||
|
||||
config.touchscreen = mTouchScreenConfig;
|
||||
config.keyboard = mKeyboardConfig;
|
||||
config.navigation = mNavigationConfig;
|
||||
}
|
||||
|
||||
public int getScancodeState(int code) {
|
||||
return nativeGetScanCodeState(0, -1, code);
|
||||
}
|
||||
|
||||
public int getScancodeState(int deviceId, int code) {
|
||||
return nativeGetScanCodeState(deviceId, -1, code);
|
||||
}
|
||||
|
||||
public int getTrackballScancodeState(int code) {
|
||||
return nativeGetScanCodeState(-1, CLASS_TRACKBALL, code);
|
||||
}
|
||||
|
||||
public int getDPadScancodeState(int code) {
|
||||
return nativeGetScanCodeState(-1, CLASS_DPAD, code);
|
||||
}
|
||||
|
||||
public int getKeycodeState(int code) {
|
||||
return nativeGetKeyCodeState(0, -1, code);
|
||||
}
|
||||
|
||||
public int getKeycodeState(int deviceId, int code) {
|
||||
return nativeGetKeyCodeState(deviceId, -1, code);
|
||||
}
|
||||
|
||||
public int getTrackballKeycodeState(int code) {
|
||||
return nativeGetKeyCodeState(-1, CLASS_TRACKBALL, code);
|
||||
}
|
||||
|
||||
public int getDPadKeycodeState(int code) {
|
||||
return nativeGetKeyCodeState(-1, CLASS_DPAD, code);
|
||||
}
|
||||
|
||||
public int getSwitchState(int sw) {
|
||||
return nativeGetSwitchState(-1, -1, sw);
|
||||
}
|
||||
|
||||
public int getSwitchState(int deviceId, int sw) {
|
||||
return nativeGetSwitchState(deviceId, -1, sw);
|
||||
}
|
||||
|
||||
public boolean hasKeys(int[] keyCodes, boolean[] keyExists) {
|
||||
if (keyCodes == null) {
|
||||
throw new IllegalArgumentException("keyCodes must not be null.");
|
||||
}
|
||||
if (keyExists == null) {
|
||||
throw new IllegalArgumentException("keyExists must not be null.");
|
||||
}
|
||||
|
||||
return nativeHasKeys(keyCodes, keyExists);
|
||||
}
|
||||
|
||||
public void registerInputChannel(InputChannel inputChannel) {
|
||||
if (inputChannel == null) {
|
||||
throw new IllegalArgumentException("inputChannel must not be null.");
|
||||
}
|
||||
|
||||
nativeRegisterInputChannel(inputChannel);
|
||||
}
|
||||
|
||||
public void unregisterInputChannel(InputChannel inputChannel) {
|
||||
if (inputChannel == null) {
|
||||
throw new IllegalArgumentException("inputChannel must not be null.");
|
||||
}
|
||||
|
||||
nativeUnregisterInputChannel(inputChannel);
|
||||
}
|
||||
|
||||
// TBD where this really belongs, duplicate copy in WindowManagerService
|
||||
static final int INJECT_FAILED = 0;
|
||||
static final int INJECT_SUCCEEDED = 1;
|
||||
static final int INJECT_NO_PERMISSION = -1;
|
||||
|
||||
/**
|
||||
* Injects a key event into the event system on behalf of an application.
|
||||
* @param event The event to inject.
|
||||
* @param nature The nature of the event.
|
||||
* @param sync If true, waits for the event to be completed before returning.
|
||||
* @param pid The pid of the injecting application.
|
||||
* @param uid The uid of the injecting application.
|
||||
* @return INJECT_SUCCEEDED, INJECT_FAILED or INJECT_NO_PERMISSION
|
||||
*/
|
||||
public int injectKeyEvent(KeyEvent event, int nature, boolean sync, int pid, int uid) {
|
||||
// TODO
|
||||
return INJECT_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a motion event into the event system on behalf of an application.
|
||||
* @param event The event to inject.
|
||||
* @param nature The nature of the event.
|
||||
* @param sync If true, waits for the event to be completed before returning.
|
||||
* @param pid The pid of the injecting application.
|
||||
* @param uid The uid of the injecting application.
|
||||
* @return INJECT_SUCCEEDED, INJECT_FAILED or INJECT_NO_PERMISSION
|
||||
*/
|
||||
public int injectMotionEvent(MotionEvent event, int nature, boolean sync, int pid, int uid) {
|
||||
// TODO
|
||||
return INJECT_FAILED;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
private static final class VirtualKeyDefinition {
|
||||
public int scanCode;
|
||||
|
||||
// configured position data, specified in display coords
|
||||
public int centerX;
|
||||
public int centerY;
|
||||
public int width;
|
||||
public int height;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callbacks from native.
|
||||
*/
|
||||
private class Callbacks {
|
||||
static final String TAG = "InputManager-Callbacks";
|
||||
|
||||
private static final boolean DEBUG_VIRTUAL_KEYS = false;
|
||||
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
|
||||
|
||||
private final InputTargetList mReusableInputTargetList = new InputTargetList();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean isScreenOn() {
|
||||
return mPowerManagerService.isScreenOn();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean isScreenBright() {
|
||||
return mPowerManagerService.isScreenBright();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void virtualKeyFeedback(long whenNanos, int deviceId, int action, int flags,
|
||||
int keyCode, int scanCode, int metaState, long downTimeNanos) {
|
||||
KeyEvent keyEvent = new KeyEvent(downTimeNanos / 1000000,
|
||||
whenNanos / 1000000, action, keyCode, 0, metaState, scanCode, deviceId,
|
||||
flags);
|
||||
|
||||
mWindowManagerService.virtualKeyFeedback(keyEvent);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyConfigurationChanged(long whenNanos,
|
||||
int touchScreenConfig, int keyboardConfig, int navigationConfig) {
|
||||
mTouchScreenConfig = touchScreenConfig;
|
||||
mKeyboardConfig = keyboardConfig;
|
||||
mNavigationConfig = navigationConfig;
|
||||
|
||||
mWindowManagerService.sendNewConfiguration();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
|
||||
mWindowManagerPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public int hackInterceptKey(int deviceId, int type, int scanCode,
|
||||
int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
|
||||
RawInputEvent event = new RawInputEvent();
|
||||
event.deviceId = deviceId;
|
||||
event.type = type;
|
||||
event.scancode = scanCode;
|
||||
event.keycode = keyCode;
|
||||
event.flags = policyFlags;
|
||||
event.value = value;
|
||||
event.when = whenNanos / 1000000;
|
||||
|
||||
return mWindowManagerPolicy.interceptKeyTq(event, isScreenOn);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void goToSleep(long whenNanos) {
|
||||
long when = whenNanos / 1000000;
|
||||
mPowerManager.goToSleep(when);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void pokeUserActivityForKey(long whenNanos) {
|
||||
long when = whenNanos / 1000000;
|
||||
mPowerManagerService.userActivity(when, false,
|
||||
LocalPowerManager.BUTTON_EVENT, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyAppSwitchComing() {
|
||||
mWindowManagerService.mKeyWaiter.appSwitchComing();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean filterTouchEvents() {
|
||||
return mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_filterTouchEvents);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean filterJumpyTouchEvents() {
|
||||
return mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_filterJumpyTouchEvents);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {
|
||||
ArrayList<VirtualKeyDefinition> keys = new ArrayList<VirtualKeyDefinition>();
|
||||
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(
|
||||
"/sys/board_properties/virtualkeys." + deviceName);
|
||||
InputStreamReader isr = new InputStreamReader(fis);
|
||||
BufferedReader br = new BufferedReader(isr, 2048);
|
||||
String str = br.readLine();
|
||||
if (str != null) {
|
||||
String[] it = str.split(":");
|
||||
if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
|
||||
final int N = it.length-6;
|
||||
for (int i=0; i<=N; i+=6) {
|
||||
if (!"0x01".equals(it[i])) {
|
||||
Slog.w(TAG, "Unknown virtual key type at elem #" + i
|
||||
+ ": " + it[i]);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
VirtualKeyDefinition key = new VirtualKeyDefinition();
|
||||
key.scanCode = Integer.parseInt(it[i+1]);
|
||||
key.centerX = Integer.parseInt(it[i+2]);
|
||||
key.centerY = Integer.parseInt(it[i+3]);
|
||||
key.width = Integer.parseInt(it[i+4]);
|
||||
key.height = Integer.parseInt(it[i+5]);
|
||||
if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
|
||||
+ key.scanCode + ": center=" + key.centerX + ","
|
||||
+ key.centerY + " size=" + key.width + "x"
|
||||
+ key.height);
|
||||
keys.add(key);
|
||||
} catch (NumberFormatException e) {
|
||||
Slog.w(TAG, "Bad number at region " + i + " in: "
|
||||
+ str, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
Slog.i(TAG, "No virtual keys found");
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG, "Error reading virtual keys", e);
|
||||
}
|
||||
|
||||
return keys.toArray(new VirtualKeyDefinition[keys.size()]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String[] getExcludedDeviceNames() {
|
||||
ArrayList<String> names = new ArrayList<String>();
|
||||
|
||||
// Read partner-provided list of excluded input devices
|
||||
XmlPullParser parser = null;
|
||||
// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
|
||||
File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
|
||||
FileReader confreader = null;
|
||||
try {
|
||||
confreader = new FileReader(confFile);
|
||||
parser = Xml.newPullParser();
|
||||
parser.setInput(confreader);
|
||||
XmlUtils.beginDocument(parser, "devices");
|
||||
|
||||
while (true) {
|
||||
XmlUtils.nextElement(parser);
|
||||
if (!"device".equals(parser.getName())) {
|
||||
break;
|
||||
}
|
||||
String name = parser.getAttributeValue(null, "name");
|
||||
if (name != null) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// It's ok if the file does not exist.
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
|
||||
} finally {
|
||||
try { if (confreader != null) confreader.close(); } catch (IOException e) { }
|
||||
}
|
||||
|
||||
return names.toArray(new String[names.size()]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public InputTarget[] getKeyEventTargets(KeyEvent event, int nature, int policyFlags) {
|
||||
mReusableInputTargetList.clear();
|
||||
|
||||
mWindowManagerService.getKeyEventTargets(mReusableInputTargetList,
|
||||
event, nature, policyFlags);
|
||||
|
||||
return mReusableInputTargetList.toNullTerminatedArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public InputTarget[] getMotionEventTargets(MotionEvent event, int nature, int policyFlags) {
|
||||
mReusableInputTargetList.clear();
|
||||
|
||||
mWindowManagerService.getMotionEventTargets(mReusableInputTargetList,
|
||||
event, nature, policyFlags);
|
||||
|
||||
return mReusableInputTargetList.toNullTerminatedArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
105
services/java/com/android/server/InputTargetList.java
Normal file
105
services/java/com/android/server/InputTargetList.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputTarget;
|
||||
|
||||
/**
|
||||
* A specialized list of input targets backed by an array.
|
||||
*
|
||||
* This class is part of an InputManager optimization to avoid allocating and copying
|
||||
* input target arrays unnecessarily on return from JNI callbacks. Internally, it keeps
|
||||
* an array full of demand-allocated InputTarget objects that it recycles each time the
|
||||
* list is cleared. The used portion of the array is padded with a null.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InputTargetList {
|
||||
private InputTarget[] mArray;
|
||||
private int mCount;
|
||||
|
||||
/**
|
||||
* Creates an empty input target list.
|
||||
*/
|
||||
public InputTargetList() {
|
||||
mArray = new InputTarget[8];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the input target list.
|
||||
*/
|
||||
public void clear() {
|
||||
if (mCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int count = mCount;
|
||||
mCount = 0;
|
||||
mArray[count] = mArray[0];
|
||||
while (count > 0) {
|
||||
count -= 1;
|
||||
mArray[count].recycle();
|
||||
}
|
||||
// mArray[0] could be set to null here but we do it in toNullTerminatedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new input target to the input target list.
|
||||
* @param inputChannel The input channel of the target window.
|
||||
* @param flags Input target flags.
|
||||
* @param timeoutNanos The input dispatch timeout (before ANR) in nanoseconds or -1 if none.
|
||||
* @param xOffset An offset to add to motion X coordinates during delivery.
|
||||
* @param yOffset An offset to add to motion Y coordinates during delivery.
|
||||
*/
|
||||
public void add(InputChannel inputChannel, int flags, long timeoutNanos,
|
||||
float xOffset, float yOffset) {
|
||||
if (inputChannel == null) {
|
||||
throw new IllegalArgumentException("inputChannel must not be null");
|
||||
}
|
||||
|
||||
if (mCount + 1 == mArray.length) {
|
||||
InputTarget[] oldArray = mArray;
|
||||
mArray = new InputTarget[oldArray.length * 2];
|
||||
System.arraycopy(oldArray, 0, mArray, 0, mCount);
|
||||
}
|
||||
|
||||
// Grab InputTarget from tail (after used section) if available.
|
||||
InputTarget inputTarget = mArray[mCount + 1];
|
||||
if (inputTarget == null) {
|
||||
inputTarget = new InputTarget();
|
||||
}
|
||||
inputTarget.mInputChannel = inputChannel;
|
||||
inputTarget.mFlags = flags;
|
||||
inputTarget.mTimeoutNanos = timeoutNanos;
|
||||
inputTarget.mXOffset = xOffset;
|
||||
inputTarget.mYOffset = yOffset;
|
||||
|
||||
mArray[mCount] = inputTarget;
|
||||
mCount += 1;
|
||||
// mArray[mCount] could be set to null here but we do it in toNullTerminatedArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input targets as a null-terminated array.
|
||||
* @return The input target array.
|
||||
*/
|
||||
public InputTarget[] toNullTerminatedArray() {
|
||||
mArray[mCount] = null;
|
||||
return mArray;
|
||||
}
|
||||
}
|
||||
@@ -298,7 +298,9 @@ public abstract class KeyInputQueue {
|
||||
|
||||
mHapticFeedbackCallback = hapticFeedbackCallback;
|
||||
|
||||
readExcludedDevices();
|
||||
if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
readExcludedDevices();
|
||||
}
|
||||
|
||||
PowerManager pm = (PowerManager)context.getSystemService(
|
||||
Context.POWER_SERVICE);
|
||||
@@ -311,7 +313,9 @@ public abstract class KeyInputQueue {
|
||||
mFirst.next = mLast;
|
||||
mLast.prev = mFirst;
|
||||
|
||||
mThread.start();
|
||||
if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
mThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisplay(Display display) {
|
||||
|
||||
@@ -101,6 +101,9 @@ import android.view.IRotationWatcher;
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
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 class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
"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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// -------------------------------------------------------------
|
||||
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
pw.print(" mWallpaperYStep="); pw.println(mWallpaperYStep);
|
||||
}
|
||||
}
|
||||
|
||||
String makeInputChannelName() {
|
||||
return Integer.toHexString(System.identityHashCode(this))
|
||||
+ " " + mAttrs.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -9275,7 +9673,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
// 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 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user