summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-01-02 16:37:43 -0800
committerJeff Brown <jeffbrown@google.com>2011-01-04 17:31:24 -0800
commitb4ff35df5c04aec71fce7e90a6d6f9ef7180c2ad (patch)
treee4473f1b22e3051a8f82239256148820d4e097d5
parenta5af5d6b122b5d7337e6640deabf7886689679eb (diff)
downloadframeworks_base-b4ff35df5c04aec71fce7e90a6d6f9ef7180c2ad.zip
frameworks_base-b4ff35df5c04aec71fce7e90a6d6f9ef7180c2ad.tar.gz
frameworks_base-b4ff35df5c04aec71fce7e90a6d6f9ef7180c2ad.tar.bz2
Mouse pointer integration.
Added support for loading the pointer icon from a resource. Moved the system server related bits of the input manager out of libui and into libinput since they do not need to be linked into applications. Change-Id: Iec11e0725b3add2b905c51f8ea2c3b4b0d1a2d67
-rw-r--r--cmds/system_server/library/Android.mk1
-rw-r--r--core/res/res/drawable-mdpi/pointericon_default.xml5
-rw-r--r--core/res/res/drawable-mdpi/pointericon_default_bitmap.pngbin0 -> 838 bytes
-rwxr-xr-xcore/res/res/values/attrs.xml9
-rw-r--r--include/ui/DisplayInfo.h9
-rw-r--r--libs/ui/Android.mk4
-rw-r--r--libs/ui/tests/Android.mk2
-rw-r--r--services/input/Android.mk56
-rw-r--r--services/input/EventHub.cpp (renamed from libs/ui/EventHub.cpp)33
-rw-r--r--services/input/EventHub.h (renamed from include/ui/EventHub.h)2
-rw-r--r--services/input/InputDispatcher.cpp (renamed from libs/ui/InputDispatcher.cpp)24
-rw-r--r--services/input/InputDispatcher.h (renamed from include/ui/InputDispatcher.h)0
-rw-r--r--services/input/InputManager.cpp (renamed from libs/ui/InputManager.cpp)26
-rw-r--r--services/input/InputManager.h (renamed from include/ui/InputManager.h)16
-rw-r--r--services/input/InputReader.cpp (renamed from libs/ui/InputReader.cpp)48
-rw-r--r--services/input/InputReader.h (renamed from include/ui/InputReader.h)8
-rw-r--r--services/input/PointerController.cpp407
-rw-r--r--services/input/PointerController.h (renamed from include/ui/PointerController.h)66
-rw-r--r--services/input/tests/Android.mk50
-rw-r--r--services/input/tests/InputDispatcher_test.cpp (renamed from libs/ui/tests/InputDispatcher_test.cpp)3
-rw-r--r--services/input/tests/InputReader_test.cpp (renamed from libs/ui/tests/InputReader_test.cpp)94
-rw-r--r--services/java/com/android/server/InputManager.java59
-rw-r--r--services/jni/Android.mk8
-rw-r--r--services/jni/com_android_server_InputManager.cpp401
24 files changed, 863 insertions, 468 deletions
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index 457cbd4..e8afce3 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -21,6 +21,7 @@ LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
libcameraservice \
libmediaplayerservice \
+ libinput \
libutils \
libbinder \
libcutils
diff --git a/core/res/res/drawable-mdpi/pointericon_default.xml b/core/res/res/drawable-mdpi/pointericon_default.xml
new file mode 100644
index 0000000..b1357b6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointericon_default.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+ android:bitmap="@drawable/pointericon_default_bitmap"
+ android:hotSpotX="2"
+ android:hotSpotY="2" />
diff --git a/core/res/res/drawable-mdpi/pointericon_default_bitmap.png b/core/res/res/drawable-mdpi/pointericon_default_bitmap.png
new file mode 100644
index 0000000..7e073a3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointericon_default_bitmap.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 588b33b..890ac7c 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4708,4 +4708,13 @@
<!-- Minimum space between the switch and caption text -->
<attr name="switchPadding" format="dimension" />
</declare-styleable>
+
+ <declare-styleable name="PointerIcon">
+ <!-- Drawable to use as the icon bitmap. -->
+ <attr name="bitmap" format="reference" />
+ <!-- X coordinate of the icon hot spot. -->
+ <attr name="hotSpotX" format="float" />
+ <!-- Y coordinate of the icon hot spot. -->
+ <attr name="hotSpotY" format="float" />
+ </declare-styleable>
</resources>
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
index c419efe..edd28a6 100644
--- a/include/ui/DisplayInfo.h
+++ b/include/ui/DisplayInfo.h
@@ -37,6 +37,15 @@ struct DisplayInfo {
float ydpi;
};
+/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
+enum {
+ DISPLAY_ORIENTATION_0 = 0,
+ DISPLAY_ORIENTATION_90 = 1,
+ DISPLAY_ORIENTATION_180 = 2,
+ DISPLAY_ORIENTATION_270 = 3
+};
+
+
}; // namespace android
#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 4ba8b5b..0d55f08 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -43,16 +43,12 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
$(commonSources) \
EGLUtils.cpp \
- EventHub.cpp \
EventRecurrence.cpp \
FramebufferNativeWindow.cpp \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \
GraphicLog.cpp \
- InputDispatcher.cpp \
- InputManager.cpp \
- InputReader.cpp \
InputTransport.cpp \
PixelFormat.cpp \
Rect.cpp \
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index aa017b9..580d73c 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -7,8 +7,6 @@ ifneq ($(TARGET_SIMULATOR),true)
# Build the unit tests.
test_src_files := \
InputChannel_test.cpp \
- InputReader_test.cpp \
- InputDispatcher_test.cpp \
InputPublisherAndConsumer_test.cpp
shared_libraries := \
diff --git a/services/input/Android.mk b/services/input/Android.mk
new file mode 100644
index 0000000..37804ff
--- /dev/null
+++ b/services/input/Android.mk
@@ -0,0 +1,56 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ EventHub.cpp \
+ InputDispatcher.cpp \
+ InputManager.cpp \
+ InputReader.cpp \
+ PointerController.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy \
+ libsurfaceflinger_client \
+ libskia \
+ libui
+
+LOCAL_C_INCLUDES := \
+ external/skia/include/core
+
+LOCAL_MODULE:= libinput
+
+LOCAL_MODULE_TAGS := optional
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/ui/EventHub.cpp b/services/input/EventHub.cpp
index 4e9fad0..487e73f 100644
--- a/libs/ui/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -1,5 +1,19 @@
-//
-// Copyright 2005 The Android Open Source Project
+/*
+ * Copyright (C) 2005 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.
+ */
+
//
// Handle events, like key input and vsync.
//
@@ -15,7 +29,8 @@
//#define LOG_NDEBUG 0
-#include <ui/EventHub.h>
+#include "EventHub.h"
+
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
@@ -58,18 +73,6 @@
/* this macro computes the number of bytes needed to represent a bit array of the specified size */
#define sizeof_bit_array(bits) ((bits + 7) / 8)
-#ifndef ABS_MT_TOUCH_MAJOR
-#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
-#endif
-
-#ifndef ABS_MT_POSITION_X
-#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
-#endif
-
-#ifndef ABS_MT_POSITION_Y
-#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
-#endif
-
// Fd at index 0 is always reserved for inotify
#define FIRST_ACTUAL_DEVICE_INDEX 1
diff --git a/include/ui/EventHub.h b/services/input/EventHub.h
index 8f922a5..74b7ec5 100644
--- a/include/ui/EventHub.h
+++ b/services/input/EventHub.h
@@ -133,7 +133,7 @@ enum {
* environment. In addition, the event hub generates fake input events to indicate
* when devices are added or removed.
*
- * The event hub provies a stream of input events (via the getEvent function).
+ * The event hub provides a stream of input events (via the getEvent function).
* It also supports querying the current actual state of input devices such as identifying
* which keys are currently down. Finally, the event hub keeps track of the capabilities of
* individual input devices, such as their class and the set of key codes that they support.
diff --git a/libs/ui/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 0548e61..3675021 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -1,8 +1,19 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// The input dispatcher.
-//
+/*
+ * 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.
+ */
+
#define LOG_TAG "InputDispatcher"
//#define LOG_NDEBUG 0
@@ -37,8 +48,9 @@
// Log debug messages about the app switch latency optimization.
#define DEBUG_APP_SWITCH 0
+#include "InputDispatcher.h"
+
#include <cutils/log.h>
-#include <ui/InputDispatcher.h>
#include <ui/PowerManager.h>
#include <stddef.h>
diff --git a/include/ui/InputDispatcher.h b/services/input/InputDispatcher.h
index 7305601..7305601 100644
--- a/include/ui/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
diff --git a/libs/ui/InputManager.cpp b/services/input/InputManager.cpp
index 09fce38..5dfa5d5 100644
--- a/libs/ui/InputManager.cpp
+++ b/services/input/InputManager.cpp
@@ -1,16 +1,26 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// The input manager.
-//
+/*
+ * 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.
+ */
+
#define LOG_TAG "InputManager"
//#define LOG_NDEBUG 0
+#include "InputManager.h"
+
#include <cutils/log.h>
-#include <ui/InputManager.h>
-#include <ui/InputReader.h>
-#include <ui/InputDispatcher.h>
namespace android {
diff --git a/include/ui/InputManager.h b/services/input/InputManager.h
index 568568b..df4d299 100644
--- a/include/ui/InputManager.h
+++ b/services/input/InputManager.h
@@ -21,8 +21,12 @@
* Native input manager.
*/
-#include <ui/EventHub.h>
+#include "EventHub.h"
+#include "InputReader.h"
+#include "InputDispatcher.h"
+
#include <ui/Input.h>
+#include <ui/InputTransport.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
@@ -31,16 +35,6 @@
namespace android {
-class InputChannel;
-
-class InputReaderInterface;
-class InputReaderPolicyInterface;
-class InputReaderThread;
-
-class InputDispatcherInterface;
-class InputDispatcherPolicyInterface;
-class InputDispatcherThread;
-
/*
* The input manager is the core of the system event processing.
*
diff --git a/libs/ui/InputReader.cpp b/services/input/InputReader.cpp
index a11a010..7a45de6 100644
--- a/libs/ui/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -1,8 +1,19 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// The input reader.
-//
+/*
+ * 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.
+ */
+
#define LOG_TAG "InputReader"
//#define LOG_NDEBUG 0
@@ -22,8 +33,9 @@
// Log debug messages about pointer assignment calculations.
#define DEBUG_POINTER_ASSIGNMENT 0
+#include "InputReader.h"
+
#include <cutils/log.h>
-#include <ui/InputReader.h>
#include <ui/Keyboard.h>
#include <ui/VirtualKeyMap.h>
@@ -84,7 +96,7 @@ static const int keyCodeRotationMapSize =
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
- if (orientation != InputReaderPolicyInterface::ROTATION_0) {
+ if (orientation != DISPLAY_ORIENTATION_0) {
for (int i = 0; i < keyCodeRotationMapSize; i++) {
if (keyCode == keyCodeRotationMap[i][0]) {
return keyCodeRotationMap[i][orientation];
@@ -860,7 +872,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
int32_t orientation;
if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
NULL, NULL, & orientation)) {
- orientation = InputReaderPolicyInterface::ROTATION_0;
+ orientation = DISPLAY_ORIENTATION_0;
}
keyCode = rotateKeyCode(keyCode, orientation);
@@ -1195,23 +1207,23 @@ void CursorInputMapper::sync(nsecs_t when) {
int32_t orientation;
if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
NULL, NULL, & orientation)) {
- orientation = InputReaderPolicyInterface::ROTATION_0;
+ orientation = DISPLAY_ORIENTATION_0;
}
float temp;
switch (orientation) {
- case InputReaderPolicyInterface::ROTATION_90:
+ case DISPLAY_ORIENTATION_90:
temp = deltaX;
deltaX = deltaY;
deltaY = -temp;
break;
- case InputReaderPolicyInterface::ROTATION_180:
+ case DISPLAY_ORIENTATION_180:
deltaX = -deltaX;
deltaY = -deltaY;
break;
- case InputReaderPolicyInterface::ROTATION_270:
+ case DISPLAY_ORIENTATION_270:
temp = deltaX;
deltaX = -deltaY;
deltaY = temp;
@@ -1485,7 +1497,7 @@ void TouchInputMapper::dumpRawAxes(String8& dump) {
bool TouchInputMapper::configureSurfaceLocked() {
// Update orientation and dimensions if needed.
- int32_t orientation = InputReaderPolicyInterface::ROTATION_0;
+ int32_t orientation = DISPLAY_ORIENTATION_0;
int32_t width = mRawAxes.x.getRange();
int32_t height = mRawAxes.y.getRange();
@@ -1677,8 +1689,8 @@ bool TouchInputMapper::configureSurfaceLocked() {
// Compute oriented surface dimensions, precision, and scales.
float orientedXScale, orientedYScale;
switch (mLocked.surfaceOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- case InputReaderPolicyInterface::ROTATION_270:
+ case DISPLAY_ORIENTATION_90:
+ case DISPLAY_ORIENTATION_270:
mLocked.orientedSurfaceWidth = mLocked.surfaceHeight;
mLocked.orientedSurfaceHeight = mLocked.surfaceWidth;
mLocked.orientedXPrecision = mLocked.yPrecision;
@@ -2553,7 +2565,7 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
// Adjust coords for orientation.
switch (mLocked.surfaceOrientation) {
- case InputReaderPolicyInterface::ROTATION_90: {
+ case DISPLAY_ORIENTATION_90: {
float xTemp = x;
x = y;
y = mLocked.surfaceWidth - xTemp;
@@ -2563,13 +2575,13 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
}
break;
}
- case InputReaderPolicyInterface::ROTATION_180: {
+ case DISPLAY_ORIENTATION_180: {
x = mLocked.surfaceWidth - x;
y = mLocked.surfaceHeight - y;
orientation = - orientation;
break;
}
- case InputReaderPolicyInterface::ROTATION_270: {
+ case DISPLAY_ORIENTATION_270: {
float xTemp = x;
x = mLocked.surfaceHeight - y;
y = xTemp;
diff --git a/include/ui/InputReader.h b/services/input/InputReader.h
index 00a06be..8c849c4 100644
--- a/include/ui/InputReader.h
+++ b/services/input/InputReader.h
@@ -17,10 +17,12 @@
#ifndef _UI_INPUT_READER_H
#define _UI_INPUT_READER_H
-#include <ui/EventHub.h>
+#include "EventHub.h"
+#include "InputDispatcher.h"
+#include "PointerController.h"
+
#include <ui/Input.h>
-#include <ui/InputDispatcher.h>
-#include <ui/PointerController.h>
+#include <ui/DisplayInfo.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Timers.h>
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
new file mode 100644
index 0000000..ebc58ee
--- /dev/null
+++ b/services/input/PointerController.cpp
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PointerController"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages about pointer updates
+#define DEBUG_POINTER_UPDATES 0
+
+#include "PointerController.h"
+
+#include <cutils/log.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkPaint.h>
+#include <SkXfermode.h>
+
+namespace android {
+
+// --- PointerController ---
+
+PointerController::PointerController(int32_t pointerLayer) :
+ mPointerLayer(pointerLayer) {
+ AutoMutex _l(mLock);
+
+ mLocked.displayWidth = -1;
+ mLocked.displayHeight = -1;
+ mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
+
+ mLocked.pointerX = 0;
+ mLocked.pointerY = 0;
+ mLocked.buttonState = 0;
+
+ mLocked.iconBitmap = NULL;
+ mLocked.iconHotSpotX = 0;
+ mLocked.iconHotSpotY = 0;
+
+ mLocked.wantVisible = false;
+ mLocked.visible = false;
+ mLocked.drawn = false;
+}
+
+PointerController::~PointerController() {
+ if (mSurfaceControl != NULL) {
+ mSurfaceControl->clear();
+ mSurfaceControl.clear();
+ }
+
+ if (mSurfaceComposerClient != NULL) {
+ mSurfaceComposerClient->dispose();
+ mSurfaceComposerClient.clear();
+ }
+
+ delete mLocked.iconBitmap;
+}
+
+bool PointerController::getBounds(float* outMinX, float* outMinY,
+ float* outMaxX, float* outMaxY) const {
+ AutoMutex _l(mLock);
+
+ return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
+}
+
+bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
+ float* outMaxX, float* outMaxY) const {
+ if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
+ return false;
+ }
+
+ *outMinX = 0;
+ *outMinY = 0;
+ switch (mLocked.displayOrientation) {
+ case DISPLAY_ORIENTATION_90:
+ case DISPLAY_ORIENTATION_270:
+ *outMaxX = mLocked.displayHeight;
+ *outMaxY = mLocked.displayWidth;
+ break;
+ default:
+ *outMaxX = mLocked.displayWidth;
+ *outMaxY = mLocked.displayHeight;
+ break;
+ }
+ return true;
+}
+
+void PointerController::move(float deltaX, float deltaY) {
+#if DEBUG_POINTER_UPDATES
+ LOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
+#endif
+ if (deltaX == 0.0f && deltaY == 0.0f) {
+ return;
+ }
+
+ AutoMutex _l(mLock);
+
+ setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
+}
+
+void PointerController::setButtonState(uint32_t buttonState) {
+#if DEBUG_POINTER_UPDATES
+ LOGD("Set button state 0x%08x", buttonState);
+#endif
+ AutoMutex _l(mLock);
+
+ if (mLocked.buttonState != buttonState) {
+ mLocked.buttonState = buttonState;
+ mLocked.wantVisible = true;
+ updateLocked();
+ }
+}
+
+uint32_t PointerController::getButtonState() const {
+ AutoMutex _l(mLock);
+
+ return mLocked.buttonState;
+}
+
+void PointerController::setPosition(float x, float y) {
+#if DEBUG_POINTER_UPDATES
+ LOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
+#endif
+ AutoMutex _l(mLock);
+
+ setPositionLocked(x, y);
+}
+
+void PointerController::setPositionLocked(float x, float y) {
+ float minX, minY, maxX, maxY;
+ if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
+ if (x <= minX) {
+ mLocked.pointerX = minX;
+ } else if (x >= maxX) {
+ mLocked.pointerX = maxX;
+ } else {
+ mLocked.pointerX = x;
+ }
+ if (y <= minY) {
+ mLocked.pointerY = minY;
+ } else if (y >= maxY) {
+ mLocked.pointerY = maxY;
+ } else {
+ mLocked.pointerY = y;
+ }
+ mLocked.wantVisible = true;
+ updateLocked();
+ }
+}
+
+void PointerController::getPosition(float* outX, float* outY) const {
+ AutoMutex _l(mLock);
+
+ *outX = mLocked.pointerX;
+ *outY = mLocked.pointerY;
+}
+
+void PointerController::updateLocked() {
+ bool wantVisibleAndHavePointerIcon = mLocked.wantVisible && mLocked.iconBitmap;
+
+ if (wantVisibleAndHavePointerIcon) {
+ // Want the pointer to be visible.
+ // Ensure the surface is created and drawn.
+ if (!createSurfaceIfNeededLocked() || !drawPointerIfNeededLocked()) {
+ return;
+ }
+ } else {
+ // Don't want the pointer to be visible.
+ // If it is not visible then we are done.
+ if (mSurfaceControl == NULL || !mLocked.visible) {
+ return;
+ }
+ }
+
+ status_t status = mSurfaceComposerClient->openTransaction();
+ if (status) {
+ LOGE("Error opening surface transaction to update pointer surface.");
+ return;
+ }
+
+ if (wantVisibleAndHavePointerIcon) {
+ status = mSurfaceControl->setPosition(
+ mLocked.pointerX - mLocked.iconHotSpotX,
+ mLocked.pointerY - mLocked.iconHotSpotY);
+ if (status) {
+ LOGE("Error %d moving pointer surface.", status);
+ goto CloseTransaction;
+ }
+
+ if (!mLocked.visible) {
+ status = mSurfaceControl->setLayer(mPointerLayer);
+ if (status) {
+ LOGE("Error %d setting pointer surface layer.", status);
+ goto CloseTransaction;
+ }
+
+ status = mSurfaceControl->show(mPointerLayer);
+ if (status) {
+ LOGE("Error %d showing pointer surface.", status);
+ goto CloseTransaction;
+ }
+
+ mLocked.visible = true;
+ }
+ } else {
+ if (mLocked.visible) {
+ status = mSurfaceControl->hide();
+ if (status) {
+ LOGE("Error %d hiding pointer surface.", status);
+ goto CloseTransaction;
+ }
+
+ mLocked.visible = false;
+ }
+ }
+
+CloseTransaction:
+ status = mSurfaceComposerClient->closeTransaction();
+ if (status) {
+ LOGE("Error closing surface transaction to update pointer surface.");
+ }
+}
+
+void PointerController::setDisplaySize(int32_t width, int32_t height) {
+ AutoMutex _l(mLock);
+
+ if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
+ mLocked.displayWidth = width;
+ mLocked.displayHeight = height;
+
+ float minX, minY, maxX, maxY;
+ if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
+ mLocked.pointerX = (minX + maxX) * 0.5f;
+ mLocked.pointerY = (minY + maxY) * 0.5f;
+ } else {
+ mLocked.pointerX = 0;
+ mLocked.pointerY = 0;
+ }
+
+ updateLocked();
+ }
+}
+
+void PointerController::setDisplayOrientation(int32_t orientation) {
+ AutoMutex _l(mLock);
+
+ if (mLocked.displayOrientation != orientation) {
+ float absoluteX, absoluteY;
+
+ // Map from oriented display coordinates to absolute display coordinates.
+ switch (mLocked.displayOrientation) {
+ case DISPLAY_ORIENTATION_90:
+ absoluteX = mLocked.displayWidth - mLocked.pointerY;
+ absoluteY = mLocked.pointerX;
+ break;
+ case DISPLAY_ORIENTATION_180:
+ absoluteX = mLocked.displayWidth - mLocked.pointerX;
+ absoluteY = mLocked.displayHeight - mLocked.pointerY;
+ break;
+ case DISPLAY_ORIENTATION_270:
+ absoluteX = mLocked.pointerY;
+ absoluteY = mLocked.displayHeight - mLocked.pointerX;
+ break;
+ default:
+ absoluteX = mLocked.pointerX;
+ absoluteY = mLocked.pointerY;
+ break;
+ }
+
+ // Map from absolute display coordinates to oriented display coordinates.
+ switch (orientation) {
+ case DISPLAY_ORIENTATION_90:
+ mLocked.pointerX = absoluteY;
+ mLocked.pointerY = mLocked.displayWidth - absoluteX;
+ break;
+ case DISPLAY_ORIENTATION_180:
+ mLocked.pointerX = mLocked.displayWidth - absoluteX;
+ mLocked.pointerY = mLocked.displayHeight - absoluteY;
+ break;
+ case DISPLAY_ORIENTATION_270:
+ mLocked.pointerX = mLocked.displayHeight - absoluteY;
+ mLocked.pointerY = absoluteX;
+ break;
+ default:
+ mLocked.pointerX = absoluteX;
+ mLocked.pointerY = absoluteY;
+ break;
+ }
+
+ mLocked.displayOrientation = orientation;
+
+ updateLocked();
+ }
+}
+
+void PointerController::setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) {
+ AutoMutex _l(mLock);
+
+ delete mLocked.iconBitmap;
+ mLocked.iconBitmap = bitmap ? new SkBitmap(*bitmap) : NULL;
+ mLocked.iconHotSpotX = hotSpotX;
+ mLocked.iconHotSpotY = hotSpotY;
+ mLocked.drawn = false;
+}
+
+bool PointerController::createSurfaceIfNeededLocked() {
+ if (!mLocked.iconBitmap) {
+ // If we don't have a pointer icon, then no point allocating a surface now.
+ return false;
+ }
+
+ if (mSurfaceComposerClient == NULL) {
+ mSurfaceComposerClient = new SurfaceComposerClient();
+ }
+
+ if (mSurfaceControl == NULL) {
+ mSurfaceControl = mSurfaceComposerClient->createSurface(getpid(),
+ String8("Pointer Icon"), 0,
+ mLocked.iconBitmap->width(), mLocked.iconBitmap->height(),
+ PIXEL_FORMAT_RGBA_8888);
+ if (mSurfaceControl == NULL) {
+ LOGE("Error creating pointer surface.");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PointerController::drawPointerIfNeededLocked() {
+ if (!mLocked.drawn) {
+ if (!mLocked.iconBitmap) {
+ return false;
+ }
+
+ if (!resizeSurfaceLocked(mLocked.iconBitmap->width(), mLocked.iconBitmap->height())) {
+ return false;
+ }
+
+ sp<Surface> surface = mSurfaceControl->getSurface();
+
+ Surface::SurfaceInfo surfaceInfo;
+ status_t status = surface->lock(&surfaceInfo);
+ if (status) {
+ LOGE("Error %d locking pointer surface before drawing.", status);
+ return false;
+ }
+
+ SkBitmap surfaceBitmap;
+ ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format);
+ surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, surfaceInfo.w, surfaceInfo.h, bpr);
+ surfaceBitmap.setPixels(surfaceInfo.bits);
+
+ SkCanvas surfaceCanvas;
+ surfaceCanvas.setBitmapDevice(surfaceBitmap);
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ surfaceCanvas.drawBitmap(*mLocked.iconBitmap, 0, 0, &paint);
+
+ status = surface->unlockAndPost();
+ if (status) {
+ LOGE("Error %d unlocking pointer surface after drawing.", status);
+ return false;
+ }
+ }
+
+ mLocked.drawn = true;
+ return true;
+}
+
+bool PointerController::resizeSurfaceLocked(int32_t width, int32_t height) {
+ status_t status = mSurfaceComposerClient->openTransaction();
+ if (status) {
+ LOGE("Error opening surface transaction to resize pointer surface.");
+ return false;
+ }
+
+ status = mSurfaceControl->setSize(width, height);
+ if (status) {
+ LOGE("Error %d setting pointer surface size.", status);
+ return false;
+ }
+
+ status = mSurfaceComposerClient->closeTransaction();
+ if (status) {
+ LOGE("Error closing surface transaction to resize pointer surface.");
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace android
diff --git a/include/ui/PointerController.h b/services/input/PointerController.h
index 4db24e5..a2a9955 100644
--- a/include/ui/PointerController.h
+++ b/services/input/PointerController.h
@@ -17,7 +17,15 @@
#ifndef _UI_POINTER_CONTROLLER_H
#define _UI_POINTER_CONTROLLER_H
+#include <ui/DisplayInfo.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+
+#include <SkBitmap.h>
namespace android {
@@ -58,6 +66,64 @@ public:
virtual void getPosition(float* outX, float* outY) const = 0;
};
+
+/*
+ * Tracks pointer movements and draws the pointer sprite to a surface.
+ *
+ * Handles pointer acceleration and animation.
+ */
+class PointerController : public PointerControllerInterface {
+protected:
+ virtual ~PointerController();
+
+public:
+ PointerController(int32_t pointerLayer);
+
+ virtual bool getBounds(float* outMinX, float* outMinY,
+ float* outMaxX, float* outMaxY) const;
+ virtual void move(float deltaX, float deltaY);
+ virtual void setButtonState(uint32_t buttonState);
+ virtual uint32_t getButtonState() const;
+ virtual void setPosition(float x, float y);
+ virtual void getPosition(float* outX, float* outY) const;
+
+ void setDisplaySize(int32_t width, int32_t height);
+ void setDisplayOrientation(int32_t orientation);
+ void setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY);
+
+private:
+ mutable Mutex mLock;
+
+ int32_t mPointerLayer;
+ sp<SurfaceComposerClient> mSurfaceComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+
+ struct Locked {
+ int32_t displayWidth;
+ int32_t displayHeight;
+ int32_t displayOrientation;
+
+ float pointerX;
+ float pointerY;
+ uint32_t buttonState;
+
+ SkBitmap* iconBitmap;
+ float iconHotSpotX;
+ float iconHotSpotY;
+
+ bool wantVisible;
+ bool visible;
+ bool drawn;
+ } mLocked;
+
+ bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
+ void setPositionLocked(float x, float y);
+ void updateLocked();
+ bool createSurfaceIfNeededLocked();
+ bool drawPointerIfNeededLocked();
+ bool resizeSurfaceLocked(int32_t width, int32_t height);
+};
+
} // namespace android
#endif // _UI_POINTER_CONTROLLER_H
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
new file mode 100644
index 0000000..799eb76
--- /dev/null
+++ b/services/input/tests/Android.mk
@@ -0,0 +1,50 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+ InputReader_test.cpp \
+ InputDispatcher_test.cpp
+
+shared_libraries := \
+ libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy \
+ libui \
+ libsurfaceflinger_client \
+ libskia \
+ libstlport \
+ libinput
+
+static_libraries := \
+ libgtest \
+ libgtest_main
+
+c_includes := \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport \
+ external/skia/include/core
+
+module_tags := eng tests
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+ $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-subdir-makefiles)
+
+endif \ No newline at end of file
diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp
index 7e17c57..b79633a 100644
--- a/libs/ui/tests/InputDispatcher_test.cpp
+++ b/services/input/tests/InputDispatcher_test.cpp
@@ -2,7 +2,8 @@
// Copyright 2010 The Android Open Source Project
//
-#include <ui/InputDispatcher.h>
+#include "../InputDispatcher.h"
+
#include <gtest/gtest.h>
#include <linux/input.h>
diff --git a/libs/ui/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 50d3383..9d2c52f 100644
--- a/libs/ui/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -2,7 +2,8 @@
// Copyright 2010 The Android Open Source Project
//
-#include <ui/InputReader.h>
+#include "../InputReader.h"
+
#include <utils/List.h>
#include <gtest/gtest.h>
#include <math.h>
@@ -40,7 +41,8 @@ protected:
virtual ~FakePointerController() { }
public:
- FakePointerController() {
+ FakePointerController() :
+ mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0) {
}
void setBounds(float minX, float minY, float maxX, float maxY) {
@@ -54,8 +56,8 @@ public:
private:
virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
*outMinX = mMinX;
- *outMaxX = mMinX;
*outMinY = mMinY;
+ *outMaxX = mMaxX;
*outMaxY = mMaxY;
return mHaveBounds;
}
@@ -973,6 +975,9 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchScreenPresent_ReturnsFing
}
TEST_F(InputReaderTest, GetInputConfiguration_WhenMousePresent_ReturnsNoNavigation) {
+ sp<FakePointerController> controller = new FakePointerController();
+ mFakePolicy->setPointerController(0, controller);
+
PropertyMap configuration;
configuration.addProperty(String8("cursor.mode"), String8("pointer"));
ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("mouse"),
@@ -1044,6 +1049,9 @@ TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsIgnored) {
}
TEST_F(InputReaderTest, GetInputDeviceIds) {
+ sp<FakePointerController> controller = new FakePointerController();
+ mFakePolicy->setPointerController(2, controller);
+
ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"),
INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY, NULL));
ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("mouse"),
@@ -1675,7 +1683,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateD
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_90);
+ DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1694,7 +1702,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_0);
+ DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1706,7 +1714,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_90);
+ DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1718,7 +1726,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_180);
+ DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1730,7 +1738,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_270);
+ DISPLAY_ORIENTATION_270);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1746,7 +1754,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_270);
+ DISPLAY_ORIENTATION_270);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 1, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
@@ -1755,7 +1763,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_180);
+ DISPLAY_ORIENTATION_180);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 0, 0);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
@@ -1941,7 +1949,7 @@ TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeF
ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X));
ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y));
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
- 0.0f, 1.0f, 0.0f, 1.0f));
+ 0.0f, 1.0f, 0.0f, 0.0f));
// When the bounds are set, then there should be a valid motion range.
mFakePointerController->setBounds(1, 2, 800, 480);
@@ -1950,11 +1958,11 @@ TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeF
mapper->populateDeviceInfo(&info2);
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X,
- 1, 800, 0.0f, 1.0f));
+ 1, 800, 0.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y,
- 2, 480, 0.0f, 1.0f));
+ 2, 480, 0.0f, 0.0f));
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE,
- 0.0f, 1.0f, 0.0f, 1.0f));
+ 0.0f, 1.0f, 0.0f, 0.0f));
}
TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) {
@@ -1969,6 +1977,8 @@ TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsSca
-1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y,
-1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
+ 0.0f, 1.0f, 0.0f, 0.0f));
}
TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) {
@@ -2151,7 +2161,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMot
mFakePolicy->setDisplayInfo(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_90);
+ DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0));
@@ -2169,8 +2179,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions)
addMapperAndConfigure(mapper);
mFakePolicy->setDisplayInfo(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_0);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0));
@@ -2181,8 +2190,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions)
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
mFakePolicy->setDisplayInfo(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_90);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1));
@@ -2193,8 +2201,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions)
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1));
mFakePolicy->setDisplayInfo(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_180);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0));
@@ -2205,8 +2212,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions)
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1));
mFakePolicy->setDisplayInfo(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- InputReaderPolicyInterface::ROTATION_270);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1));
@@ -2386,7 +2392,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_Return
TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2413,7 +2419,7 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2440,7 +2446,7 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2456,7 +2462,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) {
// Note: Ideally we should send cancels but the implementation is more straightforward
// with up and this will only happen if a device is forcibly removed.
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2489,7 +2495,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) {
TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2515,7 +2521,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2564,7 +2570,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2678,7 +2684,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB
TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2746,7 +2752,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves
TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -2836,7 +2842,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotate
FakeInputDispatcher::NotifyMotionArgs args;
// Rotation 90.
- prepareDisplay(InputReaderPolicyInterface::ROTATION_90);
+ prepareDisplay(DISPLAY_ORIENTATION_90);
processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
@@ -2857,7 +2863,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
FakeInputDispatcher::NotifyMotionArgs args;
// Rotation 0.
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
@@ -2870,7 +2876,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled());
// Rotation 90.
- prepareDisplay(InputReaderPolicyInterface::ROTATION_90);
+ prepareDisplay(DISPLAY_ORIENTATION_90);
processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
@@ -2883,7 +2889,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled());
// Rotation 180.
- prepareDisplay(InputReaderPolicyInterface::ROTATION_180);
+ prepareDisplay(DISPLAY_ORIENTATION_180);
processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
@@ -2896,7 +2902,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled());
// Rotation 270.
- prepareDisplay(InputReaderPolicyInterface::ROTATION_270);
+ prepareDisplay(DISPLAY_ORIENTATION_270);
processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
@@ -2911,7 +2917,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions)
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | PRESSURE | TOOL);
addMapperAndConfigure(mapper);
@@ -3043,7 +3049,7 @@ void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) {
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -3294,7 +3300,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID);
prepareVirtualKeys();
addMapperAndConfigure(mapper);
@@ -3454,7 +3460,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId
TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR);
addMapperAndConfigure(mapper);
@@ -3499,7 +3505,7 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | MINOR);
addConfigurationProperty("touch.touchSize.calibration", "geometric");
addConfigurationProperty("touch.toolSize.calibration", "geometric");
@@ -3540,7 +3546,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration)
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
addConfigurationProperty("touch.touchSize.calibration", "pressure");
addConfigurationProperty("touch.toolSize.calibration", "linear");
@@ -3596,7 +3602,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinear
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
- prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
addConfigurationProperty("touch.touchSize.calibration", "pressure");
addConfigurationProperty("touch.toolSize.calibration", "area");
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index b5becb5..410b8c2 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -19,10 +19,17 @@ package com.android.server;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.SystemProperties;
import android.util.Slog;
@@ -358,7 +365,49 @@ public class InputManager {
pw.println(dumpStr);
}
}
-
+
+ private static final class PointerIcon {
+ public Bitmap bitmap;
+ public float hotSpotX;
+ public float hotSpotY;
+
+ public static PointerIcon load(Resources resources, int resourceId) {
+ PointerIcon icon = new PointerIcon();
+
+ XmlResourceParser parser = resources.getXml(resourceId);
+ final int bitmapRes;
+ try {
+ XmlUtils.beginDocument(parser, "pointer-icon");
+
+ TypedArray a = resources.obtainAttributes(
+ parser, com.android.internal.R.styleable.PointerIcon);
+ bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0);
+ icon.hotSpotX = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0);
+ icon.hotSpotY = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0);
+ a.recycle();
+ } catch (Exception ex) {
+ Slog.e(TAG, "Exception parsing pointer icon resource.", ex);
+ return null;
+ } finally {
+ parser.close();
+ }
+
+ if (bitmapRes == 0) {
+ Slog.e(TAG, "<pointer-icon> is missing bitmap attribute");
+ return null;
+ }
+
+ Drawable drawable = resources.getDrawable(bitmapRes);
+ if (!(drawable instanceof BitmapDrawable)) {
+ Slog.e(TAG, "<pointer-icon> bitmap attribute must refer to a bitmap drawable");
+ return null;
+ }
+
+ icon.bitmap = ((BitmapDrawable)drawable).getBitmap();
+ return icon;
+ }
+ }
+
/*
* Callbacks from native.
*/
@@ -480,9 +529,15 @@ public class InputManager {
@SuppressWarnings("unused")
public int getPointerLayer() {
return mWindowManagerService.mPolicy.windowTypeToLayerLw(
- WindowManager.LayoutParams.TYPE_DRAG)
+ WindowManager.LayoutParams.TYPE_POINTER)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
+
+ @SuppressWarnings("unused")
+ public PointerIcon getPointerIcon() {
+ return PointerIcon.load(mContext.getResources(),
+ com.android.internal.R.drawable.pointericon_default);
+ }
}
}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 845869c..4ccea6e 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -14,7 +14,10 @@ LOCAL_SRC_FILES:= \
onload.cpp
LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+ $(JNI_H_INCLUDE) \
+ frameworks/base/services \
+ frameworks/base/core/jni \
+ external/skia/include/core
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
@@ -25,6 +28,8 @@ LOCAL_SHARED_LIBRARIES := \
libsystem_server \
libutils \
libui \
+ libinput \
+ libskia \
libsurfaceflinger_client \
libusbhost
@@ -43,4 +48,3 @@ endif
LOCAL_MODULE:= libandroid_servers
include $(BUILD_SHARED_LIBRARY)
-
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index c757ada..5ed63f0 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -24,27 +24,23 @@
// Log debug messages about InputDispatcherPolicy
#define DEBUG_INPUT_DISPATCHER_POLICY 0
-// Log debug messages about PointerController
-#define DEBUG_POINTER_CONTROLLER 1
-
#include "JNIHelp.h"
#include "jni.h"
#include <limits.h>
#include <android_runtime/AndroidRuntime.h>
-#include <ui/InputReader.h>
-#include <ui/InputDispatcher.h>
-#include <ui/InputManager.h>
-#include <ui/InputTransport.h>
+
#include <utils/Log.h>
#include <utils/threads.h>
-#include <surfaceflinger/Surface.h>
-#include <surfaceflinger/SurfaceComposerClient.h>
-#include <surfaceflinger/ISurfaceComposer.h>
-#include "../../core/jni/android_view_KeyEvent.h"
-#include "../../core/jni/android_view_MotionEvent.h"
-#include "../../core/jni/android_view_InputChannel.h"
+#include <input/InputManager.h>
+#include <input/PointerController.h>
+
+#include <android_view_KeyEvent.h>
+#include <android_view_MotionEvent.h>
+#include <android_view_InputChannel.h>
+#include <android/graphics/GraphicsJNI.h>
+
#include "com_android_server_PowerManagerService.h"
namespace android {
@@ -67,6 +63,7 @@ static struct {
jmethodID getExcludedDeviceNames;
jmethodID getMaxEventsPerSecond;
jmethodID getPointerLayer;
+ jmethodID getPointerIcon;
} gCallbacksClassInfo;
static struct {
@@ -136,57 +133,13 @@ static struct {
jfieldID navigation;
} gConfigurationClassInfo;
-// ----------------------------------------------------------------------------
-
-static inline nsecs_t now() {
- return systemTime(SYSTEM_TIME_MONOTONIC);
-}
-
-// ----------------------------------------------------------------------------
-
-class PointerController : public PointerControllerInterface {
-protected:
- virtual ~PointerController();
-
-public:
- PointerController(int32_t pointerLayer);
-
- virtual bool getBounds(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const;
- virtual void move(float deltaX, float deltaY);
- virtual void setButtonState(uint32_t buttonState);
- virtual uint32_t getButtonState() const;
- virtual void setPosition(float x, float y);
- virtual void getPosition(float* outX, float* outY) const;
-
- void setDisplaySize(int32_t width, int32_t height);
- void setDisplayOrientation(int32_t orientation);
-
-private:
- mutable Mutex mLock;
-
- int32_t mPointerLayer;
- sp<SurfaceComposerClient> mSurfaceComposerClient;
- sp<SurfaceControl> mSurfaceControl;
-
- struct Locked {
- int32_t displayWidth;
- int32_t displayHeight;
- int32_t displayOrientation;
-
- float pointerX;
- float pointerY;
- uint32_t buttonState;
-
- bool wantVisible;
- bool visible;
- bool drawn;
- } mLocked;
+static struct {
+ jclass clazz;
- bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
- void setPositionLocked(float x, float y);
- void updateLocked();
-};
+ jfieldID bitmap;
+ jfieldID hotSpotX;
+ jfieldID hotSpotY;
+} gPointerIconClassInfo;
// ----------------------------------------------------------------------------
@@ -538,13 +491,30 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32
if (controller == NULL) {
JNIEnv* env = jniEnv();
jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer);
- checkAndClearExceptionFromCallback(env, "getPointerLayer");
+ if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
+ layer = -1;
+ }
controller = new PointerController(layer);
mLocked.pointerController = controller;
controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);
controller->setDisplayOrientation(mLocked.displayOrientation);
+
+ jobject iconObj = env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.getPointerIcon);
+ if (!checkAndClearExceptionFromCallback(env, "getPointerIcon") && iconObj) {
+ jfloat iconHotSpotX = env->GetFloatField(iconObj, gPointerIconClassInfo.hotSpotX);
+ jfloat iconHotSpotY = env->GetFloatField(iconObj, gPointerIconClassInfo.hotSpotY);
+ jobject iconBitmapObj = env->GetObjectField(iconObj, gPointerIconClassInfo.bitmap);
+ if (iconBitmapObj) {
+ SkBitmap* iconBitmap = GraphicsJNI::getNativeBitmap(env, iconBitmapObj);
+ if (iconBitmap) {
+ controller->setPointerIcon(iconBitmap, iconHotSpotX, iconHotSpotY);
+ }
+ env->DeleteLocalRef(iconBitmapObj);
+ }
+ env->DeleteLocalRef(iconObj);
+ }
}
return controller;
}
@@ -984,293 +954,6 @@ bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
return result;
}
-// --- PointerController ---
-
-PointerController::PointerController(int32_t pointerLayer) :
- mPointerLayer(pointerLayer) {
- AutoMutex _l(mLock);
-
- mLocked.displayWidth = -1;
- mLocked.displayHeight = -1;
- mLocked.displayOrientation = InputReaderPolicyInterface::ROTATION_0;
-
- mLocked.pointerX = 0;
- mLocked.pointerY = 0;
- mLocked.buttonState = 0;
-
- mLocked.wantVisible = false;
- mLocked.visible = false;
- mLocked.drawn = false;
-}
-
-PointerController::~PointerController() {
- mSurfaceControl.clear();
- mSurfaceComposerClient.clear();
-}
-
-bool PointerController::getBounds(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const {
- AutoMutex _l(mLock);
-
- return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
-}
-
-bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
- float* outMaxX, float* outMaxY) const {
- if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
- return false;
- }
-
- *outMinX = 0;
- *outMinY = 0;
- switch (mLocked.displayOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- case InputReaderPolicyInterface::ROTATION_270:
- *outMaxX = mLocked.displayHeight;
- *outMaxY = mLocked.displayWidth;
- break;
- default:
- *outMaxX = mLocked.displayWidth;
- *outMaxY = mLocked.displayHeight;
- break;
- }
- return true;
-}
-
-void PointerController::move(float deltaX, float deltaY) {
-#if DEBUG_POINTER_CONTROLLER
- LOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
-#endif
- if (deltaX == 0.0f && deltaY == 0.0f) {
- return;
- }
-
- AutoMutex _l(mLock);
-
- setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
-}
-
-void PointerController::setButtonState(uint32_t buttonState) {
- AutoMutex _l(mLock);
-
- if (mLocked.buttonState != buttonState) {
- mLocked.buttonState = buttonState;
- mLocked.wantVisible = true;
- updateLocked();
- }
-}
-
-uint32_t PointerController::getButtonState() const {
- AutoMutex _l(mLock);
-
- return mLocked.buttonState;
-}
-
-void PointerController::setPosition(float x, float y) {
- AutoMutex _l(mLock);
-
- setPositionLocked(x, y);
-}
-
-void PointerController::setPositionLocked(float x, float y) {
- float minX, minY, maxX, maxY;
- if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
- if (x <= minX) {
- mLocked.pointerX = minX;
- } else if (x >= maxX) {
- mLocked.pointerX = maxX;
- } else {
- mLocked.pointerX = x;
- }
- if (y <= minY) {
- mLocked.pointerY = minY;
- } else if (y >= maxY) {
- mLocked.pointerY = maxY;
- } else {
- mLocked.pointerY = y;
- }
- mLocked.wantVisible = true;
- updateLocked();
- }
-}
-
-void PointerController::getPosition(float* outX, float* outY) const {
- AutoMutex _l(mLock);
-
- *outX = mLocked.pointerX;
- *outY = mLocked.pointerY;
-}
-
-void PointerController::updateLocked() {
-#if DEBUG_POINTER_CONTROLLER
- LOGD("Pointer at (%f, %f).", mLocked.pointerX, mLocked.pointerY);
-#endif
-
- if (!mLocked.wantVisible && !mLocked.visible) {
- return;
- }
-
- if (mSurfaceComposerClient == NULL) {
- mSurfaceComposerClient = new SurfaceComposerClient();
- }
-
- if (mSurfaceControl == NULL) {
- mSurfaceControl = mSurfaceComposerClient->createSurface(getpid(),
- String8("Pointer"), 0, 16, 16, PIXEL_FORMAT_RGBA_8888);
- if (mSurfaceControl == NULL) {
- LOGE("Error creating pointer surface.");
- return;
- }
- }
-
- status_t status = mSurfaceComposerClient->openTransaction();
- if (status) {
- LOGE("Error opening surface transaction to update pointer surface.");
- return;
- }
-
- if (mLocked.wantVisible) {
- if (!mLocked.drawn) {
- mLocked.drawn = true;
-
- sp<Surface> surface = mSurfaceControl->getSurface();
- Surface::SurfaceInfo surfaceInfo;
- status = surface->lock(&surfaceInfo);
- if (status) {
- LOGE("Error %d locking pointer surface before drawing.", status);
- goto CloseTransaction;
- }
-
- // TODO: Load pointers from assets and allow them to be set.
- char* bitmap = (char*)surfaceInfo.bits;
- ssize_t bpr = surfaceInfo.s * 4;
- for (int y = 0; y < surfaceInfo.h; y++) {
- for (int x = 0; x < surfaceInfo.w; x++) {
- bitmap[y * bpr + x * 4] = 128;
- bitmap[y * bpr + x * 4 + 1] = 255;
- bitmap[y * bpr + x * 4 + 2] = 128;
- bitmap[y * bpr + x * 4 + 3] = 255;
- }
- }
-
- status = surface->unlockAndPost();
- if (status) {
- LOGE("Error %d unlocking pointer surface after drawing.", status);
- goto CloseTransaction;
- }
- }
-
- status = mSurfaceControl->setPosition(mLocked.pointerX, mLocked.pointerY);
- if (status) {
- LOGE("Error %d moving pointer surface.", status);
- goto CloseTransaction;
- }
-
- if (!mLocked.visible) {
- mLocked.visible = true;
-
- mSurfaceControl->setLayer(mPointerLayer);
-
- LOGD("XXX Show");
- status = mSurfaceControl->show(mPointerLayer);
- if (status) {
- LOGE("Error %d showing pointer surface.", status);
- goto CloseTransaction;
- }
- }
- } else {
- if (mLocked.visible) {
- mLocked.visible = false;
-
- if (mSurfaceControl != NULL) {
- status = mSurfaceControl->hide();
- if (status) {
- LOGE("Error %d hiding pointer surface.", status);
- goto CloseTransaction;
- }
- }
- }
- }
-
-CloseTransaction:
- status = mSurfaceComposerClient->closeTransaction();
- if (status) {
- LOGE("Error closing surface transaction to update pointer surface.");
- }
-}
-
-void PointerController::setDisplaySize(int32_t width, int32_t height) {
- AutoMutex _l(mLock);
-
- if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
- mLocked.displayWidth = width;
- mLocked.displayHeight = height;
-
- float minX, minY, maxX, maxY;
- if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
- mLocked.pointerX = (minX + maxX) * 0.5f;
- mLocked.pointerY = (minY + maxY) * 0.5f;
- } else {
- mLocked.pointerX = 0;
- mLocked.pointerY = 0;
- }
-
- updateLocked();
- }
-}
-
-void PointerController::setDisplayOrientation(int32_t orientation) {
- AutoMutex _l(mLock);
-
- if (mLocked.displayOrientation != orientation) {
- float absoluteX, absoluteY;
-
- // Map from oriented display coordinates to absolute display coordinates.
- switch (mLocked.displayOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- absoluteX = mLocked.displayWidth - mLocked.pointerY;
- absoluteY = mLocked.pointerX;
- break;
- case InputReaderPolicyInterface::ROTATION_180:
- absoluteX = mLocked.displayWidth - mLocked.pointerX;
- absoluteY = mLocked.displayHeight - mLocked.pointerY;
- break;
- case InputReaderPolicyInterface::ROTATION_270:
- absoluteX = mLocked.pointerY;
- absoluteY = mLocked.displayHeight - mLocked.pointerX;
- break;
- default:
- absoluteX = mLocked.pointerX;
- absoluteY = mLocked.pointerY;
- break;
- }
-
- // Map from absolute display coordinates to oriented display coordinates.
- switch (orientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- mLocked.pointerX = absoluteY;
- mLocked.pointerY = mLocked.displayWidth - absoluteX;
- break;
- case InputReaderPolicyInterface::ROTATION_180:
- mLocked.pointerX = mLocked.displayWidth - absoluteX;
- mLocked.pointerY = mLocked.displayHeight - absoluteY;
- break;
- case InputReaderPolicyInterface::ROTATION_270:
- mLocked.pointerX = mLocked.displayHeight - absoluteY;
- mLocked.pointerY = absoluteX;
- break;
- default:
- mLocked.pointerX = absoluteX;
- mLocked.pointerY = absoluteY;
- break;
- }
-
- mLocked.displayOrientation = orientation;
-
- updateLocked();
- }
-}
-
// ----------------------------------------------------------------------------
@@ -1715,6 +1398,9 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, gCallbacksClassInfo.clazz,
"getPointerLayer", "()I");
+ GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz,
+ "getPointerIcon", "()Lcom/android/server/InputManager$PointerIcon;");
+
// InputWindow
FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow");
@@ -1854,6 +1540,19 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz,
"navigation", "I");
+ // PointerIcon
+
+ FIND_CLASS(gPointerIconClassInfo.clazz, "com/android/server/InputManager$PointerIcon");
+
+ GET_FIELD_ID(gPointerIconClassInfo.bitmap, gPointerIconClassInfo.clazz,
+ "bitmap", "Landroid/graphics/Bitmap;");
+
+ GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, gPointerIconClassInfo.clazz,
+ "hotSpotX", "F");
+
+ GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, gPointerIconClassInfo.clazz,
+ "hotSpotY", "F");
+
return 0;
}