1 /*
2  * Copyright (C) 2015 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 android.hardware.usb;
18 
19 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED;
20 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED;
21 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
22 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
23 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
24 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
25 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
26 import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY;
27 import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY;
28 import static android.hardware.usb.UsbPortStatus.MODE_DFP;
29 import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
30 import static android.hardware.usb.UsbPortStatus.MODE_NONE;
31 import static android.hardware.usb.UsbPortStatus.MODE_UFP;
32 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
33 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
34 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
35 
36 import android.Manifest;
37 import android.annotation.NonNull;
38 import android.annotation.Nullable;
39 import android.annotation.RequiresPermission;
40 import android.annotation.SystemApi;
41 import android.hardware.usb.V1_0.Constants;
42 
43 import com.android.internal.util.Preconditions;
44 
45 /**
46  * Represents a physical USB port and describes its characteristics.
47  *
48  * @hide
49  */
50 @SystemApi
51 public final class UsbPort {
52     private final String mId;
53     private final int mSupportedModes;
54     private final UsbManager mUsbManager;
55     private final int mSupportedContaminantProtectionModes;
56     private final boolean mSupportsEnableContaminantPresenceProtection;
57     private final boolean mSupportsEnableContaminantPresenceDetection;
58 
59     private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
60     /**
61      * Points to the first power role in the IUsb HAL.
62      */
63     private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
64 
65     /** @hide */
UsbPort(@onNull UsbManager usbManager, @NonNull String id, int supportedModes, int supportedContaminantProtectionModes, boolean supportsEnableContaminantPresenceProtection, boolean supportsEnableContaminantPresenceDetection)66     public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
67             int supportedContaminantProtectionModes,
68             boolean supportsEnableContaminantPresenceProtection,
69             boolean supportsEnableContaminantPresenceDetection) {
70         Preconditions.checkNotNull(id);
71         Preconditions.checkFlagsArgument(supportedModes,
72                 MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY);
73 
74         mUsbManager = usbManager;
75         mId = id;
76         mSupportedModes = supportedModes;
77         mSupportedContaminantProtectionModes = supportedContaminantProtectionModes;
78         mSupportsEnableContaminantPresenceProtection =
79                 supportsEnableContaminantPresenceProtection;
80         mSupportsEnableContaminantPresenceDetection =
81                 supportsEnableContaminantPresenceDetection;
82     }
83 
84     /**
85      * Gets the unique id of the port.
86      *
87      * @return The unique id of the port; not intended for display.
88      *
89      * @hide
90      */
getId()91     public String getId() {
92         return mId;
93     }
94 
95     /**
96      * Gets the supported modes of the port.
97      * <p>
98      * The actual mode of the port may vary depending on what is plugged into it.
99      * </p>
100      *
101      * @return The supported modes: one of {@link UsbPortStatus#MODE_DFP},
102      * {@link UsbPortStatus#MODE_UFP}, or {@link UsbPortStatus#MODE_DUAL}.
103      *
104      * @hide
105      */
getSupportedModes()106     public int getSupportedModes() {
107         return mSupportedModes;
108     }
109 
110    /**
111      * Gets the supported port proctection modes when the port is contaminated.
112      * <p>
113      * The actual mode of the port is decided by the hardware
114      * </p>
115      *
116      * @hide
117      */
getSupportedContaminantProtectionModes()118     public int getSupportedContaminantProtectionModes() {
119         return mSupportedContaminantProtectionModes;
120     }
121 
122    /**
123      * Tells if UsbService can enable/disable contaminant presence protection.
124      *
125      * @hide
126      */
supportsEnableContaminantPresenceProtection()127     public boolean supportsEnableContaminantPresenceProtection() {
128         return mSupportsEnableContaminantPresenceProtection;
129     }
130 
131    /**
132      * Tells if UsbService can enable/disable contaminant presence detection.
133      *
134      * @hide
135      */
supportsEnableContaminantPresenceDetection()136     public boolean supportsEnableContaminantPresenceDetection() {
137         return mSupportsEnableContaminantPresenceDetection;
138     }
139 
140     /**
141      * Gets the status of this USB port.
142      *
143      * @return The status of the this port, or {@code null} if port is unknown.
144      */
145     @RequiresPermission(Manifest.permission.MANAGE_USB)
getStatus()146     public @Nullable UsbPortStatus getStatus() {
147         return mUsbManager.getPortStatus(this);
148     }
149 
150     /**
151      * Sets the desired role combination of the port.
152      * <p>
153      * The supported role combinations depend on what is connected to the port and may be
154      * determined by consulting
155      * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
156      * </p><p>
157      * Note: This function is asynchronous and may fail silently without applying
158      * the requested changes.  If this function does cause a status change to occur then
159      * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent.
160      * </p>
161      *
162      * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} or
163      *                  {@link UsbPortStatus#POWER_ROLE_SINK}, or
164      *                  {@link UsbPortStatus#POWER_ROLE_NONE} if no power role.
165      * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} or
166      *                 {@link UsbPortStatus#DATA_ROLE_DEVICE}, or
167      *                 {@link UsbPortStatus#DATA_ROLE_NONE} if no data role.
168      */
169     @RequiresPermission(Manifest.permission.MANAGE_USB)
setRoles(@sbPortStatus.UsbPowerRole int powerRole, @UsbPortStatus.UsbDataRole int dataRole)170     public void setRoles(@UsbPortStatus.UsbPowerRole int powerRole,
171             @UsbPortStatus.UsbDataRole int dataRole) {
172         UsbPort.checkRoles(powerRole, dataRole);
173 
174         mUsbManager.setPortRoles(this, powerRole, dataRole);
175     }
176 
177     /**
178      * @hide
179      **/
enableContaminantDetection(boolean enable)180     public void enableContaminantDetection(boolean enable) {
181         mUsbManager.enableContaminantDetection(this, enable);
182     }
183     /**
184      * Combines one power and one data role together into a unique value with
185      * exactly one bit set.  This can be used to efficiently determine whether
186      * a combination of roles is supported by testing whether that bit is present
187      * in a bit-field.
188      *
189      * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE}
190      *                  or {@link UsbPortStatus#POWER_ROLE_SINK}, or 0 if no power role.
191      * @param dataRole  The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST}
192      *                  or {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 0 if no data role.
193      * @hide
194      */
combineRolesAsBit(int powerRole, int dataRole)195     public static int combineRolesAsBit(int powerRole, int dataRole) {
196         checkRoles(powerRole, dataRole);
197         final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole;
198         return 1 << index;
199     }
200 
201     /** @hide */
modeToString(int mode)202     public static String modeToString(int mode) {
203         StringBuilder modeString = new StringBuilder();
204         if (mode == MODE_NONE) {
205             return "none";
206         }
207 
208         if ((mode & MODE_DUAL) == MODE_DUAL) {
209             modeString.append("dual, ");
210         } else {
211             if ((mode & MODE_DFP) == MODE_DFP) {
212                 modeString.append("dfp, ");
213             } else if ((mode & MODE_UFP) == MODE_UFP) {
214                 modeString.append("ufp, ");
215             }
216         }
217         if ((mode & MODE_AUDIO_ACCESSORY) == MODE_AUDIO_ACCESSORY) {
218             modeString.append("audio_acc, ");
219         }
220         if ((mode & MODE_DEBUG_ACCESSORY) == MODE_DEBUG_ACCESSORY) {
221             modeString.append("debug_acc, ");
222         }
223 
224         if (modeString.length() == 0) {
225             return Integer.toString(mode);
226         }
227         return modeString.substring(0, modeString.length() - 2);
228     }
229 
230     /** @hide */
powerRoleToString(int role)231     public static String powerRoleToString(int role) {
232         switch (role) {
233             case POWER_ROLE_NONE:
234                 return "no-power";
235             case POWER_ROLE_SOURCE:
236                 return "source";
237             case POWER_ROLE_SINK:
238                 return "sink";
239             default:
240                 return Integer.toString(role);
241         }
242     }
243 
244     /** @hide */
dataRoleToString(int role)245     public static String dataRoleToString(int role) {
246         switch (role) {
247             case DATA_ROLE_NONE:
248                 return "no-data";
249             case DATA_ROLE_HOST:
250                 return "host";
251             case DATA_ROLE_DEVICE:
252                 return "device";
253             default:
254                 return Integer.toString(role);
255         }
256     }
257 
258     /** @hide */
contaminantPresenceStatusToString(int contaminantPresenceStatus)259     public static String contaminantPresenceStatusToString(int contaminantPresenceStatus) {
260         switch (contaminantPresenceStatus) {
261             case CONTAMINANT_DETECTION_NOT_SUPPORTED:
262                 return "not-supported";
263             case CONTAMINANT_DETECTION_DISABLED:
264                 return "disabled";
265             case CONTAMINANT_DETECTION_DETECTED:
266                 return "detected";
267             case CONTAMINANT_DETECTION_NOT_DETECTED:
268                 return "not detected";
269             default:
270                 return Integer.toString(contaminantPresenceStatus);
271         }
272     }
273 
274     /** @hide */
roleCombinationsToString(int combo)275     public static String roleCombinationsToString(int combo) {
276         StringBuilder result = new StringBuilder();
277         result.append("[");
278 
279         boolean first = true;
280         while (combo != 0) {
281             final int index = Integer.numberOfTrailingZeros(combo);
282             combo &= ~(1 << index);
283             final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET);
284             final int dataRole = index % NUM_DATA_ROLES;
285             if (first) {
286                 first = false;
287             } else {
288                 result.append(", ");
289             }
290             result.append(powerRoleToString(powerRole));
291             result.append(':');
292             result.append(dataRoleToString(dataRole));
293         }
294 
295         result.append("]");
296         return result.toString();
297     }
298 
299     /** @hide */
checkMode(int powerRole)300     public static void checkMode(int powerRole) {
301         Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
302                 Constants.PortMode.NUM_MODES - 1, "portMode");
303     }
304 
305     /** @hide */
checkPowerRole(int dataRole)306     public static void checkPowerRole(int dataRole) {
307         Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE,
308                 Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole");
309     }
310 
311     /** @hide */
checkDataRole(int mode)312     public static void checkDataRole(int mode) {
313         Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE,
314                 Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole");
315     }
316 
317     /** @hide */
checkRoles(int powerRole, int dataRole)318     public static void checkRoles(int powerRole, int dataRole) {
319         Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK,
320                 "powerRole");
321         Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole");
322     }
323 
324     /** @hide */
isModeSupported(int mode)325     public boolean isModeSupported(int mode) {
326         if ((mSupportedModes & mode) == mode) return true;
327         return false;
328     }
329 
330     @NonNull
331     @Override
toString()332     public String toString() {
333         return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes)
334                 + "supportedContaminantProtectionModes=" + mSupportedContaminantProtectionModes
335                 + "supportsEnableContaminantPresenceProtection="
336                 + mSupportsEnableContaminantPresenceProtection
337                 + "supportsEnableContaminantPresenceDetection="
338                 + mSupportsEnableContaminantPresenceDetection;
339     }
340 }
341