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.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
20 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
21 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
22 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
23 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED;
24 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED;
25 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
26 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
27 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
28 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
29 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
30 import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY;
31 import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY;
32 import static android.hardware.usb.UsbPortStatus.MODE_DFP;
33 import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
34 import static android.hardware.usb.UsbPortStatus.MODE_NONE;
35 import static android.hardware.usb.UsbPortStatus.MODE_UFP;
36 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_DISCONNECTED;
37 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
38 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_CONNECTED;
39 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
40 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
41 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
42 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
43 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_ENABLED;
44 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
45 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
46 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
47 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
48 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
49 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK_HOST_MODE;
50 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK_DEVICE_MODE;
51 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY;
52 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2;
53 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP;
54 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER;
55 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED;
56 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES;
57 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL;
58 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION;
59 import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO;
60 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
61 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
62 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED;
63 import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_ENABLED;
64 
65 import android.Manifest;
66 import android.annotation.CallbackExecutor;
67 import android.annotation.CheckResult;
68 import android.annotation.FlaggedApi;
69 import android.annotation.IntDef;
70 import android.annotation.NonNull;
71 import android.annotation.Nullable;
72 import android.annotation.RequiresPermission;
73 import android.annotation.SystemApi;
74 import android.annotation.TestApi;
75 import android.hardware.usb.flags.Flags;
76 import android.hardware.usb.UsbOperationInternal;
77 import android.hardware.usb.V1_0.Constants;
78 import android.os.Binder;
79 import android.util.Log;
80 
81 import com.android.internal.util.Preconditions;
82 
83 import java.lang.annotation.Retention;
84 import java.lang.annotation.RetentionPolicy;
85 import java.util.Objects;
86 import java.util.concurrent.atomic.AtomicInteger;
87 import java.util.concurrent.Executor;
88 import java.util.function.Consumer;
89 
90 /**
91  * Represents a physical USB port and describes its characteristics.
92  *
93  * @hide
94  */
95 @SystemApi
96 public final class UsbPort {
97     private static final String TAG = "UsbPort";
98     private final String mId;
99     private final int mSupportedModes;
100     private final UsbManager mUsbManager;
101     private final int mSupportedContaminantProtectionModes;
102     private final boolean mSupportsEnableContaminantPresenceProtection;
103     private final boolean mSupportsEnableContaminantPresenceDetection;
104     private final boolean mSupportsComplianceWarnings;
105     private final @AltModeType int mSupportedAltModes;
106 
107     private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
108     /**
109      * Points to the first power role in the IUsb HAL.
110      */
111     private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
112 
113     /**
114      * Counter for tracking UsbOperation operations.
115      */
116     private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
117 
118     /**
119      * The {@link #enableUsbData} request was successfully completed.
120      */
121     public static final int ENABLE_USB_DATA_SUCCESS = 0;
122 
123     /**
124      * The {@link #enableUsbData} request failed due to internal error.
125      */
126     public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1;
127 
128     /**
129      * The {@link #enableUsbData} request failed as it's not supported.
130      */
131     public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2;
132 
133     /**
134      * The {@link #enableUsbData} request failed as port id mismatched.
135      */
136     public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3;
137 
138     /**
139      * The {@link #enableUsbData} request failed due to other reasons.
140      */
141     public static final int ENABLE_USB_DATA_ERROR_OTHER = 4;
142 
143     /** @hide */
144     @IntDef(prefix = { "ENABLE_USB_DATA_" }, value = {
145             ENABLE_USB_DATA_SUCCESS,
146             ENABLE_USB_DATA_ERROR_INTERNAL,
147             ENABLE_USB_DATA_ERROR_NOT_SUPPORTED,
148             ENABLE_USB_DATA_ERROR_PORT_MISMATCH,
149             ENABLE_USB_DATA_ERROR_OTHER
150     })
151     @Retention(RetentionPolicy.SOURCE)
152     @interface EnableUsbDataStatus{}
153 
154     /**
155      * The {@link #enableLimitPowerTransfer} request was successfully completed.
156      */
157     public static final int ENABLE_LIMIT_POWER_TRANSFER_SUCCESS = 0;
158 
159     /**
160      * The {@link #enableLimitPowerTransfer} request failed due to internal error.
161      */
162     public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1;
163 
164     /**
165      * The {@link #enableLimitPowerTransfer} request failed as it's not supported.
166      */
167     public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2;
168 
169     /**
170      * The {@link #enableLimitPowerTransfer} request failed as port id mismatched.
171      */
172     public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH = 3;
173 
174     /**
175      * The {@link #enableLimitPowerTransfer} request failed due to other reasons.
176      */
177     public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER = 4;
178 
179     /** @hide */
180     @IntDef(prefix = { "ENABLE_LIMIT_POWER_TRANSFER_" }, value = {
181             ENABLE_LIMIT_POWER_TRANSFER_SUCCESS,
182             ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL,
183             ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED,
184             ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH,
185             ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER
186     })
187     @Retention(RetentionPolicy.SOURCE)
188     @interface EnableLimitPowerTransferStatus{}
189 
190     /**
191      * The {@link #enableUsbDataWhileDocked} request was successfully completed.
192      */
193     public static final int ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS = 0;
194 
195     /**
196      * The {@link #enableUsbDataWhileDocked} request failed due to internal error.
197      */
198     public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL = 1;
199 
200     /**
201      * The {@link #enableUsbDataWhileDocked} request failed as it's not supported.
202      */
203     public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED = 2;
204 
205     /**
206      * The {@link #enableUsbDataWhileDocked} request failed as port id mismatched.
207      */
208     public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH = 3;
209 
210     /**
211      * The {@link #enableUsbDataWhileDocked} request failed as data is still enabled.
212      */
213     public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED = 4;
214 
215     /**
216      * The {@link #enableUsbDataWhileDocked} request failed due to other reasons.
217      */
218     public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER = 5;
219 
220     /**
221      * The {@link #resetUsbPort} request was successfully completed.
222      */
223     public static final int RESET_USB_PORT_SUCCESS = 0;
224 
225     /**
226      * The {@link #resetUsbPort} request failed due to internal error.
227      */
228     public static final int RESET_USB_PORT_ERROR_INTERNAL = 1;
229 
230     /**
231      * The {@link #resetUsbPort} request failed as it's not supported.
232      */
233     public static final int RESET_USB_PORT_ERROR_NOT_SUPPORTED = 2;
234 
235     /**
236      * The {@link #resetUsbPort} request failed as port id mismatched.
237      */
238     public static final int RESET_USB_PORT_ERROR_PORT_MISMATCH = 3;
239 
240     /**
241      * The {@link #resetUsbPort} request failed due to other reasons.
242      */
243     public static final int RESET_USB_PORT_ERROR_OTHER = 4;
244 
245     /** @hide */
246     @IntDef(prefix = { "RESET_USB_PORT_" }, value = {
247             RESET_USB_PORT_SUCCESS,
248             RESET_USB_PORT_ERROR_INTERNAL,
249             RESET_USB_PORT_ERROR_NOT_SUPPORTED,
250             RESET_USB_PORT_ERROR_PORT_MISMATCH,
251             RESET_USB_PORT_ERROR_OTHER
252     })
253     @Retention(RetentionPolicy.SOURCE)
254     @interface ResetUsbPortStatus{}
255 
256     /** @hide */
257     @IntDef(prefix = { "ENABLE_USB_DATA_WHILE_DOCKED_" }, value = {
258             ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS,
259             ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL,
260             ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED,
261             ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH,
262             ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED,
263             ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER
264     })
265     @Retention(RetentionPolicy.SOURCE)
266     @interface EnableUsbDataWhileDockedStatus{}
267 
268     /**
269      * Indicates that the Alt Mode being described is DisplayPort.
270      */
271     public static final int FLAG_ALT_MODE_TYPE_DISPLAYPORT = 1 << 0;
272 
273     /** @hide */
274     @IntDef(prefix = { "FLAG_ALT_MODE_TYPE_" }, flag = true, value = {
275         FLAG_ALT_MODE_TYPE_DISPLAYPORT,
276     })
277     @Retention(RetentionPolicy.SOURCE)
278     public @interface AltModeType {}
279 
280     /** @hide */
UsbPort(@onNull UsbManager usbManager, @NonNull String id, int supportedModes, int supportedContaminantProtectionModes, boolean supportsEnableContaminantPresenceProtection, boolean supportsEnableContaminantPresenceDetection)281     public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
282             int supportedContaminantProtectionModes,
283             boolean supportsEnableContaminantPresenceProtection,
284             boolean supportsEnableContaminantPresenceDetection) {
285         this(usbManager, id, supportedModes, supportedContaminantProtectionModes,
286                 supportsEnableContaminantPresenceProtection,
287                 supportsEnableContaminantPresenceDetection,
288                 false, 0);
289     }
290 
291     /** @hide */
UsbPort(@onNull UsbManager usbManager, @NonNull String id, int supportedModes, int supportedContaminantProtectionModes, boolean supportsEnableContaminantPresenceProtection, boolean supportsEnableContaminantPresenceDetection, boolean supportsComplianceWarnings, int supportedAltModes)292     public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
293             int supportedContaminantProtectionModes,
294             boolean supportsEnableContaminantPresenceProtection,
295             boolean supportsEnableContaminantPresenceDetection,
296             boolean supportsComplianceWarnings,
297             int supportedAltModes) {
298         Objects.requireNonNull(id);
299         Preconditions.checkFlagsArgument(supportedModes,
300                 MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY);
301 
302         mUsbManager = usbManager;
303         mId = id;
304         mSupportedModes = supportedModes;
305         mSupportedContaminantProtectionModes = supportedContaminantProtectionModes;
306         mSupportsEnableContaminantPresenceProtection =
307                 supportsEnableContaminantPresenceProtection;
308         mSupportsEnableContaminantPresenceDetection =
309                 supportsEnableContaminantPresenceDetection;
310         mSupportsComplianceWarnings = supportsComplianceWarnings;
311         mSupportedAltModes = supportedAltModes;
312     }
313 
314     /**
315      * Gets the unique id of the port.
316      *
317      * @return The unique id of the port; not intended for display.
318      *
319      * @hide
320      */
getId()321     public String getId() {
322         return mId;
323     }
324 
325     /**
326      * Gets the supported modes of the port.
327      * <p>
328      * The actual mode of the port may vary depending on what is plugged into it.
329      * </p>
330      *
331      * @return The supported modes: one of {@link UsbPortStatus#MODE_DFP},
332      * {@link UsbPortStatus#MODE_UFP}, or {@link UsbPortStatus#MODE_DUAL}.
333      *
334      * @hide
335      */
getSupportedModes()336     public int getSupportedModes() {
337         return mSupportedModes;
338     }
339 
340    /**
341      * Gets the supported port proctection modes when the port is contaminated.
342      * <p>
343      * The actual mode of the port is decided by the hardware
344      * </p>
345      *
346      * @hide
347      */
getSupportedContaminantProtectionModes()348     public int getSupportedContaminantProtectionModes() {
349         return mSupportedContaminantProtectionModes;
350     }
351 
352    /**
353      * Tells if UsbService can enable/disable contaminant presence protection.
354      *
355      * @hide
356      */
supportsEnableContaminantPresenceProtection()357     public boolean supportsEnableContaminantPresenceProtection() {
358         return mSupportsEnableContaminantPresenceProtection;
359     }
360 
361    /**
362      * Tells if UsbService can enable/disable contaminant presence detection.
363      *
364      * @hide
365      */
supportsEnableContaminantPresenceDetection()366     public boolean supportsEnableContaminantPresenceDetection() {
367         return mSupportsEnableContaminantPresenceDetection;
368     }
369 
370     /**
371      * Gets the status of this USB port.
372      *
373      * @return The status of the this port, or {@code null} if port is unknown.
374      */
375     @RequiresPermission(Manifest.permission.MANAGE_USB)
getStatus()376     public @Nullable UsbPortStatus getStatus() {
377         return mUsbManager.getPortStatus(this);
378     }
379 
380     /**
381      * Returns whether this USB port supports mode change
382      *
383      * @return true if mode change is supported.
384      * @hide
385      */
386     @TestApi
387     @RequiresPermission(Manifest.permission.MANAGE_USB)
388     @FlaggedApi(Flags.FLAG_ENABLE_IS_MODE_CHANGE_SUPPORTED_API)
isModeChangeSupported()389     public boolean isModeChangeSupported() {
390         return mUsbManager.isModeChangeSupported(this);
391     }
392 
393     /**
394      * Queries USB Port to see if the port is capable of identifying
395      * non compliant USB power source/cable/accessory.
396      *
397      * @return true when the UsbPort is capable of identifying
398      *             non compliant USB power
399      *             source/cable/accessory.
400      * @return false otherwise.
401      */
402     @CheckResult
403     @RequiresPermission(Manifest.permission.MANAGE_USB)
supportsComplianceWarnings()404     public boolean supportsComplianceWarnings() {
405         return mSupportsComplianceWarnings;
406     }
407 
408     /**
409      * Returns all Alt Modes supported by the port.
410      *
411      * @hide
412      */
getSupportedAltModesMask()413     public @AltModeType int getSupportedAltModesMask() {
414         return mSupportedAltModes;
415     }
416 
417     /**
418      * Returns whether all Alt Mode types in a given mask are supported
419      * by the port.
420      *
421      * @return true if all given Alt Modes are supported, false otherwise.
422      *
423      */
isAltModeSupported(@ltModeType int typeMask)424     public boolean isAltModeSupported(@AltModeType int typeMask) {
425         return (mSupportedAltModes & typeMask) == typeMask;
426     }
427 
428 
429     /**
430      * Sets the desired role combination of the port.
431      * <p>
432      * The supported role combinations depend on what is connected to the port and may be
433      * determined by consulting
434      * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
435      * </p><p>
436      * Note: This function is asynchronous and may fail silently without applying
437      * the operationed changes.  If this function does cause a status change to occur then
438      * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent.
439      * </p>
440      *
441      * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} or
442      *                  {@link UsbPortStatus#POWER_ROLE_SINK}, or
443      *                  {@link UsbPortStatus#POWER_ROLE_NONE} if no power role.
444      * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} or
445      *                 {@link UsbPortStatus#DATA_ROLE_DEVICE}, or
446      *                 {@link UsbPortStatus#DATA_ROLE_NONE} if no data role.
447      */
448     @RequiresPermission(Manifest.permission.MANAGE_USB)
setRoles(@sbPortStatus.UsbPowerRole int powerRole, @UsbPortStatus.UsbDataRole int dataRole)449     public void setRoles(@UsbPortStatus.UsbPowerRole int powerRole,
450             @UsbPortStatus.UsbDataRole int dataRole) {
451         UsbPort.checkRoles(powerRole, dataRole);
452 
453         mUsbManager.setPortRoles(this, powerRole, dataRole);
454     }
455 
456     /**
457      * Reset Usb data on the port.
458      *
459      * @param executor Executor for the callback.
460      * @param consumer A consumer that consumes the reset result.
461      *                 {@link #RESET_USB_PORT_SUCCESS} when request completes
462      *                 successfully or
463      *                 {@link #RESET_USB_PORT_ERROR_INTERNAL} when request
464      *                 fails due to internal error or
465      *                 {@link RESET_USB_PORT_ERROR_NOT_SUPPORTED} when not
466      *                 supported or
467      *                 {@link RESET_USB_PORT_ERROR_PORT_MISMATCH} when request
468      *                 fails due to port id mismatch or
469      *                 {@link RESET_USB_PORT_ERROR_OTHER} when fails due to
470      *                  other reasons.
471      */
472     @CheckResult
473     @RequiresPermission(Manifest.permission.MANAGE_USB)
resetUsbPort(@onNull @allbackExecutor Executor executor, @NonNull @ResetUsbPortStatus Consumer<Integer> consumer)474     public void resetUsbPort(@NonNull @CallbackExecutor Executor executor,
475             @NonNull @ResetUsbPortStatus Consumer<Integer> consumer) {
476         // UID is added To minimize operationID overlap between two different packages.
477         int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
478         Log.i(TAG, "resetUsbPort opId:" + operationId);
479         UsbOperationInternal opCallback =
480                 new UsbOperationInternal(operationId, mId, executor, consumer);
481         mUsbManager.resetUsbPort(this, operationId, opCallback);
482     }
483 
484     /**
485      * Enables/Disables Usb data on the port.
486      *
487      * @param enable When true enables USB data if disabled.
488      *               When false disables USB data if enabled.
489      * @return       {@link #ENABLE_USB_DATA_SUCCESS} when request completes successfully or
490      *               {@link #ENABLE_USB_DATA_ERROR_INTERNAL} when request fails due to internal
491      *               error or
492      *               {@link ENABLE_USB_DATA_ERROR_NOT_SUPPORTED} when not supported or
493      *               {@link ENABLE_USB_DATA_ERROR_PORT_MISMATCH} when request fails due to port id
494      *               mismatch or
495      *               {@link ENABLE_USB_DATA_ERROR_OTHER} when fails due to other reasons.
496      */
497     @CheckResult
498     @RequiresPermission(Manifest.permission.MANAGE_USB)
enableUsbData(boolean enable)499     public @EnableUsbDataStatus int enableUsbData(boolean enable) {
500         // UID is added To minimize operationID overlap between two different packages.
501         int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
502         Log.i(TAG, "enableUsbData opId:" + operationId
503                 + " callingUid:" + Binder.getCallingUid());
504         UsbOperationInternal opCallback =
505                 new UsbOperationInternal(operationId, mId);
506         if (mUsbManager.enableUsbData(this, enable, operationId, opCallback) == true) {
507             opCallback.waitForOperationComplete();
508         }
509 
510         int result = opCallback.getStatus();
511         switch (result) {
512             case USB_OPERATION_SUCCESS:
513                 return ENABLE_USB_DATA_SUCCESS;
514             case USB_OPERATION_ERROR_INTERNAL:
515                 return ENABLE_USB_DATA_ERROR_INTERNAL;
516             case USB_OPERATION_ERROR_NOT_SUPPORTED:
517                 return ENABLE_USB_DATA_ERROR_NOT_SUPPORTED;
518             case USB_OPERATION_ERROR_PORT_MISMATCH:
519                 return ENABLE_USB_DATA_ERROR_PORT_MISMATCH;
520             default:
521                 return ENABLE_USB_DATA_ERROR_OTHER;
522         }
523     }
524 
525     /**
526      * Enables Usb data when disabled due to {@link UsbPort#DATA_STATUS_DISABLED_DOCK}
527      *
528      * @return {@link #ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS} when request completes successfully or
529      *         {@link #ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL} when request fails due to
530      *         internal error or
531      *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED} when not supported or
532      *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH} when request fails due to
533      *         port id mismatch or
534      *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED} when request fails as data
535      *         is still enabled or
536      *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER} when fails due to other reasons.
537      */
538     @CheckResult
539     @RequiresPermission(Manifest.permission.MANAGE_USB)
enableUsbDataWhileDocked()540     public @EnableUsbDataWhileDockedStatus int enableUsbDataWhileDocked() {
541         // UID is added To minimize operationID overlap between two different packages.
542         int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
543         Log.i(TAG, "enableUsbData opId:" + operationId
544                 + " callingUid:" + Binder.getCallingUid());
545         UsbPortStatus portStatus = getStatus();
546         if (portStatus != null &&
547                 (portStatus.getUsbDataStatus() & DATA_STATUS_DISABLED_DOCK) !=
548                  DATA_STATUS_DISABLED_DOCK) {
549             return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED;
550         }
551 
552         UsbOperationInternal opCallback =
553                 new UsbOperationInternal(operationId, mId);
554         mUsbManager.enableUsbDataWhileDocked(this, operationId, opCallback);
555                 opCallback.waitForOperationComplete();
556         int result = opCallback.getStatus();
557         switch (result) {
558             case USB_OPERATION_SUCCESS:
559                 return ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS;
560             case USB_OPERATION_ERROR_INTERNAL:
561                 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL;
562             case USB_OPERATION_ERROR_NOT_SUPPORTED:
563                 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED;
564             case USB_OPERATION_ERROR_PORT_MISMATCH:
565                 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH;
566             default:
567                 return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER;
568         }
569     }
570 
571     /**
572      * Limits power transfer In and out of the port.
573      * <p>
574      * Disables charging and limits sourcing power(when permitted by the USB spec) until
575      * port disconnect event.
576      * </p>
577      * @param enable limits power transfer when true.
578      * @return {@link #ENABLE_LIMIT_POWER_TRANSFER_SUCCESS} when request completes successfully or
579      *         {@link #ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL} when request fails due to
580      *         internal error or
581      *         {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED} when not supported or
582      *         {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH} when request fails due to
583      *         port id mismatch or
584      *         {@link ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER} when fails due to other reasons.
585      */
586     @CheckResult
587     @RequiresPermission(Manifest.permission.MANAGE_USB)
enableLimitPowerTransfer(boolean enable)588     public @EnableLimitPowerTransferStatus int enableLimitPowerTransfer(boolean enable) {
589         // UID is added To minimize operationID overlap between two different packages.
590         int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
591         Log.i(TAG, "enableLimitPowerTransfer opId:" + operationId
592                 + " callingUid:" + Binder.getCallingUid());
593         UsbOperationInternal opCallback =
594                 new UsbOperationInternal(operationId, mId);
595         mUsbManager.enableLimitPowerTransfer(this, enable, operationId, opCallback);
596         opCallback.waitForOperationComplete();
597         int result = opCallback.getStatus();
598         switch (result) {
599             case USB_OPERATION_SUCCESS:
600                 return ENABLE_LIMIT_POWER_TRANSFER_SUCCESS;
601             case USB_OPERATION_ERROR_INTERNAL:
602                 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL;
603             case USB_OPERATION_ERROR_NOT_SUPPORTED:
604                 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED;
605             case USB_OPERATION_ERROR_PORT_MISMATCH:
606                 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_PORT_MISMATCH;
607             default:
608                 return ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER;
609         }
610     }
611 
612     /**
613      * @hide
614      **/
enableContaminantDetection(boolean enable)615     public void enableContaminantDetection(boolean enable) {
616         mUsbManager.enableContaminantDetection(this, enable);
617     }
618     /**
619      * Combines one power and one data role together into a unique value with
620      * exactly one bit set.  This can be used to efficiently determine whether
621      * a combination of roles is supported by testing whether that bit is present
622      * in a bit-field.
623      *
624      * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE}
625      *                  or {@link UsbPortStatus#POWER_ROLE_SINK}, or 0 if no power role.
626      * @param dataRole  The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST}
627      *                  or {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 0 if no data role.
628      * @hide
629      */
combineRolesAsBit(int powerRole, int dataRole)630     public static int combineRolesAsBit(int powerRole, int dataRole) {
631         checkRoles(powerRole, dataRole);
632         final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole;
633         return 1 << index;
634     }
635 
636     /** @hide */
modeToString(int mode)637     public static String modeToString(int mode) {
638         StringBuilder modeString = new StringBuilder();
639         if (mode == MODE_NONE) {
640             return "none";
641         }
642 
643         if ((mode & MODE_DUAL) == MODE_DUAL) {
644             modeString.append("dual, ");
645         } else {
646             if ((mode & MODE_DFP) == MODE_DFP) {
647                 modeString.append("dfp, ");
648             } else if ((mode & MODE_UFP) == MODE_UFP) {
649                 modeString.append("ufp, ");
650             }
651         }
652         if ((mode & MODE_AUDIO_ACCESSORY) == MODE_AUDIO_ACCESSORY) {
653             modeString.append("audio_acc, ");
654         }
655         if ((mode & MODE_DEBUG_ACCESSORY) == MODE_DEBUG_ACCESSORY) {
656             modeString.append("debug_acc, ");
657         }
658 
659         if (modeString.length() == 0) {
660             return Integer.toString(mode);
661         }
662         return modeString.substring(0, modeString.length() - 2);
663     }
664 
665     /** @hide */
powerRoleToString(int role)666     public static String powerRoleToString(int role) {
667         switch (role) {
668             case POWER_ROLE_NONE:
669                 return "no-power";
670             case POWER_ROLE_SOURCE:
671                 return "source";
672             case POWER_ROLE_SINK:
673                 return "sink";
674             default:
675                 return Integer.toString(role);
676         }
677     }
678 
679     /** @hide */
dataRoleToString(int role)680     public static String dataRoleToString(int role) {
681         switch (role) {
682             case DATA_ROLE_NONE:
683                 return "no-data";
684             case DATA_ROLE_HOST:
685                 return "host";
686             case DATA_ROLE_DEVICE:
687                 return "device";
688             default:
689                 return Integer.toString(role);
690         }
691     }
692 
693     /** @hide */
contaminantPresenceStatusToString(int contaminantPresenceStatus)694     public static String contaminantPresenceStatusToString(int contaminantPresenceStatus) {
695         switch (contaminantPresenceStatus) {
696             case CONTAMINANT_DETECTION_NOT_SUPPORTED:
697                 return "not-supported";
698             case CONTAMINANT_DETECTION_DISABLED:
699                 return "disabled";
700             case CONTAMINANT_DETECTION_DETECTED:
701                 return "detected";
702             case CONTAMINANT_DETECTION_NOT_DETECTED:
703                 return "not detected";
704             default:
705                 return Integer.toString(contaminantPresenceStatus);
706         }
707     }
708 
709     /** @hide */
usbDataStatusToString(int usbDataStatus)710     public static String usbDataStatusToString(int usbDataStatus) {
711         StringBuilder statusString = new StringBuilder();
712 
713         if (usbDataStatus == DATA_STATUS_UNKNOWN) {
714             return "unknown";
715         }
716 
717         if ((usbDataStatus & DATA_STATUS_ENABLED) == DATA_STATUS_ENABLED) {
718             return "enabled";
719         }
720 
721         if ((usbDataStatus & DATA_STATUS_DISABLED_OVERHEAT) == DATA_STATUS_DISABLED_OVERHEAT) {
722             statusString.append("disabled-overheat, ");
723         }
724 
725         if ((usbDataStatus & DATA_STATUS_DISABLED_CONTAMINANT)
726                 == DATA_STATUS_DISABLED_CONTAMINANT) {
727             statusString.append("disabled-contaminant, ");
728         }
729 
730         if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK) == DATA_STATUS_DISABLED_DOCK) {
731             statusString.append("disabled-dock, ");
732         }
733 
734         if ((usbDataStatus & DATA_STATUS_DISABLED_FORCE) == DATA_STATUS_DISABLED_FORCE) {
735             statusString.append("disabled-force, ");
736         }
737 
738         if ((usbDataStatus & DATA_STATUS_DISABLED_DEBUG) == DATA_STATUS_DISABLED_DEBUG) {
739             statusString.append("disabled-debug, ");
740         }
741 
742         if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK_HOST_MODE) ==
743             DATA_STATUS_DISABLED_DOCK_HOST_MODE) {
744             statusString.append("disabled-host-dock, ");
745         }
746 
747         if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK_DEVICE_MODE) ==
748             DATA_STATUS_DISABLED_DOCK_DEVICE_MODE) {
749             statusString.append("disabled-device-dock, ");
750         }
751         return statusString.toString().replaceAll(", $", "");
752     }
753 
754     /** @hide */
powerBrickConnectionStatusToString(int powerBrickConnectionStatus)755     public static String powerBrickConnectionStatusToString(int powerBrickConnectionStatus) {
756         switch (powerBrickConnectionStatus) {
757             case POWER_BRICK_STATUS_UNKNOWN:
758                 return "unknown";
759             case POWER_BRICK_STATUS_CONNECTED:
760                 return "connected";
761             case POWER_BRICK_STATUS_DISCONNECTED:
762                 return "disconnected";
763             default:
764                 return Integer.toString(powerBrickConnectionStatus);
765         }
766     }
767 
768     /** @hide */
roleCombinationsToString(int combo)769     public static String roleCombinationsToString(int combo) {
770         StringBuilder result = new StringBuilder();
771         result.append("[");
772 
773         boolean first = true;
774         while (combo != 0) {
775             final int index = Integer.numberOfTrailingZeros(combo);
776             combo &= ~(1 << index);
777             final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET);
778             final int dataRole = index % NUM_DATA_ROLES;
779             if (first) {
780                 first = false;
781             } else {
782                 result.append(", ");
783             }
784             result.append(powerRoleToString(powerRole));
785             result.append(':');
786             result.append(dataRoleToString(dataRole));
787         }
788 
789         result.append("]");
790         return result.toString();
791     }
792 
793     /** @hide */
complianceWarningsToString(@onNull int[] complianceWarnings)794     public static String complianceWarningsToString(@NonNull int[] complianceWarnings) {
795         StringBuilder complianceWarningString = new StringBuilder();
796         complianceWarningString.append("[");
797 
798         if (complianceWarnings != null) {
799             for (int warning : complianceWarnings) {
800                 switch (warning) {
801                     case UsbPortStatus.COMPLIANCE_WARNING_OTHER:
802                         complianceWarningString.append("other, ");
803                         break;
804                     case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY:
805                         complianceWarningString.append("debug accessory, ");
806                         break;
807                     case UsbPortStatus.COMPLIANCE_WARNING_BC_1_2:
808                         complianceWarningString.append("bc12, ");
809                         break;
810                     case UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP:
811                         complianceWarningString.append("missing rp, ");
812                         break;
813                     case UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED:
814                         complianceWarningString.append("input power limited, ");
815                         break;
816                     case UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES:
817                         complianceWarningString.append("missing data lines, ");
818                         break;
819                     case UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL:
820                         complianceWarningString.append("enumeration fail, ");
821                         break;
822                     case UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION:
823                         complianceWarningString.append("flaky connection, ");
824                         break;
825                     case UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO:
826                         complianceWarningString.append("unreliable io, ");
827                         break;
828                     default:
829                         complianceWarningString.append(String.format("Unknown(%d), ", warning));
830                         break;
831                 }
832             }
833         }
834 
835         complianceWarningString.append("]");
836         return complianceWarningString.toString().replaceAll(", ]$", "]");
837     }
838 
839     /** @hide */
dpAltModeStatusToString(int dpAltModeStatus)840     public static String dpAltModeStatusToString(int dpAltModeStatus) {
841         switch (dpAltModeStatus) {
842             case DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN:
843                 return "Unknown";
844             case DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE:
845                 return "Not Capable";
846             case DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED:
847                 return "Capable-Disabled";
848             case DISPLAYPORT_ALT_MODE_STATUS_ENABLED:
849                 return "Enabled";
850             default:
851                 return Integer.toString(dpAltModeStatus);
852         }
853     }
854 
855     /** @hide */
checkMode(int powerRole)856     public static void checkMode(int powerRole) {
857         Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
858                 Constants.PortMode.NUM_MODES - 1, "portMode");
859     }
860 
861     /** @hide */
checkPowerRole(int dataRole)862     public static void checkPowerRole(int dataRole) {
863         Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE,
864                 Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole");
865     }
866 
867     /** @hide */
checkDataRole(int mode)868     public static void checkDataRole(int mode) {
869         Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE,
870                 Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole");
871     }
872 
873     /** @hide */
checkRoles(int powerRole, int dataRole)874     public static void checkRoles(int powerRole, int dataRole) {
875         Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK,
876                 "powerRole");
877         Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole");
878     }
879 
880     /** @hide */
isModeSupported(int mode)881     public boolean isModeSupported(int mode) {
882         if ((mSupportedModes & mode) == mode) return true;
883         return false;
884     }
885 
886     @NonNull
887     @Override
toString()888     public String toString() {
889         return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes)
890                 + ", supportedContaminantProtectionModes=" + mSupportedContaminantProtectionModes
891                 + ", supportsEnableContaminantPresenceProtection="
892                 + mSupportsEnableContaminantPresenceProtection
893                 + ", supportsEnableContaminantPresenceDetection="
894                 + mSupportsEnableContaminantPresenceDetection
895                 + ", supportsComplianceWarnings="
896                 + mSupportsComplianceWarnings;
897     }
898 }
899