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

Commit 5f2a4ef7 authored by Jerry Zhang's avatar Jerry Zhang Committed by Android (Google) Code Review
Browse files

Merge changes from topic "UsbManager-changes"

* changes:
  Usb changes and strings for connected devices 2.0
  Refactor and clean up USB, add tests
parents 70f93ee6 28b6fc9c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -676,6 +676,7 @@ java_library {
        "android.hardware.vibrator-V1.1-java-constants",
        "android.hardware.wifi-V1.0-java-constants",
        "android.hardware.radio-V1.0-java",
        "android.hardware.usb.gadget-V1.0-java",
    ],

    // Loaded with System.loadLibrary by android.view.textclassifier
+21 −22
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;

public class UsbCommand extends Svc.Command {
    public UsbCommand() {
@@ -37,41 +36,41 @@ public class UsbCommand extends Svc.Command {
    public String longHelp() {
        return shortHelp() + "\n"
                + "\n"
                + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n"
                + "         Set the current usb function and optionally the data lock state.\n\n"
                + "usage: svc usb setFunctions [function]\n"
                + "         Set the current usb function. If function is blank, sets to charging.\n"
                + "       svc usb setScreenUnlockedFunctions [function]\n"
                + "         Sets the functions which, if the device was charging,"
                    + " become current on screen unlock.\n"
                + "       svc usb getFunction\n"
                + "          Gets the list of currently enabled functions\n";
                + "         Sets the functions which, if the device was charging, become current on"
                    + "screen unlock. If function is blank, turn off this feature.\n"
                + "       svc usb getFunctions\n"
                + "          Gets the list of currently enabled functions\n\n"
                + "possible values of [function] are any of 'mtp', 'ptp', 'rndis', 'midi'\n";
    }

    @Override
    public void run(String[] args) {
        boolean validCommand = false;
        if (args.length >= 2) {
            if ("setFunction".equals(args[1])) {
            IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
                    Context.USB_SERVICE));
                boolean unlockData = false;
                if (args.length >= 4) {
                    unlockData = Boolean.valueOf(args[3]);
                }
            if ("setFunctions".equals(args[1])) {
                try {
                    usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), unlockData);
                    usbMgr.setCurrentFunctions(UsbManager.usbFunctionsFromString(
                            args.length >= 3 ? args[2] : ""));
                } catch (RemoteException e) {
                    System.err.println("Error communicating with UsbManager: " + e);
                }
                return;
            } else if ("getFunction".equals(args[1])) {
                System.err.println(SystemProperties.get("sys.usb.config"));
            } else if ("getFunctions".equals(args[1])) {
                try {
                    System.err.println(
                            UsbManager.usbFunctionsToString(usbMgr.getCurrentFunctions()));
                } catch (RemoteException e) {
                    System.err.println("Error communicating with UsbManager: " + e);
                }
                return;
            } else if ("setScreenUnlockedFunctions".equals(args[1])) {
                IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
                        Context.USB_SERVICE));
                try {
                    usbMgr.setScreenUnlockedFunctions((args.length >= 3 ? args[2] :
                            UsbManager.USB_FUNCTION_NONE));
                    usbMgr.setScreenUnlockedFunctions(UsbManager.usbFunctionsFromString(
                            args.length >= 3 ? args[2] : ""));
                } catch (RemoteException e) {
                    System.err.println("Error communicating with UsbManager: " + e);
                }
+11 −7
Original line number Diff line number Diff line
@@ -88,18 +88,22 @@ interface IUsbManager
    /* Returns true if the specified USB function is enabled. */
    boolean isFunctionEnabled(String function);

    /* Sets the current USB function as well as whether USB data
     * (for example, MTP exposed pictures) should be made available
     * on the USB connection. Unlocking data should only be done with
     * user involvement, since exposing pictures or other data could
     * leak sensitive user information.
     */
    /* Sets the current USB function. */
    void setCurrentFunctions(long functions);

    /* Compatibility version of setCurrentFunctions(long). */
    void setCurrentFunction(String function, boolean usbDataUnlocked);

    /* Gets the current USB functions. */
    long getCurrentFunctions();

