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.server.input; 18 19 import android.text.TextUtils; 20 import android.util.Slog; 21 import android.util.Xml; 22 23 import com.android.internal.annotations.VisibleForTesting; 24 import com.android.internal.util.XmlUtils; 25 26 import org.xmlpull.v1.XmlPullParser; 27 28 import java.io.InputStream; 29 import java.io.InputStreamReader; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 import java.util.Map; 34 35 36 class ConfigurationProcessor { 37 private static final String TAG = "ConfigurationProcessor"; 38 processExcludedDeviceNames(InputStream xml)39 static List<String> processExcludedDeviceNames(InputStream xml) throws Exception { 40 List<String> names = new ArrayList<>(); 41 try (InputStreamReader confReader = new InputStreamReader(xml)) { 42 XmlPullParser parser = Xml.newPullParser(); 43 parser.setInput(confReader); 44 XmlUtils.beginDocument(parser, "devices"); 45 while (true) { 46 XmlUtils.nextElement(parser); 47 if (!"device".equals(parser.getName())) { 48 break; 49 } 50 String name = parser.getAttributeValue(null, "name"); 51 if (name != null) { 52 names.add(name); 53 } 54 } 55 } 56 return names; 57 } 58 59 /** 60 * Parse the configuration for input port associations. 61 * 62 * Configuration format: 63 * <code> 64 * <ports> 65 * <port display="0" input="usb-xhci-hcd.0.auto-1.4.3/input0" /> 66 * <port display="1" input="usb-xhci-hcd.0.auto-1.4.2/input0" /> 67 * </ports> 68 * </code> 69 * 70 * In this example, any input device that has physical port of 71 * "usb-xhci-hcd.0.auto-1.4.3/input0" will be associated with a display 72 * that has the physical port "0". If such a display does not exist, the input device 73 * will be disabled and no input events will be dispatched from that input device until a 74 * matching display appears. Likewise, an input device that has port "..1.4.2.." will have 75 * its input events forwarded to a display that has physical port of "1". 76 * 77 * Note: display port must be a numeric value, and this is checked at runtime for validity. 78 * At the same time, it is specified as a string for simplicity. 79 * 80 * Note: do not confuse "display id" with "display port". 81 * The "display port" is the physical port on which the display is connected. This could 82 * be something like HDMI0, HDMI1, etc. For virtual displays, "display port" will be null. 83 * The "display id" is a way to identify a particular display, and is not a stable API. 84 * All displays, including virtual ones, will have a display id. 85 * 86 * Return the pairs of associations. The first item in the pair is the input port, 87 * the second item in the pair is the display port. 88 */ 89 @VisibleForTesting processInputPortAssociations(InputStream xml)90 static Map<String, Integer> processInputPortAssociations(InputStream xml) 91 throws Exception { 92 Map<String, Integer> associations = new HashMap<String, Integer>(); 93 try (InputStreamReader confReader = new InputStreamReader(xml)) { 94 XmlPullParser parser = Xml.newPullParser(); 95 parser.setInput(confReader); 96 XmlUtils.beginDocument(parser, "ports"); 97 98 while (true) { 99 XmlUtils.nextElement(parser); 100 String entryName = parser.getName(); 101 if (!"port".equals(entryName)) { 102 break; 103 } 104 String inputPort = parser.getAttributeValue(null, "input"); 105 String displayPortStr = parser.getAttributeValue(null, "display"); 106 if (TextUtils.isEmpty(inputPort) || TextUtils.isEmpty(displayPortStr)) { 107 // This is likely an error by an OEM during device configuration 108 Slog.wtf(TAG, "Ignoring incomplete entry"); 109 continue; 110 } 111 try { 112 int displayPort = Integer.parseUnsignedInt(displayPortStr); 113 associations.put(inputPort, displayPort); 114 } catch (NumberFormatException e) { 115 Slog.wtf(TAG, "Display port should be an integer"); 116 } 117 } 118 } 119 return associations; 120 } 121 } 122