Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7212c8fd authored by Badhri Jagan Sridharan's avatar Badhri Jagan Sridharan Committed by Ricky Niu
Browse files

Add systemApis to allow data transfer over USB-C while being docked



This change adds two systemApis to UsbPortStatus viz.,
a. getUsbDataStatus: Allows caller to infer whether USB data is enabled.
b. getPowerBrickStatus: Allows caller to infer whether a power brick
                        is connected to the USB port.

The change also adds enableUsbDataWhileDocked systemApi to UsbPort to
enable Usb data momentarily.

Bug: 211677613
Bug: 213312081
Test: Manually tested on tablet
CTS-Coverage-Bug: 215019881
Signed-off-by: default avatarBadhri Jagan Sridharan <badhri@google.com>
Change-Id: Ib7521f0f04b7f8e3e58dc253b28072d3631f21a7
parent bdbb2d15
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -4688,6 +4688,7 @@ package android.hardware.usb {
  public final class UsbPort {
    method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableLimitPowerTransfer(boolean);
    method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean);
    method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbDataWhileDocked();
    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
    field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1; // 0x1
@@ -4700,6 +4701,12 @@ package android.hardware.usb {
    field public static final int ENABLE_USB_DATA_ERROR_OTHER = 4; // 0x4
    field public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3; // 0x3
    field public static final int ENABLE_USB_DATA_SUCCESS = 0; // 0x0
    field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED = 4; // 0x4
    field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL = 1; // 0x1
    field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED = 2; // 0x2
    field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER = 5; // 0x5
    field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH = 3; // 0x3
    field public static final int ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS = 0; // 0x0
  }
  public final class UsbPortStatus implements android.os.Parcelable {
@@ -4707,7 +4714,9 @@ package android.hardware.usb {
    method public int getCurrentDataRole();
    method public int getCurrentMode();
    method public int getCurrentPowerRole();
    method public int getPowerBrickStatus();
    method public int getSupportedRoleCombinations();
    method @Nullable public int[] getUsbDataStatus();
    method public boolean isConnected();
    method public boolean isPowerTransferLimited();
    method public boolean isRoleCombinationSupported(int, int);
@@ -4721,9 +4730,19 @@ package android.hardware.usb {
    field public static final int MODE_DFP = 2; // 0x2
    field public static final int MODE_NONE = 0; // 0x0
    field public static final int MODE_UFP = 1; // 0x1
    field public static final int POWER_BRICK_STATUS_CONNECTED = 1; // 0x1
    field public static final int POWER_BRICK_STATUS_DISCONNECTED = 2; // 0x2
    field public static final int POWER_BRICK_STATUS_UNKNOWN = 0; // 0x0
    field public static final int POWER_ROLE_NONE = 0; // 0x0
    field public static final int POWER_ROLE_SINK = 2; // 0x2
    field public static final int POWER_ROLE_SOURCE = 1; // 0x1
    field public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3; // 0x3
    field public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6; // 0x6
    field public static final int USB_DATA_STATUS_DISABLED_DOCK = 4; // 0x4
    field public static final int USB_DATA_STATUS_DISABLED_FORCE = 5; // 0x5
    field public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
    field public static final int USB_DATA_STATUS_ENABLED = 1; // 0x1
    field public static final int USB_DATA_STATUS_UNKNOWN = 0; // 0x0
  }
}
+3 −0
Original line number Diff line number Diff line
@@ -139,6 +139,9 @@ interface IUsbManager
    /* Set USB data on or off */
    boolean enableUsbData(in String portId, boolean enable, int operationId, in IUsbOperationInternal callback);

    /* Enable USB data when disabled due to docking event  */
    void enableUsbDataWhileDocked(in String portId, int operationId, in IUsbOperationInternal callback);

    /* Gets the USB Hal Version. */
    int getUsbHalVersion();

+29 −0
Original line number Diff line number Diff line
@@ -1358,6 +1358,35 @@ public class UsbManager {
        }
    }

    /**
     * Should only be called by {@link UsbPort#enableUsbDataWhileDocked}.
     * <p>
     * Enables or disables USB data when disabled due to docking event.
     *
     * @param port USB port for which USB data needs to be enabled.
     * @param operationId operationId for the request.
     * @param callback callback object to be invoked when the operation is complete.
     * @hide
     */
    @RequiresPermission(Manifest.permission.MANAGE_USB)
    void enableUsbDataWhileDocked(@NonNull UsbPort port, int operationId,
            IUsbOperationInternal callback) {
        Objects.requireNonNull(port, "enableUsbDataWhileDocked: port must not be null. opId:"
                + operationId);
        try {
            mService.enableUsbDataWhileDocked(port.getId(), operationId, callback);
        } catch (RemoteException e) {
            Log.e(TAG, "enableUsbDataWhileDocked: failed. opId:" + operationId, e);
            try {
                callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL);
            } catch (RemoteException r) {
                Log.e(TAG, "enableUsbDataWhileDocked: failed to call onOperationComplete. opId:"
                        + operationId, r);
            }
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Sets the component that will handle USB device connection.
     * <p>
+148 −0
Original line number Diff line number Diff line
@@ -33,9 +33,19 @@ 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_BRICK_STATUS_DISCONNECTED;
import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_CONNECTED;
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 static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_ENABLED;
import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_OVERHEAT;
import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_CONTAMINANT;
import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DOCK;
import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DEBUG;

import android.Manifest;
import android.annotation.CheckResult;
@@ -154,6 +164,48 @@ public final class UsbPort {
    @Retention(RetentionPolicy.SOURCE)
    @interface EnableLimitPowerTransferStatus{}

    /**
     * The {@link #enableUsbDataWhileDocked} request was successfully completed.
     */
    public static final int ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS = 0;

    /**
     * The {@link #enableUsbDataWhileDocked} request failed due to internal error.
     */
    public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL = 1;

    /**
     * The {@link #enableUsbDataWhileDocked} request failed as it's not supported.
     */
    public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED = 2;

    /**
     * The {@link #enableUsbDataWhileDocked} request failed as port id mismatched.
     */
    public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH = 3;

    /**
     * The {@link #enableUsbDataWhileDocked} request failed as data is still enabled.
     */
    public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED = 4;

    /**
     * The {@link #enableUsbDataWhileDocked} request failed due to other reasons.
     */
    public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER = 5;

    /** @hide */
    @IntDef(prefix = { "ENABLE_USB_DATA_WHILE_DOCKED_" }, value = {
            ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS,
            ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL,
            ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED,
            ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH,
            ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED,
            ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface EnableUsbDataWhileDockedStatus{}

    /** @hide */
    public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
            int supportedContaminantProtectionModes,
@@ -307,6 +359,51 @@ public final class UsbPort {
        }
    }

    /**
     * Enables Usb data when disabled due to {@link UsbPort#USB_DATA_STATUS_DISABLED_DOCK}
     *
     * @return {@link #ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS} when request completes successfully or
     *         {@link #ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL} when request fails due to
     *         internal error or
     *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED} when not supported or
     *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH} when request fails due to
     *         port id mismatch or
     *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED} when request fails as data
     *         is still enabled or
     *         {@link ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER} when fails due to other reasons.
     */
    @CheckResult
    @RequiresPermission(Manifest.permission.MANAGE_USB)
    public @EnableUsbDataWhileDockedStatus int enableUsbDataWhileDocked() {
        // UID is added To minimize operationID overlap between two different packages.
        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
        Log.i(TAG, "enableUsbData opId:" + operationId
                + " callingUid:" + Binder.getCallingUid());
        UsbPortStatus portStatus = getStatus();
        if (portStatus != null &&
                !usbDataStatusToString(portStatus.getUsbDataStatus()).contains("disabled-dock")) {
            return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED;
        }

        UsbOperationInternal opCallback =
                new UsbOperationInternal(operationId, mId);
        mUsbManager.enableUsbDataWhileDocked(this, operationId, opCallback);
                opCallback.waitForOperationComplete();
        int result = opCallback.getStatus();
        switch (result) {
            case USB_OPERATION_SUCCESS:
                return ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS;
            case USB_OPERATION_ERROR_INTERNAL:
                return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL;
            case USB_OPERATION_ERROR_NOT_SUPPORTED:
                return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_NOT_SUPPORTED;
            case USB_OPERATION_ERROR_PORT_MISMATCH:
                return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH;
            default:
                return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER;
        }
    }

    /**
     * Limits power transfer In and out of the port.
     * <p>
@@ -445,6 +542,57 @@ public final class UsbPort {
        }
    }

    /** @hide */
    public static String usbDataStatusToString(int usbDataStatus) {
        switch (usbDataStatus) {
            case USB_DATA_STATUS_UNKNOWN:
                return "unknown";
            case USB_DATA_STATUS_ENABLED:
                return "enabled";
            case USB_DATA_STATUS_DISABLED_OVERHEAT:
                return "disabled-overheat";
            case USB_DATA_STATUS_DISABLED_CONTAMINANT:
                return "disabled-contaminant";
            case USB_DATA_STATUS_DISABLED_DOCK:
                return "disabled-dock";
            case USB_DATA_STATUS_DISABLED_FORCE:
                return "disabled-force";
            case USB_DATA_STATUS_DISABLED_DEBUG:
                return "disabled-debug";
            default:
                return Integer.toString(usbDataStatus);
        }
    }

    /** @hide */
    public static String usbDataStatusToString(int[] usbDataStatus) {
        StringBuilder modeString = new StringBuilder();
        if (usbDataStatus == null) {
            return "unknown";
        }
        for (int i = 0; i < usbDataStatus.length; i++) {
            modeString.append(usbDataStatusToString(usbDataStatus[i]));
            if (i < usbDataStatus.length - 1) {
                modeString.append(", ");
            }
        }
        return modeString.toString();
    }

    /** @hide */
    public static String powerBrickStatusToString(int powerBrickStatus) {
        switch (powerBrickStatus) {
            case POWER_BRICK_STATUS_UNKNOWN:
                return "unknown";
            case POWER_BRICK_STATUS_CONNECTED:
                return "connected";
            case POWER_BRICK_STATUS_DISCONNECTED:
                return "disconnected";
            default:
                return Integer.toString(powerBrickStatus);
        }
    }

    /** @hide */
    public static String roleCombinationsToString(int combo) {
        StringBuilder result = new StringBuilder();
+112 −13
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.hardware.usb;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -42,8 +43,9 @@ public final class UsbPortStatus implements Parcelable {
    private final int mSupportedRoleCombinations;
    private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
    private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
    private final boolean mUsbDataEnabled;
    private final boolean mPowerTransferLimited;
    private final @UsbDataStatus int[] mUsbDataStatus;
    private final @PowerBrickStatus int mPowerBrickStatus;

    /**
     * Power role: This USB port does not have a power role.
@@ -193,6 +195,57 @@ public final class UsbPortStatus implements Parcelable {
     */
    public static final int CONTAMINANT_PROTECTION_DISABLED = 1 << 3;

    /**
     * USB data status is not known.
     */
    public static final int USB_DATA_STATUS_UNKNOWN = 0;

    /**
     * USB data is enabled.
     */
    public static final int USB_DATA_STATUS_ENABLED = 1;

    /**
     * USB data is disabled as the port is too hot.
     */
    public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;

    /**
     * USB data is disabled due to contaminated port.
     */
    public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;

    /**
     * USB data is disabled due to docking event.
     */
    public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;

    /**
     * USB data is disabled by
     * {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
     */
    public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;

    /**
     * USB data is disabled for debug.
     */
    public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;

    /**
     * Unknown whether a power brick is connected.
     */
    public static final int POWER_BRICK_STATUS_UNKNOWN = 0;

    /**
     * The connected device is a power brick.
     */
    public static final int POWER_BRICK_STATUS_CONNECTED = 1;

    /**
     * The connected device is not power brick.
     */
    public static final int POWER_BRICK_STATUS_DISCONNECTED = 2;

    @IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
            CONTAMINANT_DETECTION_NOT_SUPPORTED,
            CONTAMINANT_DETECTION_DISABLED,
@@ -222,19 +275,42 @@ public final class UsbPortStatus implements Parcelable {
    @Retention(RetentionPolicy.SOURCE)
    @interface UsbPortMode{}

    /** @hide */
    @IntDef(prefix = { "USB_DATA_STATUS_" }, value = {
            USB_DATA_STATUS_UNKNOWN,
            USB_DATA_STATUS_ENABLED,
            USB_DATA_STATUS_DISABLED_OVERHEAT,
            USB_DATA_STATUS_DISABLED_CONTAMINANT,
            USB_DATA_STATUS_DISABLED_DOCK,
            USB_DATA_STATUS_DISABLED_FORCE,
            USB_DATA_STATUS_DISABLED_DEBUG
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface UsbDataStatus{}

    /** @hide */
    @IntDef(prefix = { "POWER_BRICK_STATUS_" }, value = {
            POWER_BRICK_STATUS_UNKNOWN,
            POWER_BRICK_STATUS_DISCONNECTED,
            POWER_BRICK_STATUS_CONNECTED,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface PowerBrickStatus{}

    /** @hide */
    public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
            int supportedRoleCombinations, int contaminantProtectionStatus,
            int contaminantDetectionStatus, boolean usbDataEnabled,
            boolean powerTransferLimited) {
            int contaminantDetectionStatus, @UsbDataStatus int[] usbDataStatus,
            boolean powerTransferLimited, @PowerBrickStatus int powerBrickStatus) {
        mCurrentMode = currentMode;
        mCurrentPowerRole = currentPowerRole;
        mCurrentDataRole = currentDataRole;
        mSupportedRoleCombinations = supportedRoleCombinations;
        mContaminantProtectionStatus = contaminantProtectionStatus;
        mContaminantDetectionStatus = contaminantDetectionStatus;
        mUsbDataEnabled = usbDataEnabled;
        mUsbDataStatus = usbDataStatus;
        mPowerTransferLimited = powerTransferLimited;
        mPowerBrickStatus = powerBrickStatus;
    }

    /** @hide */
@@ -247,7 +323,8 @@ public final class UsbPortStatus implements Parcelable {
        mSupportedRoleCombinations = supportedRoleCombinations;
        mContaminantProtectionStatus = contaminantProtectionStatus;
        mContaminantDetectionStatus = contaminantDetectionStatus;
        mUsbDataEnabled = true;
        mUsbDataStatus = new int[]{USB_DATA_STATUS_UNKNOWN};
        mPowerBrickStatus = POWER_BRICK_STATUS_UNKNOWN;
        mPowerTransferLimited = false;
    }

@@ -334,10 +411,14 @@ public final class UsbPortStatus implements Parcelable {
    /**
     * Returns UsbData status.
     *
     * @hide
     */
    public boolean getUsbDataStatus() {
        return mUsbDataEnabled;
     * @return Current USB data status of the port: {@link #USB_DATA_STATUS_UNKNOWN}
     *         or {@link #USB_DATA_STATUS_ENABLED} or {@link #USB_DATA_STATUS_DIASBLED_OVERHEAT}
     *         or {@link #USB_DATA_STATUS_DISABLED_CONTAMINANT}
     *         or {@link #USB_DATA_STATUS_DISABLED_DOCK} or {@link #USB_DATA_STATUS_DISABLED_FORCE}
     *         or {@link #USB_DATA_STATUS_DISABLED_DEBUG}
     */
    public @UsbDataStatus @Nullable int[] getUsbDataStatus() {
        return mUsbDataStatus;
    }

    /**
@@ -350,6 +431,17 @@ public final class UsbPortStatus implements Parcelable {
        return mPowerTransferLimited;
    }

    /**
     * Let's the caller know if a power brick is connected to the USB port.
     *
     * @return {@link #POWER_BRICK_STATUS_UNKNOWN}
     *         or {@link #POWER_BRICK_STATUS_CONNECTED}
     *         or {@link #POWER_BRICK_STATUS_DISCONNECTED}
     */
    public @PowerBrickStatus int getPowerBrickStatus() {
        return mPowerBrickStatus;
    }

    @NonNull
    @Override
    public String toString() {
@@ -363,10 +455,12 @@ public final class UsbPortStatus implements Parcelable {
                        + getContaminantDetectionStatus()
                + ", contaminantProtectionStatus="
                        + getContaminantProtectionStatus()
                + ", usbDataEnabled="
                        + getUsbDataStatus()
                + ", usbDataStatus="
                        + UsbPort.usbDataStatusToString(getUsbDataStatus())
                + ", isPowerTransferLimited="
                        + isPowerTransferLimited()
                +", powerBrickStatus="
                        + UsbPort.powerBrickStatusToString(getPowerBrickStatus())
                + "}";
    }

@@ -383,8 +477,10 @@ public final class UsbPortStatus implements Parcelable {
        dest.writeInt(mSupportedRoleCombinations);
        dest.writeInt(mContaminantProtectionStatus);
        dest.writeInt(mContaminantDetectionStatus);
        dest.writeBoolean(mUsbDataEnabled);
        dest.writeInt(mUsbDataStatus.length);
        dest.writeIntArray(mUsbDataStatus);
        dest.writeBoolean(mPowerTransferLimited);
        dest.writeInt(mPowerBrickStatus);
    }

    public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -397,11 +493,14 @@ public final class UsbPortStatus implements Parcelable {
            int supportedRoleCombinations = in.readInt();
            int contaminantProtectionStatus = in.readInt();
            int contaminantDetectionStatus = in.readInt();
            boolean usbDataEnabled = in.readBoolean();
            int[] usbDataStatus = new int[in.readInt()];
            in.readIntArray(usbDataStatus);
            boolean powerTransferLimited = in.readBoolean();
            int powerBrickStatus = in.readInt();
            return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                    supportedRoleCombinations, contaminantProtectionStatus,
                    contaminantDetectionStatus, usbDataEnabled, powerTransferLimited);
                    contaminantDetectionStatus, usbDataStatus, powerTransferLimited,
                    powerBrickStatus);
        }

        @Override
Loading