    /* Sets the screen unlocked USB function(s), which will be set automatically
     * when the screen is unlocked.
     */
    void setScreenUnlockedFunctions(String function);
    void setScreenUnlockedFunctions(long functions);

    /* Gets the current screen unlocked functions. */
    long getScreenUnlockedFunctions();

    /* Allow USB debugging from the attached host. If alwaysAllow is true, add the
     * the public key to list of host keys that the user has approved.
+195 −65
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -37,6 +38,8 @@ import android.util.Log;
import com.android.internal.util.Preconditions;

import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;

/**
 * This class allows you to access the state of USB and communicate with USB devices.
@@ -70,7 +73,7 @@ public class UsbManager {
     * MTP function is enabled
     * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
     * PTP function is enabled
     * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
     * <li> {@link #USB_FUNCTION_ACCESSORY} boolean extra indicating whether the
     * accessory function is enabled
     * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
     * audio source function is enabled
@@ -196,8 +199,7 @@ public class UsbManager {

    /**
     * A placeholder indicating that no USB function is being specified.
     * Used to distinguish between selecting no function vs. the default function in
     * {@link #setCurrentFunction(String)}.
     * Used for compatibility with old init scripts to indicate no functions vs. charging function.
     *
     * {@hide}
     */
@@ -298,6 +300,69 @@ public class UsbManager {
     */
    public static final String EXTRA_PERMISSION_GRANTED = "permission";

    /**
     * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
     * {@hide}
     */
    public static final long FUNCTION_NONE = 0;

    /**
     * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
     * {@hide}
     */
    public static final long FUNCTION_MTP = GadgetFunction.MTP;

    /**
     * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
     * {@hide}
     */
    public static final long FUNCTION_PTP = GadgetFunction.PTP;

    /**
     * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
     * {@hide}
     */
    public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;

    /**
     * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
     * {@hide}
     */
    public static final long FUNCTION_MIDI = GadgetFunction.MIDI;

    /**
     * Code for the accessory usb function.
     * {@hide}
     */
    public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;

    /**
     * Code for the audio source usb function.
     * {@hide}
     */
    public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;

    /**
     * Code for the adb usb function.
     * {@hide}
     */
    public static final long FUNCTION_ADB = GadgetFunction.ADB;

    private static final long SETTABLE_FUNCTIONS = FUNCTION_MTP | FUNCTION_PTP | FUNCTION_RNDIS
            | FUNCTION_MIDI;

    private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();

    static {
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MTP, FUNCTION_MTP);
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_PTP, FUNCTION_PTP);
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_RNDIS, FUNCTION_RNDIS);
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MIDI, FUNCTION_MIDI);
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ACCESSORY, FUNCTION_ACCESSORY);
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_AUDIO_SOURCE, FUNCTION_AUDIO_SOURCE);
        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ADB, FUNCTION_ADB);
    }

    private final Context mContext;
    private final IUsbManager mService;

