| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.hardware.usb; |
| |
| import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; |
| import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; |
| import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE; |
| import static android.hardware.usb.UsbPortStatus.MODE_AUDIO_ACCESSORY; |
| import static android.hardware.usb.UsbPortStatus.MODE_DEBUG_ACCESSORY; |
| import static android.hardware.usb.UsbPortStatus.MODE_DFP; |
| import static android.hardware.usb.UsbPortStatus.MODE_DUAL; |
| import static android.hardware.usb.UsbPortStatus.MODE_NONE; |
| import static android.hardware.usb.UsbPortStatus.MODE_UFP; |
| import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE; |
| import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; |
| import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; |
| |
| import android.Manifest; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SystemApi; |
| import android.hardware.usb.V1_0.Constants; |
| |
| import com.android.internal.util.Preconditions; |
| |
| /** |
| * Represents a physical USB port and describes its characteristics. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public final class UsbPort { |
| private final String mId; |
| private final int mSupportedModes; |
| private final UsbManager mUsbManager; |
| |
| private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES; |
| |
| /** |
| * Points to the first power role in the IUsb HAL. |
| */ |
| private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE; |
| |
| /** @hide */ |
| public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes) { |
| Preconditions.checkNotNull(id); |
| Preconditions.checkFlagsArgument(supportedModes, |
| MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY); |
| |
| mUsbManager = usbManager; |
| mId = id; |
| mSupportedModes = supportedModes; |
| } |
| |
| /** |
| * Gets the unique id of the port. |
| * |
| * @return The unique id of the port; not intended for display. |
| * |
| * @hide |
| */ |
| public String getId() { |
| return mId; |
| } |
| |
| /** |
| * Gets the supported modes of the port. |
| * <p> |
| * The actual mode of the port may vary depending on what is plugged into it. |
| * </p> |
| * |
| * @return The supported modes: one of {@link UsbPortStatus#MODE_DFP}, |
| * {@link UsbPortStatus#MODE_UFP}, or {@link UsbPortStatus#MODE_DUAL}. |
| * |
| * @hide |
| */ |
| public int getSupportedModes() { |
| return mSupportedModes; |
| } |
| |
| /** |
| * Gets the status of this USB port. |
| * |
| * @return The status of the this port, or {@code null} if port is unknown. |
| */ |
| @RequiresPermission(Manifest.permission.MANAGE_USB) |
| public @Nullable UsbPortStatus getStatus() { |
| return mUsbManager.getPortStatus(this); |
| } |
| |
| /** |
| * Sets the desired role combination of the port. |
| * <p> |
| * The supported role combinations depend on what is connected to the port and may be |
| * determined by consulting |
| * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. |
| * </p><p> |
| * Note: This function is asynchronous and may fail silently without applying |
| * the requested changes. If this function does cause a status change to occur then |
| * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent. |
| * </p> |
| * |
| * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} or |
| * {@link UsbPortStatus#POWER_ROLE_SINK}, or |
| * {@link UsbPortStatus#POWER_ROLE_NONE} if no power role. |
| * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} or |
| * {@link UsbPortStatus#DATA_ROLE_DEVICE}, or |
| * {@link UsbPortStatus#DATA_ROLE_NONE} if no data role. |
| */ |
| @RequiresPermission(Manifest.permission.MANAGE_USB) |
| public void setRoles(@UsbPortStatus.UsbPowerRole int powerRole, |
| @UsbPortStatus.UsbDataRole int dataRole) { |
| UsbPort.checkRoles(powerRole, dataRole); |
| |
| mUsbManager.setPortRoles(this, powerRole, dataRole); |
| } |
| |
| /** |
| * Combines one power and one data role together into a unique value with |
| * exactly one bit set. This can be used to efficiently determine whether |
| * a combination of roles is supported by testing whether that bit is present |
| * in a bit-field. |
| * |
| * @param powerRole The desired power role: {@link UsbPortStatus#POWER_ROLE_SOURCE} |
| * or {@link UsbPortStatus#POWER_ROLE_SINK}, or 0 if no power role. |
| * @param dataRole The desired data role: {@link UsbPortStatus#DATA_ROLE_HOST} |
| * or {@link UsbPortStatus#DATA_ROLE_DEVICE}, or 0 if no data role. |
| * @hide |
| */ |
| public static int combineRolesAsBit(int powerRole, int dataRole) { |
| checkRoles(powerRole, dataRole); |
| final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole; |
| return 1 << index; |
| } |
| |
| /** @hide */ |
| public static String modeToString(int mode) { |
| StringBuilder modeString = new StringBuilder(); |
| if (mode == MODE_NONE) { |
| return "none"; |
| } |
| |
| if ((mode & MODE_DUAL) == MODE_DUAL) { |
| modeString.append("dual, "); |
| } else { |
| if ((mode & MODE_DFP) == MODE_DFP) { |
| modeString.append("dfp, "); |
| } else if ((mode & MODE_UFP) == MODE_UFP) { |
| modeString.append("ufp, "); |
| } |
| } |
| if ((mode & MODE_AUDIO_ACCESSORY) == MODE_AUDIO_ACCESSORY) { |
| modeString.append("audio_acc, "); |
| } |
| if ((mode & MODE_DEBUG_ACCESSORY) == MODE_DEBUG_ACCESSORY) { |
| modeString.append("debug_acc, "); |
| } |
| |
| if (modeString.length() == 0) { |
| return Integer.toString(mode); |
| } |
| return modeString.substring(0, modeString.length() - 2); |
| } |
| |
| /** @hide */ |
| public static String powerRoleToString(int role) { |
| switch (role) { |
| case POWER_ROLE_NONE: |
| return "no-power"; |
| case POWER_ROLE_SOURCE: |
| return "source"; |
| case POWER_ROLE_SINK: |
| return "sink"; |
| default: |
| return Integer.toString(role); |
| } |
| } |
| |
| /** @hide */ |
| public static String dataRoleToString(int role) { |
| switch (role) { |
| case DATA_ROLE_NONE: |
| return "no-data"; |
| case DATA_ROLE_HOST: |
| return "host"; |
| case DATA_ROLE_DEVICE: |
| return "device"; |
| default: |
| return Integer.toString(role); |
| } |
| } |
| |
| /** @hide */ |
| public static String roleCombinationsToString(int combo) { |
| StringBuilder result = new StringBuilder(); |
| result.append("["); |
| |
| boolean first = true; |
| while (combo != 0) { |
| final int index = Integer.numberOfTrailingZeros(combo); |
| combo &= ~(1 << index); |
| final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET); |
| final int dataRole = index % NUM_DATA_ROLES; |
| if (first) { |
| first = false; |
| } else { |
| result.append(", "); |
| } |
| result.append(powerRoleToString(powerRole)); |
| result.append(':'); |
| result.append(dataRoleToString(dataRole)); |
| } |
| |
| result.append("]"); |
| return result.toString(); |
| } |
| |
| /** @hide */ |
| public static void checkMode(int powerRole) { |
| Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE, |
| Constants.PortMode.NUM_MODES - 1, "portMode"); |
| } |
| |
| /** @hide */ |
| public static void checkPowerRole(int dataRole) { |
| Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE, |
| Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole"); |
| } |
| |
| /** @hide */ |
| public static void checkDataRole(int mode) { |
| Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE, |
| Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole"); |
| } |
| |
| /** @hide */ |
| public static void checkRoles(int powerRole, int dataRole) { |
| Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK, |
| "powerRole"); |
| Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole"); |
| } |
| |
| /** @hide */ |
| public boolean isModeSupported(int mode) { |
| if ((mSupportedModes & mode) == mode) return true; |
| return false; |
| } |
| |
| |
| @Override |
| public String toString() { |
| return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}"; |
| } |
| } |