diff options
author | Jason Gerecke <killertofu@gmail.com> | 2014-01-27 18:30:37 -0800 |
---|---|---|
committer | Michael Wright <michaelwr@google.com> | 2014-03-10 15:54:21 -0700 |
commit | d6396d67201fb2b64d13070324bb115c9c23b08a (patch) | |
tree | 1a4e3278bc72fc189cfe8358ed21ad5269ce92c4 | |
parent | 724cc1f04f117ee27583d015b414a5ba4540d3b1 (diff) | |
download | frameworks_base-d6396d67201fb2b64d13070324bb115c9c23b08a.zip frameworks_base-d6396d67201fb2b64d13070324bb115c9c23b08a.tar.gz frameworks_base-d6396d67201fb2b64d13070324bb115c9c23b08a.tar.bz2 |
Allow persistence of input device calibration
This patch extends the PersistentDataStore store to read and write
input device calibration data. A new SET_INPUT_CALIBRATION permission
grants apps the ability to update this information, and a new
TouchCalibration class is used to wrap the raw calibration data.
Change-Id: I4daac2b15ef03616ea5b068c1e77bebd0ce7b8c1
-rw-r--r-- | core/java/android/hardware/input/IInputManager.aidl | 6 | ||||
-rw-r--r-- | core/java/android/hardware/input/InputManager.java | 38 | ||||
-rw-r--r-- | core/java/android/hardware/input/TouchCalibration.aidl | 19 | ||||
-rw-r--r-- | core/java/android/hardware/input/TouchCalibration.java | 126 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 8 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/InputManagerService.java | 35 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/PersistentDataStore.java | 73 |
8 files changed, 308 insertions, 1 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index f1e7e98..4214115 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -19,6 +19,7 @@ package android.hardware.input; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.KeyboardLayout; import android.hardware.input.IInputDevicesChangedListener; +import android.hardware.input.TouchCalibration; import android.os.IBinder; import android.view.InputDevice; import android.view.InputEvent; @@ -39,6 +40,11 @@ interface IInputManager { // applications, the caller must have the INJECT_EVENTS permission. boolean injectInputEvent(in InputEvent ev, int mode); + // Calibrate input device position + TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor); + void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, + in TouchCalibration calibration); + // Keyboard layouts configuration. KeyboardLayout[] getKeyboardLayouts(); KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index a2aeafb..ece5d82 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -500,6 +500,44 @@ public final class InputManager { } /** + * Gets the TouchCalibration applied to the specified input device's coordinates. + * + * @param inputDeviceDescriptor The input device descriptor. + * @return The TouchCalibration currently assigned for use with the given + * input device. If none is set, an identity TouchCalibration is returned. + * + * @hide + */ + public TouchCalibration getTouchCalibration(String inputDeviceDescriptor) { + try { + return mIm.getTouchCalibrationForInputDevice(inputDeviceDescriptor); + } catch (RemoteException ex) { + Log.w(TAG, "Could not get calibration matrix for input device.", ex); + return TouchCalibration.IDENTITY; + } + } + + /** + * Sets the TouchCalibration to apply to the specified input device's coordinates. + * <p> + * This method may have the side-effect of causing the input device in question + * to be reconfigured. Requires {@link android.Manifest.permissions.SET_INPUT_CALIBRATION}. + * </p> + * + * @param inputDeviceDescriptor The input device descriptor. + * @param calibration The calibration to be applied + * + * @hide + */ + public void setTouchCalibration(String inputDeviceDescriptor, TouchCalibration calibration) { + try { + mIm.setTouchCalibrationForInputDevice(inputDeviceDescriptor, calibration); + } catch (RemoteException ex) { + Log.w(TAG, "Could not set calibration matrix for input device.", ex); + } + } + + /** * Gets the mouse pointer speed. * <p> * Only returns the permanent mouse pointer speed. Ignores any temporary pointer diff --git a/core/java/android/hardware/input/TouchCalibration.aidl b/core/java/android/hardware/input/TouchCalibration.aidl new file mode 100644 index 0000000..2c28774 --- /dev/null +++ b/core/java/android/hardware/input/TouchCalibration.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 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 android.hardware.input; + +parcelable TouchCalibration; diff --git a/core/java/android/hardware/input/TouchCalibration.java b/core/java/android/hardware/input/TouchCalibration.java new file mode 100644 index 0000000..025fad0 --- /dev/null +++ b/core/java/android/hardware/input/TouchCalibration.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 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 android.hardware.input; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Encapsulates calibration data for input devices. + * + * @hide + */ +public class TouchCalibration implements Parcelable { + + public static final TouchCalibration IDENTITY = new TouchCalibration(); + + public static final Parcelable.Creator<TouchCalibration> CREATOR + = new Parcelable.Creator<TouchCalibration>() { + public TouchCalibration createFromParcel(Parcel in) { + return new TouchCalibration(in); + } + + public TouchCalibration[] newArray(int size) { + return new TouchCalibration[size]; + } + }; + + private final float mXScale, mXYMix, mXOffset; + private final float mYXMix, mYScale, mYOffset; + + /** + * Create a new TouchCalibration initialized to the identity transformation. + */ + public TouchCalibration() { + this(1,0,0,0,1,0); + } + + /** + * Create a new TouchCalibration from affine transformation paramters. + * @param xScale Influence of input x-axis value on output x-axis value. + * @param xyMix Influence of input y-axis value on output x-axis value. + * @param xOffset Constant offset to be applied to output x-axis value. + * @param yXMix Influence of input x-axis value on output y-axis value. + * @param yScale Influence of input y-axis value on output y-axis value. + * @param yOffset Constant offset to be applied to output y-axis value. + */ + public TouchCalibration(float xScale, float xyMix, float xOffset, + float yxMix, float yScale, float yOffset) { + mXScale = xScale; + mXYMix = xyMix; + mXOffset = xOffset; + mYXMix = yxMix; + mYScale = yScale; + mYOffset = yOffset; + } + + public TouchCalibration(Parcel in) { + mXScale = in.readFloat(); + mXYMix = in.readFloat(); + mXOffset = in.readFloat(); + mYXMix = in.readFloat(); + mYScale = in.readFloat(); + mYOffset = in.readFloat(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeFloat(mXScale); + dest.writeFloat(mXYMix); + dest.writeFloat(mXOffset); + dest.writeFloat(mYXMix); + dest.writeFloat(mYScale); + dest.writeFloat(mYOffset); + } + + @Override + public int describeContents() { + return 0; + } + + public float[] getAffineTransform() { + return new float[] { mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset }; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof TouchCalibration) { + TouchCalibration cal = (TouchCalibration)obj; + + return (cal.mXScale == mXScale) && + (cal.mXYMix == mXYMix) && + (cal.mXOffset == mXOffset) && + (cal.mYXMix == mYXMix) && + (cal.mYScale == mYScale) && + (cal.mYOffset == mYOffset); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Float.floatToIntBits(mXScale) ^ + Float.floatToIntBits(mXYMix) ^ + Float.floatToIntBits(mXOffset) ^ + Float.floatToIntBits(mYXMix) ^ + Float.floatToIntBits(mYScale) ^ + Float.floatToIntBits(mYOffset); + } +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4c0ddeb..b99cb90 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2069,6 +2069,14 @@ android:description="@string/permdesc_setPointerSpeed" android:protectionLevel="signature" /> + <!-- Allows low-level access to setting input device calibration. + <p>Not for use by normal applications. + @hide --> + <permission android:name="android.permission.SET_INPUT_CALIBRATION" + android:label="@string/permlab_setInputCalibration" + android:description="@string/permdesc_setInputCalibration" + android:protectionLevel="signature" /> + <!-- Allows low-level access to setting the keyboard layout. <p>Not for use by third-party applications. @hide --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index afb7085..f1bcf65 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2012,6 +2012,10 @@ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_accessNetworkConditions">Allows an application to listen for observations on network conditions. Should never be needed for normal apps.</string> + <string name="permlab_setInputCalibration">change input device calibration</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_setInputCalibration">Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps.</string> + <!-- Policy administration --> <!-- Title of policy access to limiting the user's password choices --> diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index e49382e..16972f6 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -52,6 +52,7 @@ import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; import android.hardware.input.InputManagerInternal; import android.hardware.input.KeyboardLayout; +import android.hardware.input.TouchCalibration; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -700,6 +701,40 @@ public class InputManagerService extends IInputManager.Stub mTempFullKeyboards.clear(); } + @Override // Binder call + public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor) { + if (inputDeviceDescriptor == null) { + throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); + } + + synchronized (mDataStore) { + return mDataStore.getTouchCalibration(inputDeviceDescriptor); + } + } + + @Override // Binder call + public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, + TouchCalibration calibration) { + if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION, + "setTouchCalibrationForInputDevice()")) { + throw new SecurityException("Requires SET_INPUT_CALIBRATION permission"); + } + if (inputDeviceDescriptor == null) { + throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); + } + if (calibration == null) { + throw new IllegalArgumentException("calibration must not be null"); + } + + synchronized (mDataStore) { + try { + mDataStore.setTouchCalibration(inputDeviceDescriptor, calibration); + } finally { + mDataStore.saveIfNeeded(); + } + } + } + // Must be called on handler. private void showMissingKeyboardLayoutNotification() { if (!mKeyboardLayoutNotificationShown) { diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java index 71de776..9ea369d 100644 --- a/services/core/java/com/android/server/input/PersistentDataStore.java +++ b/services/core/java/com/android/server/input/PersistentDataStore.java @@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import android.hardware.input.TouchCalibration; import android.util.AtomicFile; import android.util.Slog; import android.util.Xml; @@ -82,6 +83,25 @@ final class PersistentDataStore { } } + public TouchCalibration getTouchCalibration(String inputDeviceDescriptor) { + InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); + if (state == null) { + return TouchCalibration.IDENTITY; + } + else { + return state.getTouchCalibration(); + } + } + + public boolean setTouchCalibration(String inputDeviceDescriptor, TouchCalibration calibration) { + InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); + if (state.setTouchCalibration(calibration)) { + setDirty(); + return true; + } + return false; + } + public String getCurrentKeyboardLayout(String inputDeviceDescriptor) { InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); return state != null ? state.getCurrentKeyboardLayout() : null; @@ -275,9 +295,25 @@ final class PersistentDataStore { } private static final class InputDeviceState { + private static final String[] CALIBRATION_NAME = { "x_scale", + "x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" }; + + private TouchCalibration mTouchCalibration = TouchCalibration.IDENTITY; private String mCurrentKeyboardLayout; private ArrayList<String> mKeyboardLayouts = new ArrayList<String>(); + public TouchCalibration getTouchCalibration() { + return mTouchCalibration; + } + + public boolean setTouchCalibration(TouchCalibration calibration) { + if (calibration.equals(mTouchCalibration)) { + return false; + } + mTouchCalibration = calibration; + return true; + } + public String getCurrentKeyboardLayout() { return mCurrentKeyboardLayout; } @@ -389,6 +425,31 @@ final class PersistentDataStore { } mCurrentKeyboardLayout = descriptor; } + } else if (parser.getName().equals("calibration")) { + String format = parser.getAttributeValue(null, "format"); + if (format == null) { + throw new XmlPullParserException( + "Missing format attribute on calibration."); + } + if (format.equals("affine")) { + float[] matrix = TouchCalibration.IDENTITY.getAffineTransform(); + int depth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, depth)) { + String tag = parser.getName().toLowerCase(); + String value = parser.nextText(); + + for (int i = 0; i < matrix.length && i < CALIBRATION_NAME.length; i++) { + if (tag.equals(CALIBRATION_NAME[i])) { + matrix[i] = Float.parseFloat(value); + break; + } + } + } + mTouchCalibration = new TouchCalibration(matrix[0], matrix[1], matrix[2], + matrix[3], matrix[4], matrix[5]); + } else { + throw new XmlPullParserException("Unsupported format for calibration."); + } } } @@ -411,6 +472,16 @@ final class PersistentDataStore { } serializer.endTag(null, "keyboard-layout"); } + + serializer.startTag(null, "calibration"); + serializer.attribute(null, "format", "affine"); + float[] transform = mTouchCalibration.getAffineTransform(); + for (int i = 0; i < transform.length && i < CALIBRATION_NAME.length; i++) { + serializer.startTag(null, CALIBRATION_NAME[i]); + serializer.text(Float.toString(transform[i])); + serializer.endTag(null, CALIBRATION_NAME[i]); + } + serializer.endTag(null, "calibration"); } } -}
\ No newline at end of file +} |