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