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:
Jeff Brown
2011-01-02 16:37:43 -08:00
parent a5af5d6b12
commit b4ff35df5c
24 changed files with 863 additions and 468 deletions

View File

@@ -21,6 +21,7 @@ LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
libcameraservice \
libmediaplayerservice \
libinput \
libutils \
libbinder \
libcutils

View 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" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

View File

@@ -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>

View File

@@ -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

View File

@@ -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 \

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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.

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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.
*

View File

@@ -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;

View File

@@ -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>

View 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

View File

@@ -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

View 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

View File

@@ -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>

View File

@@ -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");

View File

@@ -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);
}
}
}

View File

@@ -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)

View File

@@ -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;
}