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

Commit ae10ee68 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Add logic to classify input events into InputDeviceUsageSources

Bug: 275726706
Test: atest inputflinger_tests
Change-Id: I3edfe3b16d705498beb3453dff83cd2a84a9bc9d
parent 9205e42f
Loading
Loading
Loading
Loading
+92 −1
Original line number Diff line number Diff line
@@ -17,10 +17,11 @@
#define LOG_TAG "InputDeviceMetricsCollector"
#include "InputDeviceMetricsCollector.h"

#include "KeyCodeClassifications.h"

#include <android-base/stringprintf.h>
#include <input/PrintTools.h>
#include <linux/input.h>
#include <statslog.h>

namespace android {

@@ -80,6 +81,96 @@ bool isIgnoredInputDeviceId(int32_t deviceId) {

} // namespace

InputDeviceUsageSource getUsageSourceForKeyArgs(const InputDeviceInfo& info,
                                                const NotifyKeyArgs& keyArgs) {
    if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) {
        return InputDeviceUsageSource::UNKNOWN;
    }

    if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) &&
        DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) {
        return InputDeviceUsageSource::DPAD;
    }

    if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) &&
        GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) {
        return InputDeviceUsageSource::GAMEPAD;
    }

    if (info.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
        return InputDeviceUsageSource::KEYBOARD;
    }

    return InputDeviceUsageSource::BUTTONS;
}

std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) {
    LOG_ALWAYS_FATAL_IF(motionArgs.pointerCount < 1, "Received motion args without pointers");
    std::set<InputDeviceUsageSource> sources;

    for (uint32_t i = 0; i < motionArgs.pointerCount; i++) {
        const auto toolType = motionArgs.pointerProperties[i].toolType;
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) {
            if (toolType == ToolType::MOUSE) {
                sources.emplace(InputDeviceUsageSource::MOUSE);
                continue;
            }
            if (toolType == ToolType::FINGER) {
                sources.emplace(InputDeviceUsageSource::TOUCHPAD);
                continue;
            }
            if (isStylusToolType(toolType)) {
                sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT);
                continue;
            }
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) &&
            toolType == ToolType::MOUSE) {
            sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) &&
            toolType == ToolType::FINGER) {
            sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) &&
            isStylusToolType(toolType)) {
            sources.emplace(InputDeviceUsageSource::STYLUS_FUSED);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) {
            sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) {
            sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) {
            sources.emplace(InputDeviceUsageSource::JOYSTICK);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) {
            sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) {
            sources.emplace(InputDeviceUsageSource::TRACKBALL);
            continue;
        }
        if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) {
            sources.emplace(InputDeviceUsageSource::TOUCHSCREEN);
            continue;
        }
        sources.emplace(InputDeviceUsageSource::UNKNOWN);
    }

    return sources;
}

// --- InputDeviceMetricsCollector ---

InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener)
      : InputDeviceMetricsCollector(listener, sStatsdLogger, DEFAULT_USAGE_SESSION_TIMEOUT) {}

+35 −0
Original line number Diff line number Diff line
@@ -17,11 +17,14 @@
#pragma once

#include "InputListener.h"
#include "NotifyArgs.h"

#include <ftl/mixins.h>
#include <input/InputDevice.h>
#include <statslog.h>
#include <chrono>
#include <map>
#include <set>
#include <vector>

namespace android {
@@ -40,6 +43,38 @@ public:
    virtual void dump(std::string& dump) = 0;
};

/**
 * Enum representation of the InputDeviceUsageSource.
 */
enum class InputDeviceUsageSource : int32_t {
    UNKNOWN = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__UNKNOWN,
    BUTTONS = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__BUTTONS,
    KEYBOARD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__KEYBOARD,
    DPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__DPAD,
    GAMEPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__GAMEPAD,
    JOYSTICK = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__JOYSTICK,
    MOUSE = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__MOUSE,
    MOUSE_CAPTURED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__MOUSE_CAPTURED,
    TOUCHPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHPAD,
    TOUCHPAD_CAPTURED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHPAD_CAPTURED,
    ROTARY_ENCODER = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__ROTARY_ENCODER,
    STYLUS_DIRECT = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_DIRECT,
    STYLUS_INDIRECT = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_INDIRECT,
    STYLUS_FUSED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_FUSED,
    TOUCH_NAVIGATION = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCH_NAVIGATION,
    TOUCHSCREEN = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHSCREEN,
    TRACKBALL = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TRACKBALL,

