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

Commit 3404d1ff authored by Arpit Singh's avatar Arpit Singh Committed by Android (Google) Code Review
Browse files

Merge "Hide Mouse and stylus pointers on mirrored displays" into main

parents 731632a1 420d074d
Loading
Loading
Loading
Loading
+93 −45
Original line number Diff line number Diff line
@@ -89,6 +89,19 @@ void setIconForController(const std::variant<std::unique_ptr<SpriteIcon>, Pointe
    }
}

// filters and returns a set of privacy sensitive displays that are currently visible.
std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysFromWindowInfos(
        const std::vector<gui::WindowInfo>& windowInfos) {
    std::unordered_set<ui::LogicalDisplayId> privacySensitiveDisplays;
    for (const auto& windowInfo : windowInfos) {
        if (!windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE) &&
            windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY)) {
            privacySensitiveDisplays.insert(windowInfo.displayId);
        }
    }
    return privacySensitiveDisplays;
}

} // namespace

// --- PointerChoreographer ---
@@ -246,10 +259,13 @@ void PointerChoreographer::processDrawingTabletEventLocked(const android::Notify
    }

    // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
    auto [it, _] = mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
    auto [it, controllerAdded] =
            mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
                                                       getMouseControllerConstructor(
                                                               args.displayId));
    // TODO (b/325252005): Add handing for drawing tablets mouse pointer controller
    if (controllerAdded) {
        onControllerAddedOrRemovedLocked();
    }

    PointerControllerInterface& pc = *it->second;

@@ -290,7 +306,7 @@ void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMo
    auto [it, controllerAdded] =
            mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
    if (controllerAdded) {
        onControllerAddedOrRemoved();
        onControllerAddedOrRemovedLocked();
    }

    PointerControllerInterface& pc = *it->second;
@@ -326,10 +342,12 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs&
    }

    // Get the stylus pointer controller for the device, or create one if it doesn't exist.
    auto [it, _] =
    auto [it, controllerAdded] =
            mStylusPointersByDevice.try_emplace(args.deviceId,
                                                getStylusControllerConstructor(args.displayId));
    // TODO (b/325252005): Add handing for stylus pointer controller
    if (controllerAdded) {
        onControllerAddedOrRemovedLocked();
    }

    PointerControllerInterface& pc = *it->second;

@@ -369,15 +387,15 @@ void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args)
    mTouchPointersByDevice.erase(args.deviceId);
    mStylusPointersByDevice.erase(args.deviceId);
    mDrawingTabletPointersByDevice.erase(args.deviceId);
    onControllerAddedOrRemoved();
    onControllerAddedOrRemovedLocked();
}

void PointerChoreographer::onControllerAddedOrRemoved() {
void PointerChoreographer::onControllerAddedOrRemovedLocked() {
    if (!HIDE_TOUCH_INDICATORS_FOR_SECURE_WINDOWS) {
        return;
    }
    bool requireListener = !mTouchPointersByDevice.empty();
    // TODO (b/325252005): Update for other types of pointer controllers
    bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
            !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();

    if (requireListener && mWindowInfoListener == nullptr) {
        mWindowInfoListener = sp<PointerChoreographerDisplayInfoListener>::make(this);
@@ -387,12 +405,47 @@ void PointerChoreographer::onControllerAddedOrRemoved() {
        SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener,
                                                                    &initialInfo);
#endif
        onWindowInfosChangedLocked(initialInfo.first);
        mWindowInfoListener->setInitialDisplayInfos(initialInfo.first);
        onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays());
    } else if (!requireListener && mWindowInfoListener != nullptr) {
#if defined(__ANDROID__)
        SurfaceComposerClient::getDefault()->removeWindowInfosListener(mWindowInfoListener);
#endif
        mWindowInfoListener = nullptr;
    } else if (requireListener && mWindowInfoListener != nullptr) {
        // controller may have been added to an existing privacy sensitive display, we need to
        // update all controllers again
        onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays());
    }
}

void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked(
        const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
    for (auto& [_, pc] : mTouchPointersByDevice) {
        pc->clearSkipScreenshotFlags();
        for (auto displayId : privacySensitiveDisplays) {
            pc->setSkipScreenshotFlagForDisplay(displayId);
        }
    }

    for (auto& [displayId, pc] : mMousePointersByDisplay) {
        if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
            pc->setSkipScreenshotFlagForDisplay(displayId);
        } else {
            pc->clearSkipScreenshotFlags();
        }
    }

    for (auto* pointerControllerByDevice :
         {&mDrawingTabletPointersByDevice, &mStylusPointersByDevice}) {
        for (auto& [_, pc] : *pointerControllerByDevice) {
            auto displayId = pc->getDisplayId();
            if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
                pc->setSkipScreenshotFlagForDisplay(displayId);
            } else {
                pc->clearSkipScreenshotFlags();
            }
        }
    }
}

