Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ca2400a authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Refactor of PointerController"

parents e286c5e1 c782be6e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@ cc_library_shared {
    name: "libinputservice",
    srcs: [
        "PointerController.cpp",
        "PointerControllerContext.cpp",
        "MouseCursorController.cpp",
        "TouchSpotController.cpp",
        "SpriteController.cpp",
        "SpriteIcon.cpp",
    ],
+460 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 "MouseCursorController"
//#define LOG_NDEBUG 0

// Log debug messages about pointer updates
#define DEBUG_MOUSE_CURSOR_UPDATES 0

#include "MouseCursorController.h"

#include <log/log.h>

#include <SkBitmap.h>
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkColor.h>
#include <SkPaint.h>

namespace {
// Time to spend fading out the pointer completely.
const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
} // namespace

namespace android {

// --- MouseCursorController ---

MouseCursorController::MouseCursorController(PointerControllerContext& context)
      : mContext(context) {
    std::scoped_lock lock(mLock);

    mLocked.animationFrameIndex = 0;
    mLocked.lastFrameUpdatedTime = 0;

    mLocked.pointerFadeDirection = 0;
    mLocked.pointerX = 0;
    mLocked.pointerY = 0;
    mLocked.pointerAlpha = 0.0f; // pointer is initially faded
    mLocked.pointerSprite = mContext.getSpriteController()->createSprite();
    mLocked.updatePointerIcon = false;
    mLocked.requestedPointerType = mContext.getPolicy()->getDefaultPointerIconId();

    mLocked.resourcesLoaded = false;

    mLocked.buttonState = 0;
}

MouseCursorController::~MouseCursorController() {
    std::scoped_lock lock(mLock);

    mLocked.pointerSprite.clear();
}

bool MouseCursorController::getBounds(float* outMinX, float* outMinY, float* outMaxX,
                                      float* outMaxY) const {
    std::scoped_lock lock(mLock);

    return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
}

bool MouseCursorController::getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX,
                                            float* outMaxY) const REQUIRES(mLock) {
    if (!mLocked.viewport.isValid()) {
        return false;
    }

    *outMinX = mLocked.viewport.logicalLeft;
    *outMinY = mLocked.viewport.logicalTop;
    *outMaxX = mLocked.viewport.logicalRight - 1;
    *outMaxY = mLocked.viewport.logicalBottom - 1;
    return true;
}

void MouseCursorController::move(float deltaX, float deltaY) {
#if DEBUG_MOUSE_CURSOR_UPDATES
    ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
#endif
    if (deltaX == 0.0f && deltaY == 0.0f) {
        return;
    }

    std::scoped_lock lock(mLock);

    setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
}

void MouseCursorController::setButtonState(int32_t buttonState) {
#if DEBUG_MOUSE_CURSOR_UPDATES
    ALOGD("Set button state 0x%08x", buttonState);
#endif
    std::scoped_lock lock(mLock);

    if (mLocked.buttonState != buttonState) {
        mLocked.buttonState = buttonState;
    }
}

int32_t MouseCursorController::getButtonState() const {
    std::scoped_lock lock(mLock);
    return mLocked.buttonState;
}

void MouseCursorController::setPosition(float x, float y) {
#if DEBUG_MOUSE_CURSOR_UPDATES
    ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
#endif
    std::scoped_lock lock(mLock);
    setPositionLocked(x, y);
}

void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
    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;
        }
        updatePointerLocked();
    }
}

void MouseCursorController::getPosition(float* outX, float* outY) const {
    std::scoped_lock lock(mLock);

    *outX = mLocked.pointerX;
    *outY = mLocked.pointerY;
}

int32_t MouseCursorController::getDisplayId() const {
    std::scoped_lock lock(mLock);
    return mLocked.viewport.displayId;
}

void MouseCursorController::fade(PointerControllerInterface::Transition transition) {
    std::scoped_lock lock(mLock);

    // Remove the inactivity timeout, since we are fading now.
    mContext.removeInactivityTimeout();

    // Start fading.
    if (transition == PointerControllerInterface::Transition::IMMEDIATE) {
        mLocked.pointerFadeDirection = 0;
        mLocked.pointerAlpha = 0.0f;
        updatePointerLocked();
    } else {
        mLocked.pointerFadeDirection = -1;
        mContext.startAnimation();
    }
}

void MouseCursorController::unfade(PointerControllerInterface::Transition transition) {
    std::scoped_lock lock(mLock);

    // Always reset the inactivity timer.
    mContext.resetInactivityTimeout();

    // Start unfading.
    if (transition == PointerControllerInterface::Transition::IMMEDIATE) {
        mLocked.pointerFadeDirection = 0;
        mLocked.pointerAlpha = 1.0f;
        updatePointerLocked();
    } else {
        mLocked.pointerFadeDirection = 1;
        mContext.startAnimation();
    }
}

void MouseCursorController::reloadPointerResources(bool getAdditionalMouseResources) {
    std::scoped_lock lock(mLock);

    loadResourcesLocked(getAdditionalMouseResources);
    updatePointerLocked();
}

/**
 * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
 * so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
 */
