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
This commit is contained in:
@@ -21,6 +21,7 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libaudioflinger \
|
||||
libcameraservice \
|
||||
libmediaplayerservice \
|
||||
libinput \
|
||||
libutils \
|
||||
libbinder \
|
||||
libcutils
|
||||
|
||||
5
core/res/res/drawable-mdpi/pointericon_default.xml
Normal file
5
core/res/res/drawable-mdpi/pointericon_default.xml
Normal file
@@ -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" />
|
||||
BIN
core/res/res/drawable-mdpi/pointericon_default_bitmap.png
Normal file
BIN
core/res/res/drawable-mdpi/pointericon_default_bitmap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 838 B |
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 := \
|
||||
|
||||
56
services/input/Android.mk
Normal file
56
services/input/Android.mk
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
407
services/input/PointerController.cpp
Normal file
407
services/input/PointerController.cpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
50
services/input/tests/Android.mk
Normal file
50
services/input/tests/Android.mk
Normal file
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 struct {
|
||||
jclass clazz;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user