diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-01-02 16:37:43 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-01-04 17:31:24 -0800 |
commit | b4ff35df5c04aec71fce7e90a6d6f9ef7180c2ad (patch) | |
tree | e4473f1b22e3051a8f82239256148820d4e097d5 | |
parent | a5af5d6b122b5d7337e6640deabf7886689679eb (diff) | |
download | frameworks_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
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 Binary files differnew file mode 100644 index 0000000..7e073a3 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointericon_default_bitmap.png 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; } |