PointerController.cpp revision 5541de9ea3513a12d1ac2ad07e7e04a3aa7741a0
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "PointerController"
18
19//#define LOG_NDEBUG 0
20
21// Log debug messages about pointer updates
22#define DEBUG_POINTER_UPDATES 0
23
24#include "PointerController.h"
25
26#include <cutils/log.h>
27
28#include <SkBitmap.h>
29#include <SkCanvas.h>
30#include <SkColor.h>
31#include <SkPaint.h>
32#include <SkXfermode.h>
33
34namespace android {
35
36// --- PointerController ---
37
38// Time to wait before starting the fade when the pointer is inactive.
39static const nsecs_t INACTIVITY_FADE_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
40static const nsecs_t INACTIVITY_FADE_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
41
42// Time to spend fading out the pointer completely.
43static const nsecs_t FADE_DURATION = 500 * 1000000LL; // 500 ms
44
45// Time to wait between frames.
46static const nsecs_t FADE_FRAME_INTERVAL = 1000000000LL / 60;
47
48// Amount to subtract from alpha per frame.
49static const float FADE_DECAY_PER_FRAME = float(FADE_FRAME_INTERVAL) / FADE_DURATION;
50
51
52PointerController::PointerController(const sp<Looper>& looper,
53        const sp<SpriteController>& spriteController) :
54        mLooper(looper), mSpriteController(spriteController) {
55    mHandler = new WeakMessageHandler(this);
56
57    AutoMutex _l(mLock);
58
59    mLocked.displayWidth = -1;
60    mLocked.displayHeight = -1;
61    mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
62
63    mLocked.pointerX = 0;
64    mLocked.pointerY = 0;
65    mLocked.buttonState = 0;
66
67    mLocked.fadeAlpha = 1;
68    mLocked.inactivityFadeDelay = INACTIVITY_FADE_DELAY_NORMAL;
69
70    mLocked.visible = false;
71
72    mLocked.sprite = mSpriteController->createSprite();
73}
74
75PointerController::~PointerController() {
76    mLooper->removeMessages(mHandler);
77
78    AutoMutex _l(mLock);
79
80    mLocked.sprite.clear();
81}
82
83bool PointerController::getBounds(float* outMinX, float* outMinY,
84        float* outMaxX, float* outMaxY) const {
85    AutoMutex _l(mLock);
86
87    return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
88}
89
90bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
91        float* outMaxX, float* outMaxY) const {
92    if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
93        return false;
94    }
95
96    *outMinX = 0;
97    *outMinY = 0;
98    switch (mLocked.displayOrientation) {
99    case DISPLAY_ORIENTATION_90:
100    case DISPLAY_ORIENTATION_270:
101        *outMaxX = mLocked.displayHeight - 1;
102        *outMaxY = mLocked.displayWidth - 1;
103        break;
104    default:
105        *outMaxX = mLocked.displayWidth - 1;
106        *outMaxY = mLocked.displayHeight - 1;
107        break;
108    }
109    return true;
110}
111
112void PointerController::move(float deltaX, float deltaY) {
113#if DEBUG_POINTER_UPDATES
114    LOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
115#endif
116    if (deltaX == 0.0f && deltaY == 0.0f) {
117        return;
118    }
119
120    AutoMutex _l(mLock);
121
122    setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
123}
124
125void PointerController::setButtonState(uint32_t buttonState) {
126#if DEBUG_POINTER_UPDATES
127    LOGD("Set button state 0x%08x", buttonState);
128#endif
129    AutoMutex _l(mLock);
130
131    if (mLocked.buttonState != buttonState) {
132        mLocked.buttonState = buttonState;
133        unfadeBeforeUpdateLocked();
134        updateLocked();
135    }
136}
137
138uint32_t PointerController::getButtonState() const {
139    AutoMutex _l(mLock);
140
141    return mLocked.buttonState;
142}
143
144void PointerController::setPosition(float x, float y) {
145#if DEBUG_POINTER_UPDATES
146    LOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
147#endif
148    AutoMutex _l(mLock);
149
150    setPositionLocked(x, y);
151}
152
153void PointerController::setPositionLocked(float x, float y) {
154    float minX, minY, maxX, maxY;
155    if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
156        if (x <= minX) {
157            mLocked.pointerX = minX;
158        } else if (x >= maxX) {
159            mLocked.pointerX = maxX;
160        } else {
161            mLocked.pointerX = x;
162        }
163        if (y <= minY) {
164            mLocked.pointerY = minY;
165        } else if (y >= maxY) {
166            mLocked.pointerY = maxY;
167        } else {
168            mLocked.pointerY = y;
169        }
170        unfadeBeforeUpdateLocked();
171        updateLocked();
172    }
173}
174
175void PointerController::getPosition(float* outX, float* outY) const {
176    AutoMutex _l(mLock);
177
178    *outX = mLocked.pointerX;
179    *outY = mLocked.pointerY;
180}
181
182void PointerController::fade() {
183    AutoMutex _l(mLock);
184
185    startFadeLocked();
186}
187
188void PointerController::unfade() {
189    AutoMutex _l(mLock);
190
191    if (unfadeBeforeUpdateLocked()) {
192        updateLocked();
193    }
194}
195
196void PointerController::setInactivityFadeDelay(InactivityFadeDelay inactivityFadeDelay) {
197    AutoMutex _l(mLock);
198
199    if (mLocked.inactivityFadeDelay != inactivityFadeDelay) {
200        mLocked.inactivityFadeDelay = inactivityFadeDelay;
201        startInactivityFadeDelayLocked();
202    }
203}
204
205void PointerController::updateLocked() {
206    mLocked.sprite->openTransaction();
207    mLocked.sprite->setPosition(mLocked.pointerX, mLocked.pointerY);
208    mLocked.sprite->setAlpha(mLocked.fadeAlpha);
209    mLocked.sprite->setVisible(mLocked.visible);
210    mLocked.sprite->closeTransaction();
211}
212
213void PointerController::setDisplaySize(int32_t width, int32_t height) {
214    AutoMutex _l(mLock);
215
216    if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
217        mLocked.displayWidth = width;
218        mLocked.displayHeight = height;
219
220        float minX, minY, maxX, maxY;
221        if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
222            mLocked.pointerX = (minX + maxX) * 0.5f;
223            mLocked.pointerY = (minY + maxY) * 0.5f;
224        } else {
225            mLocked.pointerX = 0;
226            mLocked.pointerY = 0;
227        }
228
229        updateLocked();
230    }
231}
232
233void PointerController::setDisplayOrientation(int32_t orientation) {
234    AutoMutex _l(mLock);
235
236    if (mLocked.displayOrientation != orientation) {
237        // Apply offsets to convert from the pixel top-left corner position to the pixel center.
238        // This creates an invariant frame of reference that we can easily rotate when
239        // taking into account that the pointer may be located at fractional pixel offsets.
240        float x = mLocked.pointerX + 0.5f;
241        float y = mLocked.pointerY + 0.5f;
242        float temp;
243
244        // Undo the previous rotation.
245        switch (mLocked.displayOrientation) {
246        case DISPLAY_ORIENTATION_90:
247            temp = x;
248            x = mLocked.displayWidth - y;
249            y = temp;
250            break;
251        case DISPLAY_ORIENTATION_180:
252            x = mLocked.displayWidth - x;
253            y = mLocked.displayHeight - y;
254            break;
255        case DISPLAY_ORIENTATION_270:
256            temp = x;
257            x = y;
258            y = mLocked.displayHeight - temp;
259            break;
260        }
261
262        // Perform the new rotation.
263        switch (orientation) {
264        case DISPLAY_ORIENTATION_90:
265            temp = x;
266            x = y;
267            y = mLocked.displayWidth - temp;
268            break;
269        case DISPLAY_ORIENTATION_180:
270            x = mLocked.displayWidth - x;
271            y = mLocked.displayHeight - y;
272            break;
273        case DISPLAY_ORIENTATION_270:
274            temp = x;
275            x = mLocked.displayHeight - y;
276            y = temp;
277            break;
278        }
279
280        // Apply offsets to convert from the pixel center to the pixel top-left corner position
281        // and save the results.
282        mLocked.pointerX = x - 0.5f;
283        mLocked.pointerY = y - 0.5f;
284        mLocked.displayOrientation = orientation;
285
286        updateLocked();
287    }
288}
289
290void PointerController::setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) {
291    AutoMutex _l(mLock);
292
293    mLocked.sprite->setBitmap(bitmap, hotSpotX, hotSpotY);
294}
295
296void PointerController::handleMessage(const Message& message) {
297    switch (message.what) {
298    case MSG_FADE_STEP: {
299        AutoMutex _l(mLock);
300        fadeStepLocked();
301        break;
302    }
303    }
304}
305
306bool PointerController::unfadeBeforeUpdateLocked() {
307    sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked());
308
309    if (isFadingLocked()) {
310        mLocked.visible = true;
311        mLocked.fadeAlpha = 1;
312        return true; // update required to effect the unfade
313    }
314    return false; // update not required
315}
316
317void PointerController::startFadeLocked() {
318    if (!isFadingLocked()) {
319        sendFadeStepMessageDelayedLocked(0);
320    }
321}
322
323void PointerController::startInactivityFadeDelayLocked() {
324    if (!isFadingLocked()) {
325        sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked());
326    }
327}
328
329void PointerController::fadeStepLocked() {
330    if (mLocked.visible) {
331        mLocked.fadeAlpha -= FADE_DECAY_PER_FRAME;
332        if (mLocked.fadeAlpha < 0) {
333            mLocked.fadeAlpha = 0;
334            mLocked.visible = false;
335        } else {
336            sendFadeStepMessageDelayedLocked(FADE_FRAME_INTERVAL);
337        }
338        updateLocked();
339    }
340}
341
342bool PointerController::isFadingLocked() {
343    return !mLocked.visible || mLocked.fadeAlpha != 1;
344}
345
346nsecs_t PointerController::getInactivityFadeDelayTimeLocked() {
347    return mLocked.inactivityFadeDelay == INACTIVITY_FADE_DELAY_SHORT
348            ? INACTIVITY_FADE_DELAY_TIME_SHORT : INACTIVITY_FADE_DELAY_TIME_NORMAL;
349}
350
351void PointerController::sendFadeStepMessageDelayedLocked(nsecs_t delayTime) {
352    mLooper->removeMessages(mHandler, MSG_FADE_STEP);
353    mLooper->sendMessageDelayed(delayTime, mHandler, Message(MSG_FADE_STEP));
354}
355
356} // namespace android
357