usbmanager获取鼠标设备

在旧手机上安卓6获取到了设备鼠标,但是在我安卓十上插上鼠标没有反应,不会弹出是否访问词设备

买的鼠标不可以,家里买的那个可以,可能是鼠标芯片不同吧

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以看下这个问题的回答https://ask.csdn.net/questions/149025
  • 你也可以参考下这篇文章:移动硬盘已连接USB我的电脑不显示的全网最细汇总多种解决方法(保姆级图文详细步骤)
  • 除此之外, 这篇博客: android9.0 UsbManager源码解析中的 二、每个类的简介 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    1、UsbManager:获得Usb的状态,与连接的Usb设备通信。
    2、UsbDevice:Usb设备的抽象,它包含一个或多个UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(endpoint)发送和接收数据。
    3、UsbInterface:定义了设备的功能集,一个UsbDevice包含多个UsbInterface,每个Interface都是独立的。
    4、UsbEndpoint:endpoint是interface的通信通道。
    5、UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
    6、UsbRequest:usb 请求包。可以在UsbDeviceConnection上异步传输数据。注意是只在异步通信时才会用到它。
    7、UsbConstants:usb常量的定义,对应linux/usb/ch9.h

    xref: /frameworks/base/core/java/android/hardware/usb/UsbManager.java

    这个描述的是USB目前的状态,也就是连上之后主要是做什么工作的,比如adb,音频,midi接口等等。

    /**
      * Broadcast Action:  A sticky broadcast for USB state change events when in device mode.
      *
      * This is a sticky broadcast for clients that includes USB connected/disconnected state,
      * <ul>
      * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
      * <li> {@link #USB_HOST_CONNECTED} boolean indicating whether USB is connected or
      *     disconnected as host.
      * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured.
      * currently zero if not configured, one for configured.
      * <li> {@link #USB_FUNCTION_ADB} boolean extra indicating whether the
      * adb function is enabled
      * <li> {@link #USB_FUNCTION_RNDIS} boolean extra indicating whether the
      * RNDIS ethernet function is enabled
      * <li> {@link #USB_FUNCTION_MTP} boolean extra indicating whether the
      * MTP function is enabled
      * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
      * PTP function is enabled
      * <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
      * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
      * MIDI function is enabled
      * </ul>
      * If the sticky intent has not been found, that indicates USB is disconnected,
      * USB is not configued, MTP function is enabled, and all the other functions are disabled.
      *
      * {@hide}
      */
     public static final String ACTION_USB_STATE =
             "android.hardware.usb.action.USB_STATE";
    
    public static final String ACTION_USB_PORT_CHANGED =
            "android.hardware.usb.action.USB_PORT_CHANGED";    广播操作:USB端口更改的广播。
     
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_USB_DEVICE_ATTACHED =
            "android.hardware.usb.action.USB_DEVICE_ATTACHED"; 用户连接USB设备时发送的activity intent。
     
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_USB_DEVICE_DETACHED =
            "android.hardware.usb.action.USB_DEVICE_DETACHED"; 广播操作:USB设备分离事件的广播。
     
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_USB_ACCESSORY_ATTACHED =
            "android.hardware.usb.action.USB_ACCESSORY_ATTACHED"; 用户连接USB附件时发送的活动意图。
     
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_USB_ACCESSORY_DETACHED =
            "android.hardware.usb.action.USB_ACCESSORY_DETACHED"; 用户断开连接USB附件时发送的活动意图。
     
    下面这个是定义的USB连接功能的字符串
     
    public static final String USB_CONNECTED = "connected";             表示USB是连接还是断开 
     
    public static final String USB_HOST_CONNECTED = "host_connected";   指示USB是否作为主机连接或断开连接。
     
    public static final String USB_CONFIGURED = "configured";           指示是否配置了USB。
     
    public static final String USB_DATA_UNLOCKED = "unlocked";          指示是否应在USB连接上提供机密用户数据,如照片。仅当用户明确要求解锁此数据时,才会设置此变量。
     
    public static final String USB_FUNCTION_NONE = "none";              表示未指定USB功能的占位符。
     
    public static final String USB_FUNCTION_ADB = "adb";                usb连接作为adb的功能。
     
    public static final String USB_FUNCTION_RNDIS = "rndis";            RNDIS以太网USB功能的名称。
     
    public static final String USB_FUNCTION_MTP = "mtp";                MTP连接模式,一般作为USB的默认连接方式。
     
    public static final String USB_FUNCTION_PTP = "ptp";                PTP连接模式,一种USB传输协议。
     
    public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";  USB连接被用作音频播放源
     
    public static final String USB_FUNCTION_MIDI = "midi";              USB连接被用作MIDI数字化传输
     
    public static final String USB_FUNCTION_ACCESSORY = "accessory";    accessory连接模式,一般电脑对手机都是这种模式,手机是accessory
     
    public static final String EXTRA_PORT = "port";                     {@link#ACTION_USB_PORT_CHANGED}的额外名称
     
    public static final String EXTRA_PORT_STATUS = "portStatus";        {@link#ACTION_USB_PORT_CHANGED}的额外名称
     
    public static final String EXTRA_DEVICE = "device";                 “同上”
     
    public static final String EXTRA_ACCESSORY = "accessory";           “同上”
     
    public static final String EXTRA_PERMISSION_GRANTED = "permission"; ...
     
    public static final long FUNCTION_NONE = 0;                         ...
     
    public static final long FUNCTION_MTP = GadgetFunction.MTP;         ...
     
    public static final long FUNCTION_PTP = GadgetFunction.PTP;         ...
     
    public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;     ...
     
    public static final long FUNCTION_MIDI = GadgetFunction.MIDI;       ...
     
    public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY; ...
     
    public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;   ...
    

    下面这个是其构造方法,但是我们一般都用getSystemService来获取这个USBManager

    ```c
    
    /**
     * {@hide}
     */
    public UsbManager(Context context, IUsbManager service) {
        mContext = context;
        mService = service;
    }
    

    获取所有的USB设备(当前连接的),一个很重要的方法。

    /**
     * Returns a HashMap containing all USB devices currently attached.
     * USB device name is the key for the returned HashMap.
     * The result will be empty if no devices are attached, or if
     * USB host mode is inactive or unsupported.
     *
     * @return HashMap containing all connected USB devices.
     */
    @RequiresFeature(PackageManager.FEATURE_USB_HOST)   //需要权限
    public HashMap<String,UsbDevice> getDeviceList() {
        HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>(); //这个容器里面key是字符串名字,value就是对应的USBDevice
        if (mService == null) {
            return result;
        }
        Bundle bundle = new Bundle();           //跨进程传输的数据携带者
        try {
            mService.getDeviceList(bundle);     //利用UsbService获取到当前的设备列表,它们之间的通信方式是AIDL,USBservice实现了USBManager.aidl
            for (String name : bundle.keySet()) {
                result.put(name, (UsbDevice)bundle.get(name));
            }
            return result;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    打开设备的方法,使之能接受或发送数据

    /**
     * Opens the device so it can be used to send and receive
     * data using {@link android.hardware.usb.UsbRequest}.
     *
     * @param device the device to open
     * @return a {@link UsbDeviceConnection}, or {@code null} if open failed
     */
    @RequiresFeature(PackageManager.FEATURE_USB_HOST)
    public UsbDeviceConnection openDevice(UsbDevice device) {
        try {
            String deviceName = device.getDeviceName();
            ParcelFileDescriptor pfd = mService.openDevice(deviceName, mContext.getPackageName());//仍然是调UsbService里面的方法来打开设备
            if (pfd != null) {
                UsbDeviceConnection connection = new UsbDeviceConnection(device);   //如果设备文件被打开,创建连接类
                boolean result = connection.open(deviceName, pfd, mContext);        //利用生成的文件描述符和设备名,建立连接,usb这里有专门的连接类来处理这一块的工作
                pfd.close();
                if (result) {
                    return connection;
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "exception in UsbManager.openDevice", e);
        }
        return null;
    }
    

    这个方法很简单,就是获取当前连接上的accessories的列表,但是这当前的连接只能有一个,也就是可以生效的。

    /**
     * Returns a list of currently attached USB accessories.
     * (in the current implementation there can be at most one)
     *
     * @return list of USB accessories, or null if none are attached.
     */
    @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
    public UsbAccessory[] getAccessoryList() {
        if (mService == null) {
            return null;
        }
        try {
            UsbAccessory accessory = mService.getCurrentAccessory();
            if (accessory == null) {
                return null;
            } else {
                return new UsbAccessory[] { accessory };    //看这里,其实确实只是返回了一个
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    打开accessory,发送或者接收数据,很简单,但返回的是一个ParcelFileDescriptor

    /**
     * Opens a file descriptor for reading and writing data to the USB accessory.
     *
     * <p>If data is read from the {@link java.io.InputStream} created from this file descriptor all
     * data of a USB transfer should be read at once. If only a partial request is read the rest of
     * the transfer is dropped.
     *
     * @param accessory the USB accessory to open
     * @return file descriptor, or null if the accessory could not be opened.
     */
    @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
        try {
            return mService.openAccessory(accessory);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    获取给定函数的functionfs控制文件描述符,其中usb描述符和字符串已写入。函数实现使用文件描述符来处理事件和控制请求。

    也就是说,我们想要控制这些usb操作中的一个功能,我们就用到了这个函数,传进去功能long值,返回它的文件描述符,就可以操作了。

    /**
     * Gets the functionfs control file descriptor for the given function, with
     * the usb descriptors and strings already written. The file descriptor is used
     * by the function implementation to handle events and control requests.
     *
     * @param function to get control fd for. Currently {@link #FUNCTION_MTP} and
     * {@link #FUNCTION_PTP} are supported.
     * @return A ParcelFileDescriptor holding the valid fd, or null if the fd was not found.
     *
     * {@hide}
     */
    public ParcelFileDescriptor getControlFd(long function) {
        try {
            return mService.getControlFd(function);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    这个函数主要是来判断某个Usbdevice是否有系统接入的权限。

    权限可能是通过requestPermission方法临时授予的,或者是用户选择调用者作为设备的默认应用程序授予的。

    针对安卓9及以上版本的客户端,只有在其具有{@link android.Manifest.Permission#CAMERA}权限的情况下,才能授予{@link UsbConstants#USB#class_VIDEO}类USB设备的权限。

    也就是说不能随便访问摄像头,也是加强用户隐私和安全的一种手段。

    /**
     * Returns true if the caller has permission to access the device.
     * Permission might have been granted temporarily via
     * {@link #requestPermission(UsbDevice, PendingIntent)} or
     * by the user choosing the caller as the default application for the device.
     * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that
     * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they
     * have additionally the {@link android.Manifest.permission#CAMERA} permission.
     *
     * @param device to check permissions for
     * @return true if caller has permission
     */
    @RequiresFeature(PackageManager.FEATURE_USB_HOST)
    public boolean hasPermission(UsbDevice device) {
        if (mService == null) {
            return false;
        }
        try {
            return mService.hasDevicePermission(device, mContext.getPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    这个方法主要是为给定包请求访问设备的临时权限。

    如果尚未授予权限,这可能会导致向用户显示系统对话框。成功或失败通过{@link android.app.pendingent}pi返回。

    如果成功,这将授予调用方访问设备的权限,直到设备断开连接

    /**
     * Requests temporary permission for the given package to access the device.
     * This may result in a system dialog being displayed to the user
     * if permission had not already been granted.
     * Success or failure is returned via the {@link android.app.PendingIntent} pi.
     * If successful, this grants the caller permission to access the device only
     * until the device is disconnected.
     *
     * The following extras will be added to pi:
     * <ul>
     * <li> {@link #EXTRA_DEVICE} containing the device passed into this call
     * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether       //这个PendingIntent里面存了两个变量,设备名和是否被授予了权限
     * permission was granted by the user
     * </ul>
     *
     * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that
     * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they
     * have additionally the {@link android.Manifest.permission#CAMERA} permission.
     *
     * @param device to request permissions for
     * @param pi PendingIntent for returning result
     */
    @RequiresFeature(PackageManager.FEATURE_USB_HOST)
    public void requestPermission(UsbDevice device, PendingIntent pi) {
        try {
            mService.requestDevicePermission(device, mContext.getPackageName(), pi);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    授予USB设备权限而不显示系统对话框。只有系统组件才能调用此功能。

    内部的接口,外边的不让用。

    /**
     * Grants permission for USB device without showing system dialog.
     * Only system components can call this function.
     * @param device to request permissions for
     *
     * {@hide}
     */
    public void grantPermission(UsbDevice device) {
        grantPermission(device, Process.myUid());
    }
    

    如果在设备模式下指定的USB功能当前已启用,则返回true。

    /**
     * Returns true if the specified USB function is currently enabled when in device mode.
     * <p>
     * USB functions represent interfaces which are published to the host to access
     * 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) {
        try {
            return mService.isFunctionEnabled(function);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    当连上usb时,设置当前是以什么功能作为连接状态。

    此方法用于在主要USB功能中进行选择,系统可根据其他设置和状态自动激活附加功能,比如adb。

    参数0表示设备正在充电,并且可以为此选择任何适当的功能。

    注意:此函数是异步的,在不应用请求的更改的情况下可能会自动失败。

    /**
     * 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.
     * </p><p>
     * This method is intended to select among primary USB functions.  The system may
     * automatically activate additional functions such as {@link #USB_FUNCTION_ADB}
     * or {@link #USB_FUNCTION_ACCESSORY} based on other settings and states.
     * </p><p>
     * 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 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();
        }
    }
    

    不多说了,和上面的那个方法是一对儿。

    /**
     * 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 long getCurrentFunctions() {
        try {
            return mService.getCurrentFunctions();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    设置屏幕解锁功能,当屏幕解锁时,这些功能将被保留并设置为当前功能。

    零掩码具有关闭此功能的效果,因此屏幕解锁时功能不再改变。

    *注意:当屏幕打开时,此方法将应用给定函数作为当前函数,这是异步的,可能会在不应用请求的更改的情况下无声地失败。

    /**
     * Sets the screen unlocked functions, which are persisted and set as the current functions
     * whenever the screen is unlocked.
     * <p>
     * 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 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 long getScreenUnlockedFunctions() {
        try {
            return mService.getScreenUnlockedFunctions();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    下面的这几个方法是关于端口的操作,都是系统去调用的,用户接触不到。

    getPorts是获取USB物理端口列表。

    getPortStatus是查询端口当前的状态,很简单。

    setPortRoles是设置所需的端口角色组合。

    /**
     * Returns a list of physical USB ports on the device.
     * <p>
     * This list is guaranteed to contain all dual-role USB Type C ports but it might
     * be missing other ports depending on whether the kernel USB drivers have been
     * updated to publish all of the device's ports through the new "dual_role_usb"
     * device class (which supports all types of ports despite its name).
     * </p>
     *
     * @return The list of USB ports, or null if none.
     *
     * @hide
     */
    public UsbPort[] getPorts() {
        if (mService == null) {
            return null;
        }
        try {
            return mService.getPorts();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
     
    /**
     * Gets the status of the specified USB port.
     *
     * @param port The port to query.
     * @return The status of the specified USB port, or null if unknown.
     *
     * @hide
     */
    public UsbPortStatus getPortStatus(UsbPort port) {
        Preconditions.checkNotNull(port, "port must not be null");
     
        try {
            return mService.getPortStatus(port.getId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
     
    /**
     * 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 #ACTION_USB_PORT_CHANGED} broadcast will be sent.
     * </p>
     *
     * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE}
     * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role.
     * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST}
     * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role.
     *
     * @hide
     */
    public void setPortRoles(UsbPort port, int powerRole, int dataRole) {
        Preconditions.checkNotNull(port, "port must not be null");
        UsbPort.checkRoles(powerRole, dataRole);
     
        Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName());
        try {
            mService.setPortRoles(port.getId(), powerRole, dataRole);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^