@@ -407,10 +460,10 @@ void PointerChoreographer::notifyPointerCaptureChanged(
    mNextListener.notify(args);
}

void PointerChoreographer::onWindowInfosChanged(
        const std::vector<android::gui::WindowInfo>& windowInfos) {
void PointerChoreographer::onPrivacySensitiveDisplaysChanged(
        const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
    std::scoped_lock _l(mLock);
    onWindowInfosChangedLocked(windowInfos);
    onPrivacySensitiveDisplaysChangedLocked(privacySensitiveDisplays);
}

void PointerChoreographer::dump(std::string& dump) {
@@ -467,7 +520,7 @@ PointerChoreographer::ensureMouseControllerLocked(ui::LogicalDisplayId associate
    if (it == mMousePointersByDisplay.end()) {
        it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
                     .first;
        // TODO (b/325252005): Add handing for mouse pointer controller
        onControllerAddedOrRemovedLocked();
    }

    return {displayId, *it->second};
@@ -509,7 +562,9 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo
            auto [mousePointerIt, isNewMousePointer] =
                    mMousePointersByDisplay.try_emplace(displayId,
                                                        getMouseControllerConstructor(displayId));
            // TODO (b/325252005): Add handing for mouse pointer controller
            if (isNewMousePointer) {
                onControllerAddedOrRemovedLocked();
            }

            mMouseDevices.emplace(info.getId());
            if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
@@ -549,7 +604,7 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo
                mInputDeviceInfos.end();
    });

    onControllerAddedOrRemoved();
    onControllerAddedOrRemovedLocked();

    // Check if we need to notify the policy if there's a change on the pointer display ID.
    return calculatePointerDisplayChangeToNotify();
@@ -715,31 +770,6 @@ bool PointerChoreographer::setPointerIcon(
    return false;
}

void PointerChoreographer::onWindowInfosChangedLocked(
        const std::vector<android::gui::WindowInfo>& windowInfos) {
    // Mark all spot controllers secure on displays containing secure windows and
    // remove secure flag from others if required
    std::unordered_set<ui::LogicalDisplayId> privacySensitiveDisplays;
    std::unordered_set<ui::LogicalDisplayId> allDisplayIds;
    for (const auto& windowInfo : windowInfos) {
        allDisplayIds.insert(windowInfo.displayId);
        if (!windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE) &&
            windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY)) {
            privacySensitiveDisplays.insert(windowInfo.displayId);
        }
    }

    for (auto& it : mTouchPointersByDevice) {
        auto& pc = it.second;
        for (ui::LogicalDisplayId displayId : allDisplayIds) {
            pc->setSkipScreenshot(displayId,
                                  privacySensitiveDisplays.find(displayId) !=
                                          privacySensitiveDisplays.end());
        }
    }
    // TODO (b/325252005): update skip screenshot flag for other types of pointer controllers
}

void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
    std::scoped_lock lock(mLock);
    if (visible) {
@@ -793,9 +823,27 @@ PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusContr
void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
        const gui::WindowInfosUpdate& windowInfosUpdate) {
    std::scoped_lock _l(mListenerLock);
    if (mPointerChoreographer != nullptr) {
        mPointerChoreographer->onWindowInfosChanged(windowInfosUpdate.windowInfos);
    if (mPointerChoreographer == nullptr) {
        return;
    }
    auto newPrivacySensitiveDisplays =
            getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos);
    if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) {
        mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays);
        mPointerChoreographer->onPrivacySensitiveDisplaysChanged(mPrivacySensitiveDisplays);
    }
}

void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfos(
        const std::vector<gui::WindowInfo>& windowInfos) {
    std::scoped_lock _l(mListenerLock);
    mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos);
}

std::unordered_set<ui::LogicalDisplayId /*displayId*/>
PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplays() {
    std::scoped_lock _l(mListenerLock);
    return mPrivacySensitiveDisplays;
}

void PointerChoreographer::PointerChoreographerDisplayInfoListener::
+17 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <android-base/thread_annotations.h>
#include <gui/WindowInfosListener.h>
#include <type_traits>
#include <unordered_set>