static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
    width = viewport.deviceWidth;
    height = viewport.deviceHeight;

    if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
        viewport.orientation == DISPLAY_ORIENTATION_270) {
        std::swap(width, height);
    }
}

void MouseCursorController::setDisplayViewport(const DisplayViewport& viewport,
                                               bool getAdditionalMouseResources) {
    std::scoped_lock lock(mLock);

    if (viewport == mLocked.viewport) {
        return;
    }

    const DisplayViewport oldViewport = mLocked.viewport;
    mLocked.viewport = viewport;

    int32_t oldDisplayWidth, oldDisplayHeight;
    getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
    int32_t newDisplayWidth, newDisplayHeight;
    getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);

    // Reset cursor position to center if size or display changed.
    if (oldViewport.displayId != viewport.displayId || oldDisplayWidth != newDisplayWidth ||
        oldDisplayHeight != newDisplayHeight) {
        float minX, minY, maxX, maxY;
        if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
            mLocked.pointerX = (minX + maxX) * 0.5f;
            mLocked.pointerY = (minY + maxY) * 0.5f;
            // Reload icon resources for density may be changed.
            loadResourcesLocked(getAdditionalMouseResources);
        } else {
            mLocked.pointerX = 0;
            mLocked.pointerY = 0;
        }
    } else if (oldViewport.orientation != viewport.orientation) {
        // Apply offsets to convert from the pixel top-left corner position to the pixel center.
        // This creates an invariant frame of reference that we can easily rotate when
        // taking into account that the pointer may be located at fractional pixel offsets.
        float x = mLocked.pointerX + 0.5f;
        float y = mLocked.pointerY + 0.5f;
        float temp;

        // Undo the previous rotation.
        switch (oldViewport.orientation) {
            case DISPLAY_ORIENTATION_90:
                temp = x;
                x = oldViewport.deviceHeight - y;
                y = temp;
                break;
            case DISPLAY_ORIENTATION_180:
                x = oldViewport.deviceWidth - x;
                y = oldViewport.deviceHeight - y;
                break;
            case DISPLAY_ORIENTATION_270:
                temp = x;
                x = y;
                y = oldViewport.deviceWidth - temp;
                break;
        }

        // Perform the new rotation.
        switch (viewport.orientation) {
            case DISPLAY_ORIENTATION_90:
                temp = x;
                x = y;
                y = viewport.deviceHeight - temp;
                break;
            case DISPLAY_ORIENTATION_180:
                x = viewport.deviceWidth - x;
                y = viewport.deviceHeight - y;
                break;
            case DISPLAY_ORIENTATION_270:
                temp = x;
                x = viewport.deviceWidth - y;
                y = temp;
                break;
        }

        // Apply offsets to convert from the pixel center to the pixel top-left corner position
        // and save the results.
        mLocked.pointerX = x - 0.5f;
        mLocked.pointerY = y - 0.5f;
    }

    updatePointerLocked();
}

void MouseCursorController::updatePointerIcon(int32_t iconId) {
    std::scoped_lock lock(mLock);

    if (mLocked.requestedPointerType != iconId) {
        mLocked.requestedPointerType = iconId;
        mLocked.updatePointerIcon = true;
        updatePointerLocked();
    }
}

void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) {
    std::scoped_lock lock(mLock);

    const int32_t iconId = mContext.getPolicy()->getCustomPointerIconId();
    mLocked.additionalMouseResources[iconId] = icon;
    mLocked.requestedPointerType = iconId;
    mLocked.updatePointerIcon = true;
    updatePointerLocked();
}

bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
    nsecs_t frameDelay = timestamp - mContext.getAnimationTime();

    std::scoped_lock lock(mLock);

    // Animate pointer fade.
    if (mLocked.pointerFadeDirection < 0) {
        mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
        if (mLocked.pointerAlpha <= 0.0f) {
            mLocked.pointerAlpha = 0.0f;
            mLocked.pointerFadeDirection = 0;
        } else {
            keepAnimating = true;
        }
        updatePointerLocked();
    } else if (mLocked.pointerFadeDirection > 0) {
        mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
        if (mLocked.pointerAlpha >= 1.0f) {
            mLocked.pointerAlpha = 1.0f;
            mLocked.pointerFadeDirection = 0;
        } else {
            keepAnimating = true;
        }
        updatePointerLocked();
    }

    return keepAnimating;
}

bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
    std::scoped_lock lock(mLock);

    std::map<int32_t, PointerAnimation>::const_iterator iter =
            mLocked.animationResources.find(mLocked.requestedPointerType);
    if (iter == mLocked.animationResources.end()) {
        return false;
    }

    if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
        sp<SpriteController> spriteController = mContext.getSpriteController();
        spriteController->openTransaction();

        int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
        mLocked.animationFrameIndex += incr;
        mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr;
        while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) {
            mLocked.animationFrameIndex -= iter->second.animationFrames.size();
        }
        mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);

        spriteController->closeTransaction();
    }

    // Keep animating.
    return true;
}