    ftl_first = UNKNOWN,
    ftl_last = TRACKBALL,
};

/** Returns the InputDeviceUsageSource that corresponds to the key event. */
InputDeviceUsageSource getUsageSourceForKeyArgs(const InputDeviceInfo&, const NotifyKeyArgs&);

/** Returns the InputDeviceUsageSources that correspond to the motion event. */
std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs&);

/** The logging interface for the metrics collector, injected for testing. */
class InputDeviceMetricsLogger {
public:
+55 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.
 */

#pragma once

#include <android/input.h>
#include <set>

namespace android {

/** The set of all Android key codes that are required for a device to be classified as a D-pad. */
static const std::set<int32_t> DPAD_REQUIRED_KEYCODES = {
        AKEYCODE_DPAD_UP,    AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_LEFT,
        AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_CENTER,
};

/** The set of all Android key codes that correspond to D-pad keys. */
static const std::set<int32_t> DPAD_ALL_KEYCODES = {
        AKEYCODE_DPAD_UP,       AKEYCODE_DPAD_DOWN,      AKEYCODE_DPAD_LEFT,
        AKEYCODE_DPAD_RIGHT,    AKEYCODE_DPAD_CENTER,    AKEYCODE_DPAD_UP_LEFT,
        AKEYCODE_DPAD_UP_RIGHT, AKEYCODE_DPAD_DOWN_LEFT, AKEYCODE_DPAD_DOWN_RIGHT,
};

/** The set of all Android key codes that correspond to gamepad buttons. */
static const std::set<int32_t> GAMEPAD_KEYCODES = {
        AKEYCODE_BUTTON_A,      AKEYCODE_BUTTON_B,      AKEYCODE_BUTTON_C,    //
        AKEYCODE_BUTTON_X,      AKEYCODE_BUTTON_Y,      AKEYCODE_BUTTON_Z,    //
        AKEYCODE_BUTTON_L1,     AKEYCODE_BUTTON_R1,                           //
        AKEYCODE_BUTTON_L2,     AKEYCODE_BUTTON_R2,                           //
        AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,                       //
        AKEYCODE_BUTTON_START,  AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, //
};

/** The set of all Android key codes that correspond to buttons (bit-switches) on a stylus. */
static const std::set<int32_t> STYLUS_BUTTON_KEYCODES = {
        AKEYCODE_STYLUS_BUTTON_PRIMARY,
        AKEYCODE_STYLUS_BUTTON_SECONDARY,
        AKEYCODE_STYLUS_BUTTON_TERTIARY,
        AKEYCODE_STYLUS_BUTTON_TAIL,
};

} // namespace android
+12 −35
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@

#include "EventHub.h"

#include "KeyCodeClassifications.h"

#define INDENT "  "
#define INDENT2 "    "
#define INDENT3 "      "
@@ -189,14 +191,6 @@ static std::string sha1(const std::string& in) {
    return out;
}

/* The set of all Android key codes that correspond to buttons (bit-switches) on a stylus. */
static constexpr std::array<int32_t, 4> STYLUS_BUTTON_KEYCODES = {
        AKEYCODE_STYLUS_BUTTON_PRIMARY,
        AKEYCODE_STYLUS_BUTTON_SECONDARY,
        AKEYCODE_STYLUS_BUTTON_TERTIARY,
        AKEYCODE_STYLUS_BUTTON_TAIL,
};

/**
 * Return true if name matches "v4l-touch*"
 */
@@ -2060,15 +2054,6 @@ void EventHub::scanDevicesLocked() {

// ----------------------------------------------------------------------------

static const int32_t GAMEPAD_KEYCODES[] = {
        AKEYCODE_BUTTON_A,      AKEYCODE_BUTTON_B,      AKEYCODE_BUTTON_C,    //
        AKEYCODE_BUTTON_X,      AKEYCODE_BUTTON_Y,      AKEYCODE_BUTTON_Z,    //
        AKEYCODE_BUTTON_L1,     AKEYCODE_BUTTON_R1,                           //
        AKEYCODE_BUTTON_L2,     AKEYCODE_BUTTON_R2,                           //
        AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,                       //
        AKEYCODE_BUTTON_START,  AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, //
};

status_t EventHub::registerFdForEpoll(int fd) {
    // TODO(b/121395353) - consider adding EPOLLRDHUP
    struct epoll_event eventItem = {};
@@ -2391,31 +2376,23 @@ void EventHub::openDeviceLocked(const std::string& devicePath) {
            device->classes |= InputDeviceClass::ALPHAKEY;
        }

        // See if this device has a DPAD.
        if (device->hasKeycodeLocked(AKEYCODE_DPAD_UP) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_DOWN) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_LEFT) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_RIGHT) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_CENTER)) {
        // See if this device has a D-pad.
        if (std::all_of(DPAD_REQUIRED_KEYCODES.begin(), DPAD_REQUIRED_KEYCODES.end(),
                        [&](int32_t keycode) { return device->hasKeycodeLocked(keycode); })) {
            device->classes |= InputDeviceClass::DPAD;
        }

        // See if this device has a gamepad.
        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES) / sizeof(GAMEPAD_KEYCODES[0]); i++) {
            if (device->hasKeycodeLocked(GAMEPAD_KEYCODES[i])) {
        if (std::any_of(GAMEPAD_KEYCODES.begin(), GAMEPAD_KEYCODES.end(),
                        [&](int32_t keycode) { return device->hasKeycodeLocked(keycode); })) {
            device->classes |= InputDeviceClass::GAMEPAD;
                break;
            }
        }

        // See if this device has any stylus buttons that we would want to fuse with touch data.
        if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT)) {
            for (int32_t keycode : STYLUS_BUTTON_KEYCODES) {
                if (device->hasKeycodeLocked(keycode)) {
        if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT) &&
            std::any_of(STYLUS_BUTTON_KEYCODES.begin(), STYLUS_BUTTON_KEYCODES.end(),
                        [&](int32_t keycode) { return device->hasKeycodeLocked(keycode); })) {
            device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
                    break;
                }
            }
        }
    }

