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