Android 监听U盘OTG挂载状态

Android 监听U盘OTG挂载状态

本篇博客介绍下在Android系统中,如何监听和获取U盘OTG挂载状态

在Android中插入U盘时,系统会先准备U盘并检查是否有错误,检查完成后才会把U盘挂载到系统中。因此U盘插入和检查U盘错误这个两个阶段都不能算是U盘挂载状态,我们要获取的状态是检查完成后挂载的状态,也就是USB_DISK_MOUNTED这个广播

class UsbDiskReceiver(private val onUsbDiskMountState: ((Int) -> Unit)? = null) :
    BroadcastReceiver() {

    companion object {
        private val TAG = UsbDiskReceiver::class.java.simpleName
        const val USB_DISK_MOUNTED = 1
        const val USB_DISK_UNMOUNTED = 2
    }

    override fun onReceive(context: Context?, intent: Intent?) {
        val action = intent?.action

        Log.i(TAG, "onReceive: $action")

        if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
            onUsbDiskMountState?.invoke(USB_DISK_MOUNTED)
            Log.i(TAG, "onReceive: media mounted")
        } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
            onUsbDiskMountState?.invoke(USB_DISK_UNMOUNTED)
            Log.i(TAG, "onReceive: media unmounted")
        }
    }
}

在onCreate中注册广播,在onDestroy中注销广播。有一点要注意:除了ACTION_MEDIA_MOUNTEDACTION_MEDIA_UNMOUNTED之外还需要添加usbDeviceStateFilter.addDataScheme("file")这句,否则接收不到广播

private lateinit var mUsbReceiver: BroadcastReceiver

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    mUsbReceiver = UsbDiskReceiver { usbDiskMountState ->
        when (usbDiskMountState) {
            UsbDiskReceiver.USB_DISK_MOUNTED -> // todo otg is mounted
            UsbDiskReceiver.USB_DISK_UNMOUNTED -> // todo otg is unmounted
        }
    }

    val usbDeviceStateFilter = IntentFilter()
    usbDeviceStateFilter.addAction(Intent.ACTION_MEDIA_MOUNTED)
    usbDeviceStateFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED)
    usbDeviceStateFilter.addDataScheme("file")
    registerReceiver(mUsbReceiver, usbDeviceStateFilter)
}

override fun onDestroy() {
    super.onDestroy()
    unregisterReceiver(mUsbReceiver)
}

USB_DISK_MOUNTED广播不是粘性广播,也就是说如果在注册广播前U盘就已经是挂载状态的话,是接收不到广播的,所以需要通过查看设备事件的方式来获取状态

U盘在挂载后会在/proc/mounts文件中生成特定的日志,比如:

/dev/block/vold/public:8,1 /mnt/media_rw/A23D-1C08 vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1023,gid=1023,fmask=0007,dmask=0007,allow_utime=0020,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0

我们可以从日志中找到类似/mnt/media_rw/A23D-1C08 vfat的信息,这条信息表示的就是U盘挂载的虚拟目录,所以我们可以通过查找/mntvfat的方式来获取挂载状态

public String getUsbDiskPath() {
    String filePath = "/proc/mounts";
    File file = new File(filePath);
    List<String> lineList = new ArrayList<>();
    try (InputStream inputStream = new FileInputStream(file);
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            if (line.contains("vfat")) {
                lineList.add(line);
            }
        }
    } catch (IOException e) {
        Log.e(TAG, "searchPath: ", e);
    }
    if (lineList.size() > 0) {
        String editPath = lineList.get(lineList.size() - 1);
        int start = editPath.indexOf("/mnt");
        int end = editPath.indexOf(" vfat");
        return editPath.substring(start, end);
    }
    return null;
}

在onCreate中判断即可

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    if (getUsbDiskPath() != null) {
        // todo otg is mounted
    }
}

参考

http://fengwanxingzhou.coding.me/Android8.0%E7%9B%91%E5%90%ACU%E7%9B%98%E6%8F%92%E5%85%A5%E6%8B%94%E5%87%BA%E4%BA%8B%E4%BB%B6/

https://www.jianshu.com/p/b2425efca483

发布了174 篇原创文章 · 获赞 119 · 访问量 55万+

猜你喜欢

转载自blog.csdn.net/lj402159806/article/details/103098736