/* * 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 #include "PointerController.h" #include "PointerControllerContext.h" #include #include #include namespace android { namespace { const ui::Transform kIdentityTransform; } // namespace // --- PointerController::DisplayInfoListener --- void PointerController::DisplayInfoListener::onWindowInfosChanged( const std::vector&, const std::vector& displayInfo) { mPointerController.onDisplayInfosChanged(displayInfo); } // --- PointerController --- std::shared_ptr PointerController::create( const sp& policy, const sp& looper, const sp& spriteController) { // using 'new' to access non-public constructor std::shared_ptr controller = std::shared_ptr( new PointerController(policy, looper, spriteController)); /* * Now we need to hook up the constructed PointerController object to its callbacks. * * This must be executed after the constructor but before any other methods on PointerController * in order to ensure that the fully constructed object is visible on the Looper thread, since * that may be a different thread than where the PointerController is initially constructed. * * Unfortunately, this cannot be done as part of the constructor since we need to hand out * weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr. */ controller->mContext.setHandlerController(controller); controller->mContext.setCallbackController(controller); return controller; } PointerController::PointerController(const sp& policy, const sp& looper, const sp& spriteController) : mContext(policy, looper, spriteController, *this), mCursorController(mContext), mDisplayInfoListener(new DisplayInfoListener(*this)) { std::scoped_lock lock(mLock); mLocked.presentation = Presentation::SPOT; SurfaceComposerClient::getDefault()->addWindowInfosListener(mDisplayInfoListener); } bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { return mCursorController.getBounds(outMinX, outMinY, outMaxX, outMaxY); } void PointerController::move(float deltaX, float deltaY) { const int32_t displayId = mCursorController.getDisplayId(); vec2 transformed; { std::scoped_lock lock(mLock); const auto& transform = getTransformForDisplayLocked(displayId); transformed = transformWithoutTranslation(transform, {deltaX, deltaY}); } mCursorController.move(transformed.x, transformed.y); } void PointerController::setButtonState(int32_t buttonState) { mCursorController.setButtonState(buttonState); } int32_t PointerController::getButtonState() const { return mCursorController.getButtonState(); } void PointerController::setPosition(float x, float y) { const int32_t displayId = mCursorController.getDisplayId(); vec2 transformed; { std::scoped_lock lock(mLock); const auto& transform = getTransformForDisplayLocked(displayId); transformed = transform.transform(x, y); } mCursorController.setPosition(transformed.x, transformed.y); } void PointerController::getPosition(float* outX, float* outY) const { const int32_t displayId = mCursorController.getDisplayId(); mCursorController.getPosition(outX, outY); { std::scoped_lock lock(mLock); const auto& transform = getTransformForDisplayLocked(displayId); const auto xy = transform.inverse().transform(*outX, *outY); *outX = xy.x; *outY = xy.y; } } int32_t PointerController::getDisplayId() const { return mCursorController.getDisplayId(); } void PointerController::fade(Transition transition) { std::scoped_lock lock(mLock); mCursorController.fade(transition); } void PointerController::unfade(Transition transition) { std::scoped_lock lock(mLock); mCursorController.unfade(transition); } void PointerController::setPresentation(Presentation presentation) { std::scoped_lock lock(mLock); if (mLocked.presentation == presentation) { return; } mLocked.presentation = presentation; if (!mCursorController.isViewportValid()) { return; } if (presentation == Presentation::POINTER) { mCursorController.getAdditionalMouseResources(); clearSpotsLocked(); } } void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId) { std::scoped_lock lock(mLock); std::array outSpotCoords{}; const ui::Transform& transform = getTransformForDisplayLocked(displayId); for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; const vec2 xy = transform.transform(spotCoords[index].getXYValue()); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); } auto it = mLocked.spotControllers.find(displayId); if (it == mLocked.spotControllers.end()) { mLocked.spotControllers.try_emplace(displayId, displayId, mContext); } mLocked.spotControllers.at(displayId).setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits); } void PointerController::clearSpots() { std::scoped_lock lock(mLock); clearSpotsLocked(); } void PointerController::clearSpotsLocked() REQUIRES(mLock) { for (auto& [displayID, spotController] : mLocked.spotControllers) { spotController.clearSpots(); } } void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { mContext.setInactivityTimeout(inactivityTimeout); } void PointerController::reloadPointerResources() { std::scoped_lock lock(mLock); for (auto& [displayID, spotController] : mLocked.spotControllers) { spotController.reloadSpotResources(); } if (mCursorController.resourcesLoaded()) { bool getAdditionalMouseResources = false; if (mLocked.presentation == PointerController::Presentation::POINTER) { getAdditionalMouseResources = true; } mCursorController.reloadPointerResources(getAdditionalMouseResources); } } void PointerController::setDisplayViewport(const DisplayViewport& viewport) { std::scoped_lock lock(mLock); bool getAdditionalMouseResources = false; if (mLocked.presentation == PointerController::Presentation::POINTER) { getAdditionalMouseResources = true; } mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources); } void PointerController::updatePointerIcon(int32_t iconId) { std::scoped_lock lock(mLock); mCursorController.updatePointerIcon(iconId); } void PointerController::setCustomPointerIcon(const SpriteIcon& icon) { std::scoped_lock lock(mLock); mCursorController.setCustomPointerIcon(icon); } void PointerController::doInactivityTimeout() { fade(Transition::GRADUAL); } void PointerController::onDisplayViewportsUpdated(std::vector& viewports) { std::unordered_set displayIdSet; for (const DisplayViewport& viewport : viewports) { displayIdSet.insert(viewport.displayId); } std::scoped_lock lock(mLock); for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) { int32_t displayID = it->first; if (!displayIdSet.count(displayID)) { /* * Ensures that an in-progress animation won't dereference * a null pointer to TouchSpotController. */ mContext.removeAnimationCallback(displayID); it = mLocked.spotControllers.erase(it); } else { ++it; } } } void PointerController::onDisplayInfosChanged(const std::vector& displayInfo) { std::scoped_lock lock(mLock); mLocked.mDisplayInfos = displayInfo; } const ui::Transform& PointerController::getTransformForDisplayLocked(int displayId) const { const auto& di = mLocked.mDisplayInfos; auto it = std::find_if(di.begin(), di.end(), [displayId](const gui::DisplayInfo& info) { return info.displayId == displayId; }); return it != di.end() ? it->transform : kIdentityTransform; } } // namespace android