Move some APIs from window manager to input manager.
Simplified input injection API down to just one call.
Removed all input state reading API. It was only used by the
window manager policy and required a permission that applications
could not obtain. READ_INPUT_STATE is now unused and deprecated.
Change-Id: I41278141586ddee9468cae0fb59ff0dced6cbc00
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9dde51c..c5d7b91 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -45,6 +45,7 @@
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
import android.hardware.SerialManager;
+import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
@@ -325,9 +326,9 @@
}});
registerService(INPUT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new InputManager(ctx);
- }});
+ public Object createService(ContextImpl ctx) {
+ return new InputManager(ctx);
+ }});
registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e4f7950..f955713 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -23,6 +23,7 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -35,6 +36,7 @@
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.IWindowManager;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -859,11 +861,30 @@
*/
public void sendKeySync(KeyEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectKeyEvent(event, true);
- } catch (RemoteException e) {
+
+ long downTime = event.getDownTime();
+ long eventTime = event.getEventTime();
+ int action = event.getAction();
+ int code = event.getKeyCode();
+ int repeatCount = event.getRepeatCount();
+ int metaState = event.getMetaState();
+ int deviceId = event.getDeviceId();
+ int scancode = event.getScanCode();
+ int source = event.getSource();
+ int flags = event.getFlags();
+ if (source == InputDevice.SOURCE_UNKNOWN) {
+ source = InputDevice.SOURCE_KEYBOARD;
}
+ if (eventTime == 0) {
+ eventTime = SystemClock.uptimeMillis();
+ }
+ if (downTime == 0) {
+ downTime = eventTime;
+ }
+ KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
+ deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
+ InputManager.injectInputEvent(newEvent,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -902,11 +923,10 @@
*/
public void sendPointerSync(MotionEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectPointerEvent(event, true);
- } catch (RemoteException e) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
}
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -922,11 +942,10 @@
*/
public void sendTrackballEventSync(MotionEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectTrackballEvent(event, true);
- } catch (RemoteException e) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
+ event.setSource(InputDevice.SOURCE_TRACKBALL);
}
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 85061bb..c2abce5 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,6 +16,22 @@
package android.hardware.input;
+import android.view.InputDevice;
+import android.view.InputEvent;
+
/** @hide */
interface IInputManager {
+ // Gets input device information.
+ InputDevice getInputDevice(int deviceId);
+ int[] getInputDeviceIds();
+
+ // Reports whether the hardware supports the given keys; returns true if successful
+ boolean hasKeys(int deviceId, int sourceMask, in int[] keyCodes, out boolean[] keyExists);
+
+ // Temporarily changes the pointer speed.
+ void tryPointerSpeed(int speed);
+
+ // Injects an input event into the system. To inject into windows owned by other
+ // applications, the caller must have the INJECT_EVENTS permission.
+ boolean injectInputEvent(in InputEvent ev, int mode);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6093404..ba64035f 100755
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -31,10 +31,20 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.InputDevice;
+import android.view.InputEvent;
import android.view.KeyCharacterMap;
+import android.view.WindowManagerPolicy;
import android.view.KeyCharacterMap.UnavailableException;
import java.util.ArrayList;
@@ -53,6 +63,8 @@
public final class InputManager {
private static final String TAG = "InputManager";
+ private static final IInputManager sIm;
+
private final Context mContext;
// Used to simulate a persistent data store.
@@ -118,6 +130,53 @@
public static final String META_DATA_KEYBOARD_LAYOUTS =
"android.hardware.input.metadata.KEYBOARD_LAYOUTS";
+ /**
+ * Pointer Speed: The minimum (slowest) pointer speed (-7).
+ * @hide
+ */
+ public static final int MIN_POINTER_SPEED = -7;
+
+ /**
+ * Pointer Speed: The maximum (fastest) pointer speed (7).
+ * @hide
+ */
+ public static final int MAX_POINTER_SPEED = 7;
+
+ /**
+ * Pointer Speed: The default pointer speed (0).
+ * @hide
+ */
+ public static final int DEFAULT_POINTER_SPEED = 0;
+
+ /**
+ * Input Event Injection Synchronization Mode: None.
+ * Never blocks. Injection is asynchronous and is assumed always to be successful.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0; // see InputDispatcher.h
+
+ /**
+ * Input Event Injection Synchronization Mode: Wait for result.
+ * Waits for previous events to be dispatched so that the input dispatcher can
+ * determine whether input event injection will be permitted based on the current
+ * input focus. Does not wait for the input event to finish being handled
+ * by the application.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; // see InputDispatcher.h
+
+ /**
+ * Input Event Injection Synchronization Mode: Wait for finish.
+ * Waits for the event to be delivered to the application and handled.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; // see InputDispatcher.h
+
+ static {
+ IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
+ sIm = IInputManager.Stub.asInterface(b);
+ }
+
/** @hide */
public InputManager(Context context) {
mContext = context;
@@ -296,6 +355,160 @@
return null;
}
+ /**
+ * Gets the mouse pointer speed.
+ * <p>
+ * Only returns the permanent mouse pointer speed. Ignores any temporary pointer
+ * speed set by {@link #tryPointerSpeed}.
+ * </p>
+ *
+ * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public int getPointerSpeed() {
+ int speed = DEFAULT_POINTER_SPEED;
+ try {
+ speed = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED);
+ } catch (SettingNotFoundException snfe) {
+ }
+ return speed;
+ }
+
+ /**
+ * Sets the mouse pointer speed.
+ * <p>
+ * Requires {@link android.Manifest.permissions.WRITE_SETTINGS}.
+ * </p>
+ *
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public void setPointerSpeed(int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED, speed);
+ }
+
+ /**
+ * Changes the mouse pointer speed temporarily, but does not save the setting.
+ * <p>
+ * Requires {@link android.Manifest.permission.SET_POINTER_SPEED}.
+ * </p>
+ *
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public void tryPointerSpeed(int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ try {
+ sIm.tryPointerSpeed(speed);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not set temporary pointer speed.", ex);
+ }
+ }
+
+ /**
+ * Gets information about the input device with the specified id.
+ * @param id The device id.
+ * @return The input device or null if not found.
+ *
+ * @hide
+ */
+ public static InputDevice getInputDevice(int id) {
+ try {
+ return sIm.getInputDevice(id);
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not get input device information.", ex);
+ }
+ }
+
+ /**
+ * Gets the ids of all input devices in the system.
+ * @return The input device ids.
+ *
+ * @hide
+ */
+ public static int[] getInputDeviceIds() {
+ try {
+ return sIm.getInputDeviceIds();
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not get input device ids.", ex);
+ }
+ }
+
+ /**
+ * Queries the framework about whether any physical keys exist on the
+ * any keyboard attached to the device that are capable of producing the given
+ * array of key codes.
+ *
+ * @param keyCodes The array of key codes to query.
+ * @return A new array of the same size as the key codes array whose elements
+ * are set to true if at least one attached keyboard supports the corresponding key code
+ * at the same index in the key codes array.
+ *
+ * @hide
+ */
+ public static boolean[] deviceHasKeys(int[] keyCodes) {
+ boolean[] ret = new boolean[keyCodes.length];
+ try {
+ sIm.hasKeys(-1, InputDevice.SOURCE_ANY, keyCodes, ret);
+ } catch (RemoteException e) {
+ // no fallback; just return the empty array
+ }
+ return ret;
+ }
+
+ /**
+ * Injects an input event into the event system on behalf of an application.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
+ * <p>
+ * Requires {@link android.Manifest.permission.INJECT_EVENTS} to inject into
+ * windows that are owned by other applications.
+ * </p><p>
+ * Make sure you correctly set the event time and input source of the event
+ * before calling this method.
+ * </p>
+ *
+ * @param event The event to inject.
+ * @param mode The synchronization mode. One of:
+ * {@link #INJECT_INPUT_EVENT_MODE_ASYNC},
+ * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT}, or
+ * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH}.
+ * @return True if input event injection succeeded.
+ *
+ * @hide
+ */
+ public static boolean injectInputEvent(InputEvent event, int mode) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+ if (mode != INJECT_INPUT_EVENT_MODE_ASYNC
+ && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
+ && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
+ throw new IllegalArgumentException("mode is invalid");
+ }
+
+ try {
+ return sIm.injectInputEvent(event, mode);
+ } catch (RemoteException ex) {
+ return false;
+ }
+ }
+
private static String makeKeyboardLayoutDescriptor(String packageName,
String receiverName, String keyboardName) {
return packageName + "/" + receiverName + "/" + keyboardName;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index eb030de..8fe8e40 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,15 +65,6 @@
// Is the device configured to have a full system bar for larger screens?
boolean hasSystemNavBar();
- // These can only be called when injecting events to your own window,
- // or by holding the INJECT_EVENTS permission. These methods may block
- // until pending input events are finished being dispatched even when 'sync' is false.
- // Avoid calling these methods on your UI thread or use the 'NoWait' version instead.
- boolean injectKeyEvent(in KeyEvent ev, boolean sync);
- boolean injectPointerEvent(in MotionEvent ev, boolean sync);
- boolean injectTrackballEvent(in MotionEvent ev, boolean sync);
- boolean injectInputEventNoWait(in InputEvent ev);
-
// These can only be called when holding the MANAGE_APP_TOKENS permission.
void pauseKeyDispatching(IBinder token);
void resumeKeyDispatching(IBinder token);
@@ -128,26 +119,6 @@
void setAnimationScale(int which, float scale);
void setAnimationScales(in float[] scales);
- // These require the READ_INPUT_STATE permission.
- int getSwitchState(int sw);
- int getSwitchStateForDevice(int devid, int sw);
- int getScancodeState(int sw);
- int getScancodeStateForDevice(int devid, int sw);
- int getTrackballScancodeState(int sw);
- int getDPadScancodeState(int sw);
- int getKeycodeState(int sw);
- int getKeycodeStateForDevice(int devid, int sw);
- int getTrackballKeycodeState(int sw);
- int getDPadKeycodeState(int sw);
- InputChannel monitorInput(String inputChannelName);
-
- // Report whether the hardware supports the given keys; returns true if successful
- boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
-
- // Get input device information.
- InputDevice getInputDevice(int deviceId);
- int[] getInputDeviceIds();
-
// For testing
void setInTouchMode(boolean showFocus);
@@ -220,11 +191,6 @@
void statusBarVisibilityChanged(int visibility);
/**
- * Called by the settings application to temporarily set the pointer speed.
- */
- void setPointerSpeed(int speed);
-
- /**
* Block until the given window has been drawn to the screen.
*/
void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 91e47e6..93a0185 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,9 +16,9 @@
package android.view;
+import android.hardware.input.InputManager;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
@@ -301,13 +301,7 @@
* @return The input device or null if not found.
*/
public static InputDevice getDevice(int id) {
- IWindowManager wm = Display.getWindowManager();
- try {
- return wm.getInputDevice(id);
- } catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get input device information from Window Manager.", ex);
- }
+ return InputManager.getInputDevice(id);
}
/**
@@ -315,13 +309,7 @@
* @return The input device ids.
*/
public static int[] getDeviceIds() {
- IWindowManager wm = Display.getWindowManager();
- try {
- return wm.getInputDeviceIds();
- } catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get input device ids from Window Manager.", ex);
- }
+ return InputManager.getInputDeviceIds();
}
/**
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 98cce5efe..b03f086 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -19,10 +19,9 @@
import android.text.method.MetaKeyKeyListener;
import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
-import android.os.RemoteException;
+import android.hardware.input.InputManager;
import android.util.SparseArray;
-import java.io.Reader;
import java.lang.Character;
/**
@@ -528,10 +527,7 @@
* @return True if at least one attached keyboard supports the specified key code.
*/
public static boolean deviceHasKey(int keyCode) {
- int[] codeArray = new int[1];
- codeArray[0] = keyCode;
- boolean[] ret = deviceHasKeys(codeArray);
- return ret[0];
+ return InputManager.deviceHasKeys(new int[] { keyCode })[0];
}
/**
@@ -545,14 +541,7 @@
* at the same index in the key codes array.
*/
public static boolean[] deviceHasKeys(int[] keyCodes) {
- boolean[] ret = new boolean[keyCodes.length];
- IWindowManager wm = Display.getWindowManager();
- try {
- wm.hasKeys(keyCodes, ret);
- } catch (RemoteException e) {
- // no fallback; just return the empty array
- }
- return ret;
+ return InputManager.deviceHasKeys(keyCodes);
}
/**
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index cf9cafc..491cd67 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -349,6 +349,10 @@
* between it and the policy.
*/
public interface WindowManagerFuncs {
+ public static final int LID_ABSENT = -1;
+ public static final int LID_CLOSED = 0;
+ public static final int LID_OPEN = 1;
+
/**
* Ask the window manager to re-evaluate the system UI flags.
*/
@@ -362,6 +366,16 @@
InputEventReceiver.Factory inputEventReceiverFactory,
String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
boolean hasFocus, boolean touchFullscreen);
+
+ /**
+ * Returns a code that describes the current state of the lid switch.
+ */
+ public int getLidState();
+
+ /**
+ * Creates an input channel that will receive all input from the input dispatcher.
+ */
+ public InputChannel monitorInput(String name);
}
/**
@@ -943,10 +957,10 @@
public void setRotationLw(int rotation);
/**
- * Called when the system is mostly done booting to determine whether
+ * Called when the system is mostly done booting to set whether
* the system should go into safe mode.
*/
- public boolean detectSafeMode();
+ public void setSafeMode(boolean safeMode);
/**
* Called when the system is mostly done booting.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5ae12b6..00faa41 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1200,7 +1200,8 @@
android:protectionLevel="signature|system" />
<!-- Allows an application to retrieve the current state of keys and
- switches. This is only for use by the system.-->
+ switches. This is only for use by the system.
+ @deprecated The API that used this permission has been removed. -->
<permission android:name="android.permission.READ_INPUT_STATE"
android:label="@string/permlab_readInputState"
android:description="@string/permdesc_readInputState"