/*
 * Copyright 2024 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.
 */

#include "FakeInputDispatcherPolicy.h"

#include <gtest/gtest.h>

namespace android {

// --- FakeInputDispatcherPolicy ---

void FakeInputDispatcherPolicy::assertFilterInputEventWasCalled(const NotifyKeyArgs& args) {
    assertFilterInputEventWasCalledInternal([&args](const InputEvent& event) {
        ASSERT_EQ(event.getType(), InputEventType::KEY);
        EXPECT_EQ(event.getDisplayId(), args.displayId);

        const auto& keyEvent = static_cast<const KeyEvent&>(event);
        EXPECT_EQ(keyEvent.getEventTime(), args.eventTime);
        EXPECT_EQ(keyEvent.getAction(), args.action);
    });
}

void FakeInputDispatcherPolicy::assertFilterInputEventWasCalled(const NotifyMotionArgs& args,
                                                                vec2 point) {
    assertFilterInputEventWasCalledInternal([&](const InputEvent& event) {
        ASSERT_EQ(event.getType(), InputEventType::MOTION);
        EXPECT_EQ(event.getDisplayId(), args.displayId);

        const auto& motionEvent = static_cast<const MotionEvent&>(event);
        EXPECT_EQ(motionEvent.getEventTime(), args.eventTime);
        EXPECT_EQ(motionEvent.getAction(), args.action);
        EXPECT_NEAR(motionEvent.getX(0), point.x, MotionEvent::ROUNDING_PRECISION);
        EXPECT_NEAR(motionEvent.getY(0), point.y, MotionEvent::ROUNDING_PRECISION);
        EXPECT_NEAR(motionEvent.getRawX(0), point.x, MotionEvent::ROUNDING_PRECISION);
        EXPECT_NEAR(motionEvent.getRawY(0), point.y, MotionEvent::ROUNDING_PRECISION);
    });
}

void FakeInputDispatcherPolicy::assertFilterInputEventWasNotCalled() {
    std::scoped_lock lock(mLock);
    ASSERT_EQ(nullptr, mFilteredEvent);
}

void FakeInputDispatcherPolicy::assertNotifySwitchWasCalled(const NotifySwitchArgs& args) {
    std::scoped_lock lock(mLock);
    ASSERT_TRUE(mLastNotifySwitch);
    // We do not check id because it is not exposed to the policy
    EXPECT_EQ(args.eventTime, mLastNotifySwitch->eventTime);
    EXPECT_EQ(args.policyFlags, mLastNotifySwitch->policyFlags);
    EXPECT_EQ(args.switchValues, mLastNotifySwitch->switchValues);
    EXPECT_EQ(args.switchMask, mLastNotifySwitch->switchMask);
    mLastNotifySwitch = std::nullopt;
}

void FakeInputDispatcherPolicy::assertOnPointerDownEquals(const sp<IBinder>& touchedToken) {
    std::scoped_lock lock(mLock);
    ASSERT_EQ(touchedToken, mOnPointerDownToken);
    mOnPointerDownToken.clear();
}

void FakeInputDispatcherPolicy::assertOnPointerDownWasNotCalled() {
    std::scoped_lock lock(mLock);
    ASSERT_TRUE(mOnPointerDownToken == nullptr)
            << "Expected onPointerDownOutsideFocus to not have been called";
}

void FakeInputDispatcherPolicy::assertNotifyNoFocusedWindowAnrWasCalled(
        std::chrono::nanoseconds timeout,
        const std::shared_ptr<InputApplicationHandle>& expectedApplication) {
    std::unique_lock lock(mLock);
    android::base::ScopedLockAssertion assumeLocked(mLock);
    std::shared_ptr<InputApplicationHandle> application;
    ASSERT_NO_FATAL_FAILURE(
            application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock));
    ASSERT_EQ(expectedApplication, application);
}

void FakeInputDispatcherPolicy::assertNotifyWindowUnresponsiveWasCalled(
        std::chrono::nanoseconds timeout, const sp<gui::WindowInfoHandle>& window) {
    LOG_ALWAYS_FATAL_IF(window == nullptr, "window should not be null");
    assertNotifyWindowUnresponsiveWasCalled(timeout, window->getToken(),
                                            window->getInfo()->ownerPid);
}

