widget/gonk/libui/PointerController.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     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  */
    17 #define LOG_TAG "PointerController"
    19 //#define LOG_NDEBUG 0
    21 // Log debug messages about pointer updates
    22 #define DEBUG_POINTER_UPDATES 0
    24 #include "PointerController.h"
    26 #include "cutils_log.h"
    28 #include <SkBitmap.h>
    29 #include <SkCanvas.h>
    30 #include <SkColor.h>
    31 #include <SkPaint.h>
    32 #include <SkXfermode.h>
    34 namespace android {
    36 // --- PointerController ---
    38 // Time to wait before starting the fade when the pointer is inactive.
    39 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
    40 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
    42 // Time to wait between animation frames.
    43 static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60;
    45 // Time to spend fading out the spot completely.
    46 static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
    48 // Time to spend fading out the pointer completely.
    49 static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
    52 // --- PointerController ---
    54 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
    55         const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
    56         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
    57     mHandler = new WeakMessageHandler(this);
    59     AutoMutex _l(mLock);
    61     mLocked.animationPending = false;
    63     mLocked.displayWidth = -1;
    64     mLocked.displayHeight = -1;
    65     mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
    67     mLocked.presentation = PRESENTATION_POINTER;
    68     mLocked.presentationChanged = false;
    70     mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
    72     mLocked.pointerFadeDirection = 0;
    73     mLocked.pointerX = 0;
    74     mLocked.pointerY = 0;
    75     mLocked.pointerAlpha = 0.0f; // pointer is initially faded
    76     mLocked.pointerSprite = mSpriteController->createSprite();
    77     mLocked.pointerIconChanged = false;
    79     mLocked.buttonState = 0;
    81     loadResources();
    82 }
    84 PointerController::~PointerController() {
    85     mLooper->removeMessages(mHandler);
    87     AutoMutex _l(mLock);
    89     mLocked.pointerSprite.clear();
    91     for (size_t i = 0; i < mLocked.spots.size(); i++) {
    92         delete mLocked.spots.itemAt(i);
    93     }
    94     mLocked.spots.clear();
    95     mLocked.recycledSprites.clear();
    96 }
    98 bool PointerController::getBounds(float* outMinX, float* outMinY,
    99         float* outMaxX, float* outMaxY) const {
   100     AutoMutex _l(mLock);
   102     return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
   103 }
   105 bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
   106         float* outMaxX, float* outMaxY) const {
   107     if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
   108         return false;
   109     }
   111     *outMinX = 0;
   112     *outMinY = 0;
   113     switch (mLocked.displayOrientation) {
   114     case DISPLAY_ORIENTATION_90:
   115     case DISPLAY_ORIENTATION_270:
   116         *outMaxX = mLocked.displayHeight - 1;
   117         *outMaxY = mLocked.displayWidth - 1;
   118         break;
   119     default:
   120         *outMaxX = mLocked.displayWidth - 1;
   121         *outMaxY = mLocked.displayHeight - 1;
   122         break;
   123     }
   124     return true;
   125 }
   127 void PointerController::move(float deltaX, float deltaY) {
   128 #if DEBUG_POINTER_UPDATES
   129     ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
   130 #endif
   131     if (deltaX == 0.0f && deltaY == 0.0f) {
   132         return;
   133     }
   135     AutoMutex _l(mLock);
   137     setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
   138 }
   140 void PointerController::setButtonState(int32_t buttonState) {
   141 #if DEBUG_POINTER_UPDATES
   142     ALOGD("Set button state 0x%08x", buttonState);
   143 #endif
   144     AutoMutex _l(mLock);
   146     if (mLocked.buttonState != buttonState) {
   147         mLocked.buttonState = buttonState;
   148     }
   149 }
   151 int32_t PointerController::getButtonState() const {
   152     AutoMutex _l(mLock);
   154     return mLocked.buttonState;
   155 }
   157 void PointerController::setPosition(float x, float y) {
   158 #if DEBUG_POINTER_UPDATES
   159     ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
   160 #endif
   161     AutoMutex _l(mLock);
   163     setPositionLocked(x, y);
   164 }
   166 void PointerController::setPositionLocked(float x, float y) {
   167     float minX, minY, maxX, maxY;
   168     if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
   169         if (x <= minX) {
   170             mLocked.pointerX = minX;
   171         } else if (x >= maxX) {
   172             mLocked.pointerX = maxX;
   173         } else {
   174             mLocked.pointerX = x;
   175         }
   176         if (y <= minY) {
   177             mLocked.pointerY = minY;
   178         } else if (y >= maxY) {
   179             mLocked.pointerY = maxY;
   180         } else {
   181             mLocked.pointerY = y;
   182         }
   183         updatePointerLocked();
   184     }
   185 }
   187 void PointerController::getPosition(float* outX, float* outY) const {
   188     AutoMutex _l(mLock);
   190     *outX = mLocked.pointerX;
   191     *outY = mLocked.pointerY;
   192 }
   194 void PointerController::fade(Transition transition) {
   195     AutoMutex _l(mLock);
   197     // Remove the inactivity timeout, since we are fading now.
   198     removeInactivityTimeoutLocked();
   200     // Start fading.
   201     if (transition == TRANSITION_IMMEDIATE) {
   202         mLocked.pointerFadeDirection = 0;
   203         mLocked.pointerAlpha = 0.0f;
   204         updatePointerLocked();
   205     } else {
   206         mLocked.pointerFadeDirection = -1;
   207         startAnimationLocked();
   208     }
   209 }
   211 void PointerController::unfade(Transition transition) {
   212     AutoMutex _l(mLock);
   214     // Always reset the inactivity timer.
   215     resetInactivityTimeoutLocked();
   217     // Start unfading.
   218     if (transition == TRANSITION_IMMEDIATE) {
   219         mLocked.pointerFadeDirection = 0;
   220         mLocked.pointerAlpha = 1.0f;
   221         updatePointerLocked();
   222     } else {
   223         mLocked.pointerFadeDirection = 1;
   224         startAnimationLocked();
   225     }
   226 }
   228 void PointerController::setPresentation(Presentation presentation) {
   229     AutoMutex _l(mLock);
   231     if (mLocked.presentation != presentation) {
   232         mLocked.presentation = presentation;
   233         mLocked.presentationChanged = true;
   235         if (presentation != PRESENTATION_SPOT) {
   236             fadeOutAndReleaseAllSpotsLocked();
   237         }
   239         updatePointerLocked();
   240     }
   241 }
   243 void PointerController::setSpots(const PointerCoords* spotCoords,
   244         const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
   245 #if DEBUG_POINTER_UPDATES
   246     ALOGD("setSpots: idBits=%08x", spotIdBits.value);
   247     for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
   248         uint32_t id = idBits.firstMarkedBit();
   249         idBits.clearBit(id);
   250         const PointerCoords& c = spotCoords[spotIdToIndex[id]];
   251         ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
   252                 c.getAxisValue(AMOTION_EVENT_AXIS_X),
   253                 c.getAxisValue(AMOTION_EVENT_AXIS_Y),
   254                 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
   255     }
   256 #endif
   258     AutoMutex _l(mLock);
   260     mSpriteController->openTransaction();
   262     // Add or move spots for fingers that are down.
   263     for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
   264         uint32_t id = idBits.clearFirstMarkedBit();
   265         const PointerCoords& c = spotCoords[spotIdToIndex[id]];
   266         const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
   267                 ? mResources.spotTouch : mResources.spotHover;
   268         float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
   269         float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
   271         Spot* spot = getSpotLocked(id);
   272         if (!spot) {
   273             spot = createAndAddSpotLocked(id);
   274         }
   276         spot->updateSprite(&icon, x, y);
   277     }
   279     // Remove spots for fingers that went up.
   280     for (size_t i = 0; i < mLocked.spots.size(); i++) {
   281         Spot* spot = mLocked.spots.itemAt(i);
   282         if (spot->id != Spot::INVALID_ID
   283                 && !spotIdBits.hasBit(spot->id)) {
   284             fadeOutAndReleaseSpotLocked(spot);
   285         }
   286     }
   288     mSpriteController->closeTransaction();
   289 }
   291 void PointerController::clearSpots() {
   292 #if DEBUG_POINTER_UPDATES
   293     ALOGD("clearSpots");
   294 #endif
   296     AutoMutex _l(mLock);
   298     fadeOutAndReleaseAllSpotsLocked();
   299 }
   301 void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
   302     AutoMutex _l(mLock);
   304     if (mLocked.inactivityTimeout != inactivityTimeout) {
   305         mLocked.inactivityTimeout = inactivityTimeout;
   306         resetInactivityTimeoutLocked();
   307     }
   308 }
   310 void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
   311     AutoMutex _l(mLock);
   313     // Adjust to use the display's unrotated coordinate frame.
   314     if (orientation == DISPLAY_ORIENTATION_90
   315             || orientation == DISPLAY_ORIENTATION_270) {
   316         int32_t temp = height;
   317         height = width;
   318         width = temp;
   319     }
   321     if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
   322         mLocked.displayWidth = width;
   323         mLocked.displayHeight = height;
   325         float minX, minY, maxX, maxY;
   326         if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
   327             mLocked.pointerX = (minX + maxX) * 0.5f;
   328             mLocked.pointerY = (minY + maxY) * 0.5f;
   329         } else {
   330             mLocked.pointerX = 0;
   331             mLocked.pointerY = 0;
   332         }
   334         fadeOutAndReleaseAllSpotsLocked();
   335     }
   337     if (mLocked.displayOrientation != orientation) {
   338         // Apply offsets to convert from the pixel top-left corner position to the pixel center.
   339         // This creates an invariant frame of reference that we can easily rotate when
   340         // taking into account that the pointer may be located at fractional pixel offsets.
   341         float x = mLocked.pointerX + 0.5f;
   342         float y = mLocked.pointerY + 0.5f;
   343         float temp;
   345         // Undo the previous rotation.
   346         switch (mLocked.displayOrientation) {
   347         case DISPLAY_ORIENTATION_90:
   348             temp = x;
   349             x = mLocked.displayWidth - y;
   350             y = temp;
   351             break;
   352         case DISPLAY_ORIENTATION_180:
   353             x = mLocked.displayWidth - x;
   354             y = mLocked.displayHeight - y;
   355             break;
   356         case DISPLAY_ORIENTATION_270:
   357             temp = x;
   358             x = y;
   359             y = mLocked.displayHeight - temp;
   360             break;
   361         }
   363         // Perform the new rotation.
   364         switch (orientation) {
   365         case DISPLAY_ORIENTATION_90:
   366             temp = x;
   367             x = y;
   368             y = mLocked.displayWidth - temp;
   369             break;
   370         case DISPLAY_ORIENTATION_180:
   371             x = mLocked.displayWidth - x;
   372             y = mLocked.displayHeight - y;
   373             break;
   374         case DISPLAY_ORIENTATION_270:
   375             temp = x;
   376             x = mLocked.displayHeight - y;
   377             y = temp;
   378             break;
   379         }
   381         // Apply offsets to convert from the pixel center to the pixel top-left corner position
   382         // and save the results.
   383         mLocked.pointerX = x - 0.5f;
   384         mLocked.pointerY = y - 0.5f;
   385         mLocked.displayOrientation = orientation;
   386     }
   388     updatePointerLocked();
   389 }
   391 void PointerController::setPointerIcon(const SpriteIcon& icon) {
   392     AutoMutex _l(mLock);
   394     mLocked.pointerIcon = icon.copy();
   395     mLocked.pointerIconChanged = true;
   397     updatePointerLocked();
   398 }
   400 void PointerController::handleMessage(const Message& message) {
   401     switch (message.what) {
   402     case MSG_ANIMATE:
   403         doAnimate();
   404         break;
   405     case MSG_INACTIVITY_TIMEOUT:
   406         doInactivityTimeout();
   407         break;
   408     }
   409 }
   411 void PointerController::doAnimate() {
   412     AutoMutex _l(mLock);
   414     bool keepAnimating = false;
   415     mLocked.animationPending = false;
   416     nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;
   418     // Animate pointer fade.
   419     if (mLocked.pointerFadeDirection < 0) {
   420         mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
   421         if (mLocked.pointerAlpha <= 0.0f) {
   422             mLocked.pointerAlpha = 0.0f;
   423             mLocked.pointerFadeDirection = 0;
   424         } else {
   425             keepAnimating = true;
   426         }
   427         updatePointerLocked();
   428     } else if (mLocked.pointerFadeDirection > 0) {
   429         mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
   430         if (mLocked.pointerAlpha >= 1.0f) {
   431             mLocked.pointerAlpha = 1.0f;
   432             mLocked.pointerFadeDirection = 0;
   433         } else {
   434             keepAnimating = true;
   435         }
   436         updatePointerLocked();
   437     }
   439     // Animate spots that are fading out and being removed.
   440     for (size_t i = 0; i < mLocked.spots.size(); i++) {
   441         Spot* spot = mLocked.spots.itemAt(i);
   442         if (spot->id == Spot::INVALID_ID) {
   443             spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
   444             if (spot->alpha <= 0) {
   445                 mLocked.spots.removeAt(i--);
   446                 releaseSpotLocked(spot);
   447             } else {
   448                 spot->sprite->setAlpha(spot->alpha);
   449                 keepAnimating = true;
   450             }
   451         }
   452     }
   454     if (keepAnimating) {
   455         startAnimationLocked();
   456     }
   457 }
   459 void PointerController::doInactivityTimeout() {
   460     fade(TRANSITION_GRADUAL);
   461 }
   463 void PointerController::startAnimationLocked() {
   464     if (!mLocked.animationPending) {
   465         mLocked.animationPending = true;
   466         mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
   467         mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE));
   468     }
   469 }
   471 void PointerController::resetInactivityTimeoutLocked() {
   472     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
   474     nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
   475             ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
   476     mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
   477 }
   479 void PointerController::removeInactivityTimeoutLocked() {
   480     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
   481 }
   483 void PointerController::updatePointerLocked() {
   484     mSpriteController->openTransaction();
   486     mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
   487     mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
   489     if (mLocked.pointerAlpha > 0) {
   490         mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
   491         mLocked.pointerSprite->setVisible(true);
   492     } else {
   493         mLocked.pointerSprite->setVisible(false);
   494     }
   496     if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
   497         mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER
   498                 ? mLocked.pointerIcon : mResources.spotAnchor);
   499         mLocked.pointerIconChanged = false;
   500         mLocked.presentationChanged = false;
   501     }
   503     mSpriteController->closeTransaction();
   504 }
   506 PointerController::Spot* PointerController::getSpotLocked(uint32_t id) {
   507     for (size_t i = 0; i < mLocked.spots.size(); i++) {
   508         Spot* spot = mLocked.spots.itemAt(i);
   509         if (spot->id == id) {
   510             return spot;
   511         }
   512     }
   513     return NULL;
   514 }
   516 PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) {
   517     // Remove spots until we have fewer than MAX_SPOTS remaining.
   518     while (mLocked.spots.size() >= MAX_SPOTS) {
   519         Spot* spot = removeFirstFadingSpotLocked();
   520         if (!spot) {
   521             spot = mLocked.spots.itemAt(0);
   522             mLocked.spots.removeAt(0);
   523         }
   524         releaseSpotLocked(spot);
   525     }
   527     // Obtain a sprite from the recycled pool.
   528     sp<Sprite> sprite;
   529     if (! mLocked.recycledSprites.isEmpty()) {
   530         sprite = mLocked.recycledSprites.top();
   531         mLocked.recycledSprites.pop();
   532     } else {
   533         sprite = mSpriteController->createSprite();
   534     }
   536     // Return the new spot.
   537     Spot* spot = new Spot(id, sprite);
   538     mLocked.spots.push(spot);
   539     return spot;
   540 }
   542 PointerController::Spot* PointerController::removeFirstFadingSpotLocked() {
   543     for (size_t i = 0; i < mLocked.spots.size(); i++) {
   544         Spot* spot = mLocked.spots.itemAt(i);
   545         if (spot->id == Spot::INVALID_ID) {
   546             mLocked.spots.removeAt(i);
   547             return spot;
   548         }
   549     }
   550     return NULL;
   551 }
   553 void PointerController::releaseSpotLocked(Spot* spot) {
   554     spot->sprite->clearIcon();
   556     if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
   557         mLocked.recycledSprites.push(spot->sprite);
   558     }
   560     delete spot;
   561 }
   563 void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
   564     if (spot->id != Spot::INVALID_ID) {
   565         spot->id = Spot::INVALID_ID;
   566         startAnimationLocked();
   567     }
   568 }
   570 void PointerController::fadeOutAndReleaseAllSpotsLocked() {
   571     for (size_t i = 0; i < mLocked.spots.size(); i++) {
   572         Spot* spot = mLocked.spots.itemAt(i);
   573         fadeOutAndReleaseSpotLocked(spot);
   574     }
   575 }
   577 void PointerController::loadResources() {
   578     mPolicy->loadPointerResources(&mResources);
   579 }
   582 // --- PointerController::Spot ---
   584 void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) {
   585     sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
   586     sprite->setAlpha(alpha);
   587     sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
   588     sprite->setPosition(x, y);
   590     this->x = x;
   591     this->y = y;
   593     if (icon != lastIcon) {
   594         lastIcon = icon;
   595         if (icon) {
   596             sprite->setIcon(*icon);
   597             sprite->setVisible(true);
   598         } else {
   599             sprite->setVisible(false);
   600         }
   601     }
   602 }
   604 } // namespace android

mercurial