void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
    if (!mLocked.viewport.isValid()) {
        return;
    }
    sp<SpriteController> spriteController = mContext.getSpriteController();
    spriteController->openTransaction();

    mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
    mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
    mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);

    if (mLocked.pointerAlpha > 0) {
        mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
        mLocked.pointerSprite->setVisible(true);
    } else {
        mLocked.pointerSprite->setVisible(false);
    }

    if (mLocked.updatePointerIcon) {
        if (mLocked.requestedPointerType == mContext.getPolicy()->getDefaultPointerIconId()) {
            mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
        } else {
            std::map<int32_t, SpriteIcon>::const_iterator iter =
                    mLocked.additionalMouseResources.find(mLocked.requestedPointerType);
            if (iter != mLocked.additionalMouseResources.end()) {
                std::map<int32_t, PointerAnimation>::const_iterator anim_iter =
                        mLocked.animationResources.find(mLocked.requestedPointerType);
                if (anim_iter != mLocked.animationResources.end()) {
                    mLocked.animationFrameIndex = 0;
                    mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
                    mContext.startAnimation();
                }
                mLocked.pointerSprite->setIcon(iter->second);
            } else {
                ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType);
                mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
            }
        }
        mLocked.updatePointerIcon = false;
    }

    spriteController->closeTransaction();
}

void MouseCursorController::loadResourcesLocked(bool getAdditionalMouseResources) REQUIRES(mLock) {
    if (!mLocked.viewport.isValid()) {
        return;
    }

    if (!mLocked.resourcesLoaded) mLocked.resourcesLoaded = true;

    sp<PointerControllerPolicyInterface> policy = mContext.getPolicy();
    policy->loadPointerResources(&mResources, mLocked.viewport.displayId);
    policy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);

    mLocked.additionalMouseResources.clear();
    mLocked.animationResources.clear();
    if (getAdditionalMouseResources) {
        policy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
                                             &mLocked.animationResources,
                                             mLocked.viewport.displayId);
    }

    mLocked.updatePointerIcon = true;
}

bool MouseCursorController::isViewportValid() {
    std::scoped_lock lock(mLock);
    return mLocked.viewport.isValid();
}

void MouseCursorController::getAdditionalMouseResources() {
    std::scoped_lock lock(mLock);

    if (mLocked.additionalMouseResources.empty()) {
        mContext.getPolicy()->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
                                                           &mLocked.animationResources,
                                                           mLocked.viewport.displayId);
    }
    mLocked.updatePointerIcon = true;
    updatePointerLocked();
}

bool MouseCursorController::resourcesLoaded() {
    std::scoped_lock lock(mLock);
    return mLocked.resourcesLoaded;
}

} // namespace android
+111 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

#ifndef _UI_MOUSE_CURSOR_CONTROLLER_H
#define _UI_MOUSE_CURSOR_CONTROLLER_H

#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <ui/DisplayInfo.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>

#include <map>
#include <memory>
#include <vector>

#include "PointerControllerContext.h"
#include "SpriteController.h"

namespace android {

/*
 * Helper class for PointerController that specifically handles
 * mouse cursor resources and actions.
 */
class MouseCursorController {
public:
    MouseCursorController(PointerControllerContext& context);
    ~MouseCursorController();

    bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
    void move(float deltaX, float deltaY);
    void setButtonState(int32_t buttonState);
    int32_t getButtonState() const;
    void setPosition(float x, float y);
    void getPosition(float* outX, float* outY) const;
    int32_t getDisplayId() const;
    void fade(PointerControllerInterface::Transition transition);
    void unfade(PointerControllerInterface::Transition transition);
    void setDisplayViewport(const DisplayViewport& viewport, bool getAdditionalMouseResources);

    void updatePointerIcon(int32_t iconId);
    void setCustomPointerIcon(const SpriteIcon& icon);
    void reloadPointerResources(bool getAdditionalMouseResources);

    void getAdditionalMouseResources();
    bool isViewportValid();

    bool doBitmapAnimation(nsecs_t timestamp);
    bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);

    bool resourcesLoaded();

private:
    mutable std::mutex mLock;

    PointerResources mResources;

    PointerControllerContext& mContext;

    struct Locked {
        DisplayViewport viewport;

        size_t animationFrameIndex;
        nsecs_t lastFrameUpdatedTime;

        int32_t pointerFadeDirection;
        float pointerX;
        float pointerY;
        float pointerAlpha;
        sp<Sprite> pointerSprite;
        SpriteIcon pointerIcon;
        bool updatePointerIcon;

        bool resourcesLoaded;

        std::map<int32_t, SpriteIcon> additionalMouseResources;
        std::map<int32_t, PointerAnimation> animationResources;

        int32_t requestedPointerType;

        int32_t buttonState;

    } mLocked GUARDED_BY(mLock);

    bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
    void setPositionLocked(float x, float y);

    void updatePointerLocked();

    void loadResourcesLocked(bool getAdditionalMouseResources);
};

} // namespace android

#endif // _UI_MOUSE_CURSOR_CONTROLLER_H
+85 −673

File changed.

Preview size limit exceeded, changes collapsed.

+17 −148

File changed.

Preview size limit exceeded, changes collapsed.

Loading