@@ -548,15 +613,14 @@ public class UsbManager {
     * services offered by the device.
     * </p>
     *
     * @deprecated use getCurrentFunctions() instead.
     * @param function name of the USB function
     * @return true if the USB function is enabled
     *
     * {@hide}
     */
    @Deprecated
    public boolean isFunctionEnabled(String function) {
        if (mService == null) {
            return false;
        }
        try {
            return mService.isFunctionEnabled(function);
        } catch (RemoteException e) {
@@ -565,7 +629,7 @@ public class UsbManager {
    }

    /**
     * Sets the current USB function when in device mode.
     * Sets the current USB functions when in device mode.
     * <p>
     * USB functions represent interfaces which are published to the host to access
     * services offered by the device.
@@ -574,27 +638,59 @@ public class UsbManager {
     * automatically activate additional functions such as {@link #USB_FUNCTION_ADB}
     * or {@link #USB_FUNCTION_ACCESSORY} based on other settings and states.
     * </p><p>
     * The allowed values are: {@link #USB_FUNCTION_NONE}, {@link #USB_FUNCTION_AUDIO_SOURCE},
     * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP},
     * or {@link #USB_FUNCTION_RNDIS}.
     * </p><p>
     * Also sets whether USB data (for example, MTP exposed pictures) should be made available
     * on the USB connection when in device mode. Unlocking usb data should only be done with
     * user involvement, since exposing pictures or other data could leak sensitive
     * user information.
     * An argument of 0 indicates that the device is charging, and can pick any
     * appropriate function for that purpose.
     * </p><p>
     * Note: This function is asynchronous and may fail silently without applying
     * the requested changes.
     * </p>
     *
     * @param function name of the USB function, or null to restore the default function
     * @param usbDataUnlocked whether user data is accessible
     * @param functions the USB function(s) to set, as a bitwise mask.
     *                  Must satisfy {@link UsbManager#areSettableFunctions}
     *
     * {@hide}
     */
    public void setCurrentFunctions(long functions) {
        try {
            mService.setCurrentFunctions(functions);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Sets the current USB functions when in device mode.
     *
     * @deprecated use setCurrentFunctions(long) instead.
     * @param functions the USB function(s) to set.
     * @param usbDataUnlocked unused

     * {@hide}
     */
    @Deprecated
    public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
        try {
            mService.setCurrentFunction(functions, usbDataUnlocked);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns the current USB functions in device mode.
     * <p>
     * This function returns the state of primary USB functions and can return a
     * mask containing any usb function(s) except for ADB.
     * </p>
     *
     * @return The currently enabled functions, in a bitwise mask.
     * A zero mask indicates that the current function is the charging function.
     *
     * {@hide}
     */
    public void setCurrentFunction(String function, boolean usbDataUnlocked) {
    public long getCurrentFunctions() {
        try {
            mService.setCurrentFunction(function, usbDataUnlocked);
            return mService.getCurrentFunctions();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -604,23 +700,37 @@ public class UsbManager {
     * Sets the screen unlocked functions, which are persisted and set as the current functions
     * whenever the screen is unlocked.
     * <p>
     * The allowed values are: {@link #USB_FUNCTION_NONE},
     * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP},
     * or {@link #USB_FUNCTION_RNDIS}.
     * {@link #USB_FUNCTION_NONE} has the effect of switching off this feature, so functions
     * A zero mask has the effect of switching off this feature, so functions
     * no longer change on screen unlock.
     * </p><p>
     * Note: When the screen is on, this method will apply given functions as current functions,
     * which is asynchronous and may fail silently without applying the requested changes.
     * </p>
     *
     * @param function function to set as default
     * @param functions functions to set, in a bitwise mask.
     *                  Must satisfy {@link UsbManager#areSettableFunctions}
     *
     * {@hide}
     */
    public void setScreenUnlockedFunctions(long functions) {
        try {
            mService.setScreenUnlockedFunctions(functions);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Gets the current screen unlocked functions.
     *
     * @return The currently set screen enabled functions.
     * A zero mask indicates that the screen unlocked functions feature is not enabled.
     *
     * {@hide}
     */
    public void setScreenUnlockedFunctions(String function) {
    public long getScreenUnlockedFunctions() {
        try {
            mService.setScreenUnlockedFunctions(function);
            return mService.getScreenUnlockedFunctions();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -719,51 +829,71 @@ public class UsbManager {
        }
    }

    /** @hide */
    public static String addFunction(String functions, String function) {
        if (USB_FUNCTION_NONE.equals(functions)) {
            return function;
    /**
     * Returns whether the given functions are valid inputs to UsbManager.
     * Currently the empty functions or any of MTP, PTP, RNDIS, MIDI are accepted.
     *
     * @return Whether the mask is settable.
     *
     * {@hide}
     */
    public static boolean areSettableFunctions(long functions) {
        return functions == FUNCTION_NONE
                || ((~SETTABLE_FUNCTIONS & functions) == 0 && Long.bitCount(functions) == 1);
    }

    /**
     * Converts the given function mask to string. Maintains ordering with respect to init scripts.
     *
     * @return String representation of given mask
     *
     * {@hide}
     */
    public static String usbFunctionsToString(long functions) {
        StringJoiner joiner = new StringJoiner(",");
        if ((functions & FUNCTION_MTP) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_MTP);
        }
        if (!containsFunction(functions, function)) {
            if (functions.length() > 0) {
                functions += ",";
        if ((functions & FUNCTION_PTP) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_PTP);
        }
            functions += function;
        if ((functions & FUNCTION_RNDIS) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_RNDIS);
        }
        return functions;
        if ((functions & FUNCTION_MIDI) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_MIDI);
        }

    /** @hide */
    public static String removeFunction(String functions, String function) {
        String[] split = functions.split(",");
        for (int i = 0; i < split.length; i++) {
            if (function.equals(split[i])) {
                split[i] = null;
        if ((functions & FUNCTION_ACCESSORY) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_ACCESSORY);
        }
        if ((functions & FUNCTION_AUDIO_SOURCE) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_AUDIO_SOURCE);
        }
        if (split.length == 1 && split[0] == null) {
            return USB_FUNCTION_NONE;
        if ((functions & FUNCTION_ADB) != 0) {
            joiner.add(UsbManager.USB_FUNCTION_ADB);
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < split.length; i++) {
            String s = split[i];
            if (s != null) {
                if (builder.length() > 0) {
                    builder.append(",");
        return joiner.toString();
    }
                builder.append(s);

    /**
     * Parses a string of usb functions that are comma separated.
     *
     * @return A mask of all valid functions in the string
     *
     * {@hide}
     */
    public static long usbFunctionsFromString(String functions) {
        if (functions == null || functions.equals(USB_FUNCTION_NONE)) {
            return FUNCTION_NONE;
        }
        long ret = 0;
        for (String function : functions.split(",")) {
            if (FUNCTION_NAME_TO_CODE.containsKey(function)) {
                ret |= FUNCTION_NAME_TO_CODE.get(function);
            } else if (function.length() > 0) {
                throw new IllegalArgumentException("Invalid usb function " + functions);
            }
        return builder.toString();
        }

    /** @hide */
    public static boolean containsFunction(String functions, String function) {
        int index = functions.indexOf(function);
        if (index < 0) return false;
        if (index > 0 && functions.charAt(index - 1) != ',') return false;
        int charAfter = index + function.length();
        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
        return true;
        return ret;
    }
}
+10 −6
Original line number Diff line number Diff line
@@ -3222,19 +3222,23 @@
    <string name="dlg_ok">OK</string>

    <!-- USB_PREFERENCES: Notification for when the user connected to the charger only.  This is the title -->
    <string name="usb_charging_notification_title">USB charging this device</string>
    <string name="usb_charging_notification_title">Charging this device via USB</string>
    <!-- USB_PREFERENCES: Notification for when the user connects the phone to supply power to attached device.  This is the title -->
    <string name="usb_supplying_notification_title">USB supplying power to attached device</string>
    <string name="usb_supplying_notification_title">Charging connected device via USB</string>
    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MTP mode.  This is the title -->
    <string name="usb_mtp_notification_title">USB for file transfer</string>
    <string name="usb_mtp_notification_title">USB file transfer turned on</string>
    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode.  This is the title -->
    <string name="usb_ptp_notification_title">USB for photo transfer</string>
    <string name="usb_ptp_notification_title">PTP via USB turned on</string>
    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in Tethering mode.  This is the title -->
    <string name="usb_tether_notification_title">USB tethering turned on</string>
    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MIDI mode.  This is the title -->
    <string name="usb_midi_notification_title">USB for MIDI</string>
    <string name="usb_midi_notification_title">MIDI via USB turned on</string>
    <!-- USB_PREFERENCES: Notification for when a USB accessory is attached.  This is the title -->
    <string name="usb_accessory_notification_title">Connected to a USB accessory</string>
    <string name="usb_accessory_notification_title">USB accessory mode turned on</string>
    <!-- See USB_PREFERENCES. This is the message. -->
    <string name="usb_notification_message">Tap for more options.</string>
    <!-- See USB_PREFERENCES. This is the message when a data mode is turned on (mtp, ptp, midi) and the device is supplying power.. -->
    <string name="usb_power_notification_message">Charging connected device. Tap for more options.</string>
    <!-- USB_PREFERENCES: Notification for when a type-c USB audio accessory is attached but not supported.  This is the title -->
    <string name="usb_unsupported_audio_accessory_title">Analog audio accessory detected</string>
    <!-- Message of notification shown when a type-c USB audio accessory is attached but not supported. -->
Loading