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

Commit e38fdfae authored by Jeff Brown's avatar Jeff Brown
Browse files

Add a unique input device descriptor.

The purpose of the input device descriptor is to make it possible
to associate persistent settings for each input device, such as the
keyboard layout.

The descriptor is a hash of the information we have about the
device, such as its vendor id, product id, unique id, name,
or location.

Bug: 6110399
Change-Id: Idb80f946819b3f0dbf4e661bb0a753dbc2b60981
parent dc0dbbd4
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -39,12 +39,9 @@ import android.os.ServiceManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import android.view.Display;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyCharacterMap;
import android.view.WindowManagerPolicy;
import android.view.KeyCharacterMap.UnavailableException;

import java.util.ArrayList;
+18 −2
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import java.util.List;
public final class InputDevice implements Parcelable {
    private int mId;
    private String mName;
    private String mDescriptor;
    private int mSources;
    private int mKeyboardType;
    private String mKeyCharacterMapFile;
@@ -334,12 +335,24 @@ public final class InputDevice implements Parcelable {
     * An input device descriptor uniquely identifies an input device.  Its value
     * is intended to be persistent across system restarts, and should not change even
     * if the input device is disconnected, reconnected or reconfigured at any time.
     * </p><p>
     * It is possible for there to be multiple {@link InputDevice} instances that have the
     * same input device descriptor.  This might happen in situations where a single
     * human input device registers multiple {@link InputDevice} instances (HID collections)
     * that describe separate features of the device, such as a keyboard that also
     * has a trackpad.  Alternately, it may be that the input devices are simply
     * indistinguishable, such as two keyboards made by the same manufacturer.
     * </p><p>
     * The input device descriptor returned by {@link #getDescriptor} should only bt
     * used when an application needs to remember settings associated with a particular
     * input device.  For all other purposes when referring to a logical
     * {@link InputDevice} instance at runtime use the id returned by {@link #getId()}.
     * </p>
     *
     * @return The input device descriptor.
     */
    public String getDescriptor() {
        return "PLACEHOLDER"; // TODO: implement for real
        return mDescriptor;
    }

    /**
@@ -548,6 +561,7 @@ public final class InputDevice implements Parcelable {
    private void readFromParcel(Parcel in) {
        mId = in.readInt();
        mName = in.readString();
        mDescriptor = in.readString();
        mSources = in.readInt();
        mKeyboardType = in.readInt();
        mKeyCharacterMapFile = in.readString();
@@ -566,6 +580,7 @@ public final class InputDevice implements Parcelable {
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mId);
        out.writeString(mName);
        out.writeString(mDescriptor);
        out.writeInt(mSources);
        out.writeInt(mKeyboardType);
        out.writeString(mKeyCharacterMapFile);
@@ -592,6 +607,7 @@ public final class InputDevice implements Parcelable {
    public String toString() {
        StringBuilder description = new StringBuilder();
        description.append("Input Device ").append(mId).append(": ").append(mName).append("\n");
        description.append("  Descriptor: ").append(mDescriptor).append("\n");

        description.append("  Keyboard Type: ");
        switch (mKeyboardType) {
+28 −18
Original line number Diff line number Diff line
@@ -811,6 +811,31 @@ private:
    VelocityTracker mVelocityTracker;
};

/*
 * Identifies a device.
 */
struct InputDeviceIdentifier {
    inline InputDeviceIdentifier() :
            bus(0), vendor(0), product(0), version(0) {
    }

    // Information provided by the kernel.
    String8 name;
    String8 location;
    String8 uniqueId;
    uint16_t bus;
    uint16_t vendor;
    uint16_t product;
    uint16_t version;

    // A composite input device descriptor string that uniquely identifies the device
    // even across reboots or reconnections.  The value of this field is used by
    // upper layers of the input system to associate settings with individual devices.
    // It is hashed from whatever kernel provided information is available.
    // Ideally, the way this value is computed should not change between Android releases
    // because that would invalidate persistent settings that rely on it.
    String8 descriptor;
};

/*
 * Describes the characteristics and capabilities of an input device.
@@ -830,10 +855,11 @@ public:
        float fuzz;
    };

    void initialize(int32_t id, const String8& name);
    void initialize(int32_t id, const String8& name, const String8& descriptor);

    inline int32_t getId() const { return mId; }
    inline const String8 getName() const { return mName; }
    inline const String8 getDescriptor() const { return mDescriptor; }
    inline uint32_t getSources() const { return mSources; }

    const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
@@ -856,6 +882,7 @@ public:
private:
    int32_t mId;
    String8 mName;
    String8 mDescriptor;
    uint32_t mSources;
    int32_t mKeyboardType;
    String8 mKeyCharacterMapFile;
@@ -863,23 +890,6 @@ private:
    Vector<MotionRange> mMotionRanges;
};

/*
 * Identifies a device.
 */
struct InputDeviceIdentifier {
    inline InputDeviceIdentifier() :
            bus(0), vendor(0), product(0), version(0) {
    }

    String8 name;
    String8 location;
    String8 uniqueId;
    uint16_t bus;
    uint16_t vendor;
    uint16_t product;
    uint16_t version;
};

/* Types of input device configuration files. */
enum InputDeviceConfigurationFileType {
    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0,     /* .idc file */
+6 −3
Original line number Diff line number Diff line
@@ -1226,21 +1226,24 @@ void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
// --- InputDeviceInfo ---

InputDeviceInfo::InputDeviceInfo() {
    initialize(-1, String8("uninitialized device info"));
    initialize(-1, String8("uninitialized device info"), String8("unknown"));
}

InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
        mId(other.mId), mName(other.mName), mSources(other.mSources),
        mId(other.mId), mName(other.mName), mDescriptor(other.mDescriptor),
        mSources(other.mSources),
        mKeyboardType(other.mKeyboardType),
        mKeyCharacterMapFile(other.mKeyCharacterMapFile),
        mMotionRanges(other.mMotionRanges) {
}

InputDeviceInfo::~InputDeviceInfo() {
}

void InputDeviceInfo::initialize(int32_t id, const String8& name) {
void InputDeviceInfo::initialize(int32_t id, const String8& name, const String8& descriptor) {
    mId = id;
    mName = name;
    mDescriptor = descriptor;
    mSources = 0;
    mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
    mMotionRanges.clear();
+53 −14
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#include <androidfw/KeyCharacterMap.h>
#include <androidfw/VirtualKeyMap.h>

#include <sha1.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
@@ -78,6 +79,20 @@ static inline const char* toString(bool value) {
    return value ? "true" : "false";
}

static String8 sha1(const String8& in) {
    SHA1_CTX ctx;
    SHA1Init(&ctx);
    SHA1Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
    u_char digest[SHA1_DIGEST_LENGTH];
    SHA1Final(digest, &ctx);

    String8 out;
    for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) {
        out.appendFormat("%02x", digest[i]);
    }
    return out;
}

// --- Global Functions ---

uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
@@ -209,11 +224,11 @@ EventHub::~EventHub(void) {
    release_wake_lock(WAKE_LOCK_ID);
}

String8 EventHub::getDeviceName(int32_t deviceId) const {
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
    AutoMutex _l(mLock);
    Device* device = getDeviceLocked(deviceId);
    if (device == NULL) return String8();
    return device->identifier.name;
    if (device == NULL) return InputDeviceIdentifier();
    return device->identifier;
}

uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
@@ -893,6 +908,30 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
        identifier.uniqueId.setTo(buffer);
    }

    // Compute a device descriptor that uniquely identifies the device.
    // The descriptor is assumed to be a stable identifier.  Its value should not
    // change between reboots, reconnections, firmware updates or new releases of Android.
    // Ideally, we also want the descriptor to be short and relatively opaque.
    String8 rawDescriptor;
    rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product);
    if (!identifier.uniqueId.isEmpty()) {
        rawDescriptor.append("uniqueId:");
        rawDescriptor.append(identifier.uniqueId);
    } if (identifier.vendor == 0 && identifier.product == 0) {
        // If we don't know the vendor and product id, then the device is probably
        // built-in so we need to rely on other information to uniquely identify
        // the input device.  Usually we try to avoid relying on the device name or
        // location but for built-in input device, they are unlikely to ever change.
        if (!identifier.name.isEmpty()) {
            rawDescriptor.append("name:");
            rawDescriptor.append(identifier.name);
        } else if (!identifier.location.isEmpty()) {
            rawDescriptor.append("location:");
            rawDescriptor.append(identifier.location);
        }
    }
    identifier.descriptor = sha1(rawDescriptor);

    // Make file descriptor non-blocking for use with poll().
    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
        ALOGE("Error %d making device file descriptor non-blocking.", errno);
@@ -904,19 +943,18 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
    int32_t deviceId = mNextDeviceId++;
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);

#if 0
    ALOGI("add device %d: %s\n", deviceId, devicePath);
    ALOGI("  bus:       %04x\n"
    ALOGV("add device %d: %s\n", deviceId, devicePath);
    ALOGV("  bus:        %04x\n"
         "  vendor      %04x\n"
         "  product     %04x\n"
         "  version     %04x\n",
        identifier.bus, identifier.vendor, identifier.product, identifier.version);
    ALOGI("  name:      \"%s\"\n", identifier.name.string());
    ALOGI("  location:  \"%s\"\n", identifier.location.string());
    ALOGI("  unique id: \"%s\"\n", identifier.uniqueId.string());
    ALOGI("  driver:    v%d.%d.%d\n",
    ALOGV("  name:       \"%s\"\n", identifier.name.string());
    ALOGV("  location:   \"%s\"\n", identifier.location.string());
    ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.string());
    ALOGV("  descriptor: \"%s\" (%s)\n", identifier.descriptor.string(), rawDescriptor.string());
    ALOGV("  driver:     v%d.%d.%d\n",
        driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
#endif

    // Load the configuration file for the device.
    loadConfigurationLocked(device);
@@ -1303,6 +1341,7 @@ void EventHub::dump(String8& dump) {
            }
            dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
            dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
            dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
            dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
            dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
            dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
Loading