namespace android {

@@ -108,7 +109,8 @@ public:
    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;

    // Public because it's also used by tests to simulate the WindowInfosListener callback
    void onWindowInfosChanged(const std::vector<android::gui::WindowInfo>& windowInfos);
    void onPrivacySensitiveDisplaysChanged(
            const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays);

    void dump(std::string& dump) override;

@@ -133,20 +135,32 @@ private:
    void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processDeviceReset(const NotifyDeviceResetArgs& args);
    void onControllerAddedOrRemoved() REQUIRES(mLock);
    void onWindowInfosChangedLocked(const std::vector<android::gui::WindowInfo>& windowInfos)
    void onControllerAddedOrRemovedLocked() REQUIRES(mLock);
    void onPrivacySensitiveDisplaysChangedLocked(
            const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays)
            REQUIRES(mLock);

    /* This listener keeps tracks of visible privacy sensitive displays and updates the
     * choreographer if there are any changes.
     *
     * Listener uses mListenerLock to guard all private data as choreographer and SurfaceComposer
     * both can call into the listener. To prevent deadlocks Choreographer can call listener with
     * its lock held, but listener must not call choreographer with its lock.
     */
    class PointerChoreographerDisplayInfoListener : public gui::WindowInfosListener {
    public:
        explicit PointerChoreographerDisplayInfoListener(PointerChoreographer* pc)
              : mPointerChoreographer(pc){};
        void onWindowInfosChanged(const gui::WindowInfosUpdate&) override;
        void setInitialDisplayInfos(const std::vector<gui::WindowInfo>& windowInfos);
        std::unordered_set<ui::LogicalDisplayId /*displayId*/> getPrivacySensitiveDisplays();
        void onPointerChoreographerDestroyed();

    private:
        std::mutex mListenerLock;
        PointerChoreographer* mPointerChoreographer GUARDED_BY(mListenerLock);
        std::unordered_set<ui::LogicalDisplayId /*displayId*/> mPrivacySensitiveDisplays
                GUARDED_BY(mListenerLock);
    };
    sp<PointerChoreographerDisplayInfoListener> mWindowInfoListener GUARDED_BY(mLock);

+6 −3
Original line number Diff line number Diff line
@@ -142,10 +142,13 @@ public:
    /* Sets the custom pointer icon for mice or styluses. */
    virtual void setCustomPointerIcon(const SpriteIcon& icon) = 0;

    /* Sets the flag to skip screenshot of the pointer indicators on the display matching the
     * provided displayId.
    /* Sets the flag to skip screenshot of the pointer indicators on the display for the specified
     * displayId. This flag can only be reset with resetSkipScreenshotFlags()
     */
    virtual void setSkipScreenshot(ui::LogicalDisplayId displayId, bool skip) = 0;
    virtual void setSkipScreenshotFlagForDisplay(ui::LogicalDisplayId displayId) = 0;

    /* Resets the flag to skip screenshot of the pointer indicators for all displays. */
    virtual void clearSkipScreenshotFlags() = 0;
};

} // namespace android
+7 −7
Original line number Diff line number Diff line
@@ -76,13 +76,13 @@ void FakePointerController::setCustomPointerIcon(const SpriteIcon& icon) {
    mCustomIconStyle = icon.style;
}

void FakePointerController::setSkipScreenshot(ui::LogicalDisplayId displayId, bool skip) {
    if (skip) {
void FakePointerController::setSkipScreenshotFlagForDisplay(ui::LogicalDisplayId displayId) {
    mDisplaysToSkipScreenshot.insert(displayId);
    } else {
        mDisplaysToSkipScreenshot.erase(displayId);
}
};

void FakePointerController::clearSkipScreenshotFlags() {
    mDisplaysToSkipScreenshot.clear();
}

void FakePointerController::assertViewportSet(ui::LogicalDisplayId displayId) {
    ASSERT_TRUE(mDisplayId);
+2 −1
Original line number Diff line number Diff line
@@ -45,7 +45,8 @@ public:
    void setDisplayViewport(const DisplayViewport& viewport) override;
    void updatePointerIcon(PointerIconStyle iconId) override;
    void setCustomPointerIcon(const SpriteIcon& icon) override;
    void setSkipScreenshot(ui::LogicalDisplayId displayId, bool skip) override;
    void setSkipScreenshotFlagForDisplay(ui::LogicalDisplayId displayId) override;
    void clearSkipScreenshotFlags() override;
    void fade(Transition) override;

    void assertViewportSet(ui::LogicalDisplayId displayId);
Loading