1 /* 2 * Copyright (C) 2018 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 20 import android.app.Instrumentation; 21 import android.util.Log; 22 23 import androidx.annotation.GuardedBy; 24 25 import org.json.JSONArray; 26 import org.json.JSONException; 27 import org.json.JSONObject; 28 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * Represents a virtual HID device registered through /dev/uhid. 35 */ 36 public final class HidDevice extends VirtualInputDevice { 37 private static final String TAG = "HidDevice"; 38 // hid executable expects "-" argument to read from stdin instead of a file 39 private static final String HID_COMMAND = "hid -"; 40 41 @GuardedBy("mLock") 42 private List<HidResultData> mResults = new ArrayList<HidResultData>(); 43 44 @Override getShellCommand()45 protected String getShellCommand() { 46 return HID_COMMAND; 47 } 48 49 @Override readResults()50 protected void readResults() { 51 try { 52 mReader.beginObject(); 53 HidResultData result = new HidResultData(); 54 while (mReader.hasNext()) { 55 String fieldName = mReader.nextName(); 56 if (fieldName.equals("eventId")) { 57 result.eventId = Byte.decode(mReader.nextString()); 58 } 59 if (fieldName.equals("deviceId")) { 60 result.deviceId = Integer.decode(mReader.nextString()); 61 } 62 if (fieldName.equals("reportType")) { 63 result.reportType = Byte.decode(mReader.nextString()); 64 } 65 if (fieldName.equals("reportData")) { 66 result.reportData = readData(); 67 } 68 } 69 mReader.endObject(); 70 addResult(result); 71 } catch (IOException ex) { 72 Log.w(TAG, "Exiting JSON Result reader. " + ex); 73 } 74 } 75 HidDevice(Instrumentation instrumentation, int id, int vendorId, int productId, int sources, String registerCommand)76 public HidDevice(Instrumentation instrumentation, int id, 77 int vendorId, int productId, int sources, String registerCommand) { 78 super(instrumentation, id, vendorId, productId, sources, registerCommand); 79 } 80 81 /** 82 * Get hid command return results as list of HidResultData 83 * 84 * @return List of HidResultData results 85 */ getResults(int deviceId, byte eventId)86 public synchronized List<HidResultData> getResults(int deviceId, byte eventId) 87 throws IOException { 88 List<HidResultData> results = new ArrayList<HidResultData>(); 89 synchronized (mLock) { 90 for (HidResultData result : mResults) { 91 if (deviceId == result.deviceId && eventId == result.eventId) { 92 results.add(result); 93 } 94 } 95 } 96 return results; 97 } 98 99 /** 100 * Add hid command returned HidResultData result 101 * 102 * @param result HidResultData result 103 */ addResult(HidResultData result)104 public synchronized void addResult(HidResultData result) { 105 synchronized (mLock) { 106 if (mId == result.deviceId && mResults != null) { 107 mResults.add(result); 108 } 109 } 110 } 111 112 /** 113 * Send a HID report to the device. The report should follow the report descriptor 114 * that was specified during device registration. 115 * An example report: 116 * String report = "[0x01, 0x00, 0x00, 0x02]"; 117 * 118 * @param report The report to send (a JSON-formatted array of hex) 119 */ sendHidReport(String report)120 public void sendHidReport(String report) { 121 JSONObject json = new JSONObject(); 122 try { 123 json.put("command", "report"); 124 json.put("id", mId); 125 json.put("report", new JSONArray(report)); 126 } catch (JSONException e) { 127 throw new RuntimeException("Could not process HID report: " + report); 128 } 129 writeCommands(json.toString().getBytes()); 130 } 131 132 } 133