void FakeInputDispatcherPolicy::assertNotifyWindowUnresponsiveWasCalled(
        std::chrono::nanoseconds timeout, const sp<IBinder>& expectedToken,
        std::optional<gui::Pid> expectedPid) {
    std::unique_lock lock(mLock);
    android::base::ScopedLockAssertion assumeLocked(mLock);
    AnrResult result;
    ASSERT_NO_FATAL_FAILURE(result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock));
    ASSERT_EQ(expectedToken, result.token);
    ASSERT_EQ(expectedPid, result.pid);
}

sp<IBinder> FakeInputDispatcherPolicy::getUnresponsiveWindowToken(
        std::chrono::nanoseconds timeout) {
    std::unique_lock lock(mLock);
    android::base::ScopedLockAssertion assumeLocked(mLock);
    AnrResult result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock);
    const auto& [token, _] = result;
    return token;
}

void FakeInputDispatcherPolicy::assertNotifyWindowResponsiveWasCalled(
        const sp<IBinder>& expectedToken, std::optional<gui::Pid> expectedPid) {
    std::unique_lock lock(mLock);
    android::base::ScopedLockAssertion assumeLocked(mLock);
    AnrResult result;
    ASSERT_NO_FATAL_FAILURE(result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock));
    ASSERT_EQ(expectedToken, result.token);
    ASSERT_EQ(expectedPid, result.pid);
}

sp<IBinder> FakeInputDispatcherPolicy::getResponsiveWindowToken() {
    std::unique_lock lock(mLock);
    android::base::ScopedLockAssertion assumeLocked(mLock);
    AnrResult result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock);
    const auto& [token, _] = result;
    return token;
}

void FakeInputDispatcherPolicy::assertNotifyAnrWasNotCalled() {
    std::scoped_lock lock(mLock);
    ASSERT_TRUE(mAnrApplications.empty());
    ASSERT_TRUE(mAnrWindows.empty());
    ASSERT_TRUE(mResponsiveWindows.empty())
            << "ANR was not called, but please also consume the 'connection is responsive' "
               "signal";
}

PointerCaptureRequest FakeInputDispatcherPolicy::assertSetPointerCaptureCalled(
        const sp<gui::WindowInfoHandle>& window, bool enabled) {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);

    if (!mPointerCaptureChangedCondition
                 .wait_for(lock, 100ms, [this, enabled, window]() REQUIRES(mLock) {
                     if (enabled) {
                         return mPointerCaptureRequest->isEnable() &&
                                 mPointerCaptureRequest->window == window->getToken();
                     } else {
                         return !mPointerCaptureRequest->isEnable();
                     }
                 })) {
        ADD_FAILURE() << "Timed out waiting for setPointerCapture(" << window->getName() << ", "
                      << enabled << ") to be called.";
        return {};
    }
    auto request = *mPointerCaptureRequest;
    mPointerCaptureRequest.reset();
    return request;
}

void FakeInputDispatcherPolicy::assertSetPointerCaptureNotCalled() {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);

    if (mPointerCaptureChangedCondition.wait_for(lock, 100ms) != std::cv_status::timeout) {
        FAIL() << "Expected setPointerCapture(request) to not be called, but was called. "
                  "enabled = "
               << std::to_string(mPointerCaptureRequest->isEnable());
    }
    mPointerCaptureRequest.reset();
}

void FakeInputDispatcherPolicy::assertDropTargetEquals(const InputDispatcherInterface& dispatcher,
                                                       const sp<IBinder>& targetToken) {
    dispatcher.waitForIdle();
    std::scoped_lock lock(mLock);
    ASSERT_TRUE(mNotifyDropWindowWasCalled);
    ASSERT_EQ(targetToken, mDropTargetWindowToken);
    mNotifyDropWindowWasCalled = false;
}

void FakeInputDispatcherPolicy::assertNotifyInputChannelBrokenWasCalled(const sp<IBinder>& token) {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);
    std::optional<sp<IBinder>> receivedToken =
            getItemFromStorageLockedInterruptible(100ms, mBrokenInputChannels, lock,
                                                  mNotifyInputChannelBroken);
    ASSERT_TRUE(receivedToken.has_value()) << "Did not receive the broken channel token";
    ASSERT_EQ(token, *receivedToken);
}

