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