1 /* <lambda>null2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.input 18 19 import org.json.JSONArray 20 21 /** 22 * Represents a single uinput configuration item. 23 * 24 * @property type The name of a uinput ioctl command (e.g., "UI_SET_EVBIT", "UI_SET_KEYBIT"). 25 * @property data A list of values associated with the configuration command. The type of values in 26 * the list depends on the specific ioctl: 27 * - UI_SET_EVBIT: Event types (e.g., "EV_KEY", "EV_ABS"). 28 * - UI_SET_KEYBIT: Key codes (e.g., "KEY_A", "KEY_ENTER"). 29 * - UI_SET_ABSBIT: Absolute axis codes (e.g., "ABS_MT_POSITION_X", "ABS_MT_SLOT"). 30 * - UI_SET_PROPBIT: Property bits (e.g., "INPUT_PROP_POINTER"). 31 * - ... (other ioctls have their own specific value types) 32 * Important! All devices need a UI_SET_EVBIT item specifying the event types they register. If this 33 * is not present, the UI_SET_ABSBIT and other ioctls will silently fail. 34 */ 35 data class ConfigurationItem(val type: String, val data: List<Any>) { 36 init { 37 // Ensure all elements are of the same type 38 if (data.isEmpty()) { 39 throw IllegalArgumentException("Provided list is empty") 40 } // Handle empty lists 41 val firstElementType = data[0]::class 42 if (!data.all { it::class == firstElementType }) { 43 throw IllegalArgumentException("Elements must have the same type $firstElementType") 44 } 45 } 46 override fun toString(): String = """{"type": "$type", "data": ${JSONArray(data)}}""" 47 } 48 49 /** 50 * Represents information about an absolute axis for uinput devices. 51 * 52 * @property value The current value of the axis. 53 * @property minimum The minimum value the axis can report. 54 * @property maximum The maximum value the axis can report. 55 * @property fuzz The fuzz value for the axis (used for filtering out small changes). 56 * @property flat The flat value for the axis (used to determine whether the axis is "still" around 0). 57 * @property resolution The resolution of the axis (units per mm or per radian). 58 */ 59 data class AbsInfo( 60 val value: Int, 61 val minimum: Int, 62 val maximum: Int, 63 val fuzz: Int, 64 val flat: Int, 65 val resolution: Int, 66 ) { toStringnull67 override fun toString(): String = 68 """{"value": $value, 69 "minimum": $minimum, 70 "maximum": $maximum, 71 "fuzz": $fuzz, 72 "flat": $flat, 73 "resolution": $resolution 74 }""".trimMargin() 75 } 76 77 /** 78 * Represents a uinput device registration command. 79 * 80 * @property id A unique identifier for the device. 81 * @property name The name of the device. 82 * @property vid The vendor ID of the device manufacturer. 83 * @property pid The product ID of the device. 84 * @property bus The bus type the device is connected to (e.g., "usb", "bluetooth"). 85 * @property port The specific port on the bus (e.g., "usb:1", "bluetooth:hci0:1"). 86 * @property configuration A list of [ConfigurationItem] objects specifying how to configure the 87 * device, e.g. what axes does it have, which buttons it reports. 88 * @property absInfo A map of absolute axis codes (as strings) to their corresponding [AbsInfo]s. 89 * @property ffEffectsMax (Optional) The maximum number of force feedback effects. 90 91 * See frameworks/base/cmds/uinput/README.md for more details on how to specify this and examples. 92 */ 93 data class UinputRegisterCommand ( 94 val id: Int, 95 val name: String, 96 val vid: Int, 97 val pid: Int, 98 val bus: String, 99 val port: String, 100 val configuration: List<ConfigurationItem>, 101 val absInfo: Map<String, AbsInfo>, 102 val ffEffectsMax: Int? = null, 103 ) : RegisterCommand() { 104 /** 105 * Convert to a json-format string. 106 */ 107 override fun toString(): String { 108 val configurationString = configuration.joinToString(separator = ",") 109 val ffEffects = if (ffEffectsMax == null) "" else ",\n\"ff_effects_max\" : $ffEffectsMax" 110 val absInfoString = if (absInfo.isEmpty()) { 111 "" 112 } else { 113 val infos = absInfo.map { (key, value) -> 114 """{"code": "$key", "info": $value}""" 115 }.joinToString(separator = ",") 116 ",\n\"abs_info\": [$infos]" 117 } 118 return """{"id": $id, 119 "command": "register", 120 "name": "$name", 121 "vid": $vid, 122 "pid": $pid, 123 "bus": "$bus", 124 "port": "$port", 125 "configuration": [$configurationString] 126 $ffEffects 127 $absInfoString 128 }""".trimMargin() 129 } 130 } 131