void FakeInputDispatcherPolicy::setInterceptKeyTimeout(std::chrono::milliseconds timeout) {
    mInterceptKeyTimeout = timeout;
}

std::chrono::nanoseconds FakeInputDispatcherPolicy::getKeyWaitingForEventsTimeout() {
    return 500ms;
}

void FakeInputDispatcherPolicy::setStaleEventTimeout(std::chrono::nanoseconds timeout) {
    mStaleEventTimeout = timeout;
}

void FakeInputDispatcherPolicy::setConsumeKeyBeforeDispatching(bool consumeKeyBeforeDispatching) {
    mConsumeKeyBeforeDispatching = consumeKeyBeforeDispatching;
}

void FakeInputDispatcherPolicy::assertFocusedDisplayNotified(ui::LogicalDisplayId expectedDisplay) {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);

    if (!mFocusedDisplayNotifiedCondition.wait_for(lock, 100ms,
                                                   [this, expectedDisplay]() REQUIRES(mLock) {
                                                       if (!mNotifiedFocusedDisplay.has_value() ||
                                                           mNotifiedFocusedDisplay.value() !=
                                                                   expectedDisplay) {
                                                           return false;
                                                       }
                                                       return true;
                                                   })) {
        ADD_FAILURE() << "Timed out waiting for notifyFocusedDisplayChanged(" << expectedDisplay
                      << ") to be called.";
    }
}

void FakeInputDispatcherPolicy::assertUserActivityNotPoked() {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);

    std::optional<UserActivityPokeEvent> pokeEvent =
            getItemFromStorageLockedInterruptible(500ms, mUserActivityPokeEvents, lock,
                                                  mNotifyUserActivity);

    ASSERT_FALSE(pokeEvent) << "Expected user activity not to have been poked";
}

void FakeInputDispatcherPolicy::assertUserActivityPoked(
        std::optional<UserActivityPokeEvent> expectedPokeEvent) {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);

    std::optional<UserActivityPokeEvent> pokeEvent =
            getItemFromStorageLockedInterruptible(500ms, mUserActivityPokeEvents, lock,
                                                  mNotifyUserActivity);
    ASSERT_TRUE(pokeEvent) << "Expected a user poke event";

    if (expectedPokeEvent) {
        ASSERT_EQ(expectedPokeEvent, *pokeEvent);
    }
}

void FakeInputDispatcherPolicy::assertNotifyDeviceInteractionWasCalled(int32_t deviceId,
                                                                       std::set<gui::Uid> uids) {
    ASSERT_EQ(std::make_pair(deviceId, uids), mNotifiedInteractions.popWithTimeout(100ms));
}

void FakeInputDispatcherPolicy::assertNotifyDeviceInteractionWasNotCalled() {
    ASSERT_FALSE(mNotifiedInteractions.popWithTimeout(10ms));
}

void FakeInputDispatcherPolicy::setUnhandledKeyHandler(
        std::function<std::optional<KeyEvent>(const KeyEvent&)> handler) {
    std::scoped_lock lock(mLock);
    mUnhandledKeyHandler = handler;
}

void FakeInputDispatcherPolicy::assertUnhandledKeyReported(int32_t keycode) {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);
    std::optional<int32_t> unhandledKeycode =
            getItemFromStorageLockedInterruptible(100ms, mReportedUnhandledKeycodes, lock,
                                                  mNotifyUnhandledKey);
    ASSERT_TRUE(unhandledKeycode) << "Expected unhandled key to be reported";
    ASSERT_EQ(unhandledKeycode, keycode);
}

void FakeInputDispatcherPolicy::assertUnhandledKeyNotReported() {
    std::unique_lock lock(mLock);
    base::ScopedLockAssertion assumeLocked(mLock);
    std::optional<int32_t> unhandledKeycode =
            getItemFromStorageLockedInterruptible(10ms, mReportedUnhandledKeycodes, lock,
                                                  mNotifyUnhandledKey);
    ASSERT_FALSE(unhandledKeycode) << "Expected unhandled key NOT to be reported";
}