+74 −0
Original line number Diff line number Diff line
@@ -285,4 +285,78 @@ private:
    std::vector<PointerBuilder> mPointers;
};

class KeyArgsBuilder {
public:
    KeyArgsBuilder(int32_t action, int32_t source) {
        mAction = action;
        mSource = source;
        mEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
        mDownTime = mEventTime;
    }

    KeyArgsBuilder& deviceId(int32_t deviceId) {
        mDeviceId = deviceId;
        return *this;
    }

    KeyArgsBuilder& downTime(nsecs_t downTime) {
        mDownTime = downTime;
        return *this;
    }

    KeyArgsBuilder& eventTime(nsecs_t eventTime) {
        mEventTime = eventTime;
        return *this;
    }

    KeyArgsBuilder& displayId(int32_t displayId) {
        mDisplayId = displayId;
        return *this;
    }

    KeyArgsBuilder& policyFlags(int32_t policyFlags) {
        mPolicyFlags = policyFlags;
        return *this;
    }

    KeyArgsBuilder& addFlag(uint32_t flags) {
        mFlags |= flags;
        return *this;
    }

    KeyArgsBuilder& keyCode(int32_t keyCode) {
        mKeyCode = keyCode;
        return *this;
    }

    NotifyKeyArgs build() const {
        return {InputEvent::nextId(),
                mEventTime,
                /*readTime=*/mEventTime,
                mDeviceId,
                mSource,
                mDisplayId,
                mPolicyFlags,
                mAction,
                mFlags,
                mKeyCode,
                mScanCode,
                mMetaState,
                mDownTime};
    }

private:
    int32_t mAction;
    int32_t mDeviceId = DEFAULT_DEVICE_ID;
    uint32_t mSource;
    nsecs_t mDownTime;
    nsecs_t mEventTime;
    int32_t mDisplayId{ADISPLAY_ID_DEFAULT};
    uint32_t mPolicyFlags = DEFAULT_POLICY_FLAGS;
    int32_t mFlags{0};
    int32_t mKeyCode{AKEYCODE_UNKNOWN};
    int32_t mScanCode{0};
    int32_t mMetaState{AMETA_NONE};
};

} // namespace android
Loading