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_MOUNTED
和ACTION_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盘挂载的虚拟目录,所以我们可以通过查找/mnt
和vfat
的方式来获取挂载状态
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
}
}