template <class T>
T FakeInputDispatcherPolicy::getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout,
                                                            std::queue<T>& storage,
                                                            std::unique_lock<std::mutex>& lock)
        REQUIRES(mLock) {
    // If there is an ANR, Dispatcher won't be idle because there are still events
    // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle
    // before checking if ANR was called.
    // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need
    // to provide it some time to act. 100ms seems reasonable.
    std::chrono::duration timeToWait = timeout + 100ms; // provide some slack
    const std::chrono::time_point start = std::chrono::steady_clock::now();
    std::optional<T> token =
            getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr);
    if (!token.has_value()) {
        ADD_FAILURE() << "Did not receive the ANR callback";
        return {};
    }

    const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
    // Ensure that the ANR didn't get raised too early. We can't be too strict here because
    // the dispatcher started counting before this function was called
    if (std::chrono::abs(timeout - waited) > 100ms) {
        ADD_FAILURE() << "ANR was raised too early or too late. Expected "
                      << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
                      << "ms, but waited "
                      << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count()
                      << "ms instead";
    }
    return *token;
}

template <class T>
std::optional<T> FakeInputDispatcherPolicy::getItemFromStorageLockedInterruptible(
        std::chrono::nanoseconds timeout, std::queue<T>& storage,
        std::unique_lock<std::mutex>& lock, std::condition_variable& condition) REQUIRES(mLock) {
    condition.wait_for(lock, timeout, [&storage]() REQUIRES(mLock) { return !storage.empty(); });
    if (storage.empty()) {
        return std::nullopt;
    }
    T item = storage.front();
    storage.pop();
    return std::make_optional(item);
}

void FakeInputDispatcherPolicy::notifyWindowUnresponsive(const sp<IBinder>& connectionToken,
                                                         std::optional<gui::Pid> pid,
                                                         const std::string&) {
    std::scoped_lock lock(mLock);
    mAnrWindows.push({connectionToken, pid});
    mNotifyAnr.notify_all();
}

void FakeInputDispatcherPolicy::notifyWindowResponsive(const sp<IBinder>& connectionToken,
                                                       std::optional<gui::Pid> pid) {
    std::scoped_lock lock(mLock);
    mResponsiveWindows.push({connectionToken, pid});
    mNotifyAnr.notify_all();
}

void FakeInputDispatcherPolicy::notifyNoFocusedWindowAnr(
        const std::shared_ptr<InputApplicationHandle>& applicationHandle) {
    std::scoped_lock lock(mLock);
    mAnrApplications.push(applicationHandle);
    mNotifyAnr.notify_all();
}

void FakeInputDispatcherPolicy::notifyInputChannelBroken(const sp<IBinder>& connectionToken) {
    std::scoped_lock lock(mLock);
    mBrokenInputChannels.push(connectionToken);
    mNotifyInputChannelBroken.notify_all();
}

void FakeInputDispatcherPolicy::notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {}

void FakeInputDispatcherPolicy::notifySensorEvent(int32_t deviceId,
                                                  InputDeviceSensorType sensorType,
                                                  InputDeviceSensorAccuracy accuracy,
                                                  nsecs_t timestamp,
                                                  const std::vector<float>& values) {}

void FakeInputDispatcherPolicy::notifySensorAccuracy(int deviceId, InputDeviceSensorType sensorType,
                                                     InputDeviceSensorAccuracy accuracy) {}

void FakeInputDispatcherPolicy::notifyVibratorState(int32_t deviceId, bool isOn) {}

bool FakeInputDispatcherPolicy::filterInputEvent(const InputEvent& inputEvent,
                                                 uint32_t policyFlags) {
    std::scoped_lock lock(mLock);
    switch (inputEvent.getType()) {
        case InputEventType::KEY: {
            const KeyEvent& keyEvent = static_cast<const KeyEvent&>(inputEvent);
            mFilteredEvent = std::make_unique<KeyEvent>(keyEvent);
            break;
        }

        case InputEventType::MOTION: {
            const MotionEvent& motionEvent = static_cast<const MotionEvent&>(inputEvent);
            mFilteredEvent = std::make_unique<MotionEvent>(motionEvent);
            break;
        }
        default: {
            ADD_FAILURE() << "Should only filter keys or motions";
            break;
        }
    }
    return true;
}

void FakeInputDispatcherPolicy::interceptKeyBeforeQueueing(const KeyEvent& inputEvent, uint32_t&) {
    if (inputEvent.getAction() == AKEY_EVENT_ACTION_UP) {
        // Clear intercept state when we handled the event.
        mInterceptKeyTimeout = 0ms;
    }
}

void FakeInputDispatcherPolicy::interceptMotionBeforeQueueing(ui::LogicalDisplayId, uint32_t,
                                                              int32_t, nsecs_t, uint32_t&) {}

nsecs_t FakeInputDispatcherPolicy::interceptKeyBeforeDispatching(const sp<IBinder>&,
                                                                 const KeyEvent&, uint32_t) {
    if (mConsumeKeyBeforeDispatching) {
        return -1;
    }
    nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count();
    // Clear intercept state so we could dispatch the event in next wake.
    mInterceptKeyTimeout = 0ms;
    return delay;
}

std::optional<KeyEvent> FakeInputDispatcherPolicy::dispatchUnhandledKey(const sp<IBinder>&,
                                                                        const KeyEvent& event,
                                                                        uint32_t) {
    std::scoped_lock lock(mLock);
    mReportedUnhandledKeycodes.emplace(event.getKeyCode());
    mNotifyUnhandledKey.notify_all();
    return mUnhandledKeyHandler != nullptr ? mUnhandledKeyHandler(event) : std::nullopt;
}

void FakeInputDispatcherPolicy::notifySwitch(nsecs_t when, uint32_t switchValues,
                                             uint32_t switchMask, uint32_t policyFlags) {
    std::scoped_lock lock(mLock);
    // We simply reconstruct NotifySwitchArgs in policy because InputDispatcher is
    // essentially a passthrough for notifySwitch.
    mLastNotifySwitch =
            NotifySwitchArgs(InputEvent::nextId(), when, policyFlags, switchValues, switchMask);
}

void FakeInputDispatcherPolicy::pokeUserActivity(nsecs_t eventTime, int32_t eventType,
                                                 ui::LogicalDisplayId displayId) {
    std::scoped_lock lock(mLock);
    mNotifyUserActivity.notify_all();
    mUserActivityPokeEvents.push({eventTime, eventType, displayId});
}

bool FakeInputDispatcherPolicy::isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) {
    return std::chrono::nanoseconds(currentTime - eventTime) >= mStaleEventTimeout;
}

void FakeInputDispatcherPolicy::onPointerDownOutsideFocus(const sp<IBinder>& newToken) {
    std::scoped_lock lock(mLock);
    mOnPointerDownToken = newToken;
}

void FakeInputDispatcherPolicy::setPointerCapture(const PointerCaptureRequest& request) {
    std::scoped_lock lock(mLock);
    mPointerCaptureRequest = {request};
    mPointerCaptureChangedCondition.notify_all();
}

void FakeInputDispatcherPolicy::notifyDropWindow(const sp<IBinder>& token, float x, float y) {
    std::scoped_lock lock(mLock);
    mNotifyDropWindowWasCalled = true;
    mDropTargetWindowToken = token;
}

void FakeInputDispatcherPolicy::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
                                                        const std::set<gui::Uid>& uids) {
    ASSERT_TRUE(mNotifiedInteractions.emplace(deviceId, uids));
}

void FakeInputDispatcherPolicy::assertFilterInputEventWasCalledInternal(
        const std::function<void(const InputEvent&)>& verify) {
    std::scoped_lock lock(mLock);
    ASSERT_NE(nullptr, mFilteredEvent) << "Expected filterInputEvent() to have been called.";
    verify(*mFilteredEvent);
    mFilteredEvent = nullptr;
}

void FakeInputDispatcherPolicy::notifyFocusedDisplayChanged(ui::LogicalDisplayId displayId) {
    std::scoped_lock lock(mLock);
    mNotifiedFocusedDisplay = displayId;
    mFocusedDisplayNotifiedCondition.notify_all();
}

} // namespace android
