判断Android tv U盘挂载不同于判断手机是否连接usb,我们没办法直接使用usbDevice类进行操作。
只能通过判断action动作,在android中,插入U盘的时候,kernal内核会向上发出action动作,让应用层来获取。
在代码中添加以下代码段,来监听U盘挂载:
intentFilter.addAction(Intent.ACTION_USB_DISK_MOUNTED);
intentFilter.addAction(Intent.ACTION_USB_DISK_UNMOUNTED);
intentFilter.addAction(Intent.ACTION_USB_DISK_UNMOUNTED);
intentFilter.addDataScheme("file");
this.registerReceiver(usbReceiver, intentFilter);
注意:intentFilter.addDataScheme(“file”)–》是必须添加的,不然没办法监听action动作。
添加完成之后,就可以使用广播来进行动作监听事件触发:
private BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
List infos = UsbDeviceManager.getAvaliableStorage(UsbDeviceManager.listAllStorage(arg0));
if (infos != null) {
if (arg1.getAction().equals(Intent.ACTION_USB_DISK_MOUNTED)) {
infos = UsbDeviceManager.getAvaliableStorage(UsbDeviceManager.listAllStorage(arg0));
for(StorageItemEntity sie:infos){
Log.i("LWL",sie.toString());
}
} else if (arg1.getAction().equals(Intent.ACTION_USB_DISK_UNMOUNTED)) {
Log.v(TAG, "ACTION_USB_DISK_UNMOUNTED::::" + arg1.getAction());
List aliveUsb = UsbDeviceManager.getAvaliableStorage(UsbDeviceManager.listAllStorage(arg0));
for(StorageItemEntity sie:aliveUsb){
Log.i("LWL",sie.toString());
}
}
}
}
};
StorageItemEntity类是用来存放所有挂载的U盘的信息:
/**
* @author 李文烙
*
*/
public class StorageItemEntity {
//存储器的地址
private String uri;
//存储器的类型
private int type = 0;
//U盘的名字
private String manufactorName = null;
//存储器的状态
private String state;
//是否可以移除
private boolean isRemoveable;
public StorageItemEntity(){
}
public StorageItemEntity(String path){
this.uri=path;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getManufactorName() {
return manufactorName;
}
public void setManufactorName(String manufactorName) {
this.manufactorName = manufactorName;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public boolean isRemoveable() {
return isRemoveable;
}
public void setRemoveable(boolean removeable) {
isRemoveable = removeable;
}
@Override
public String toString() {
return "StorageItemEntity=[ uri="+this.uri+",type="+type+",manufactorName="+manufactorName+",state="+state+",isRemoveable="+isRemoveable;
}
}
通过以上的代码并不能实现U盘挂载的监听,我们还需要添加一个工具类,用来判断所有挂载的磁盘以及现在处于挂载状态的U盘(未移除),:
/**
* author: 李文烙
* date: 2017/11/17
* annotation
*/
public class UsbDeviceManager {
private static final String TAG = "UsbDeviceManager";
private static UsbDeviceManager usbManager;
public static UsbDeviceManager getUsbDeviceManager()
{
if (usbManager != null) {
return usbManager;
}
usbManager = new UsbDeviceManager();
return usbManager;
}
public static List listAllStorage(Context context) {
ArrayList storages = new ArrayList();
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
try {
Class>[] paramClasses = {};
Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses);
Object[] params = {};
Object[] invokes = (Object[]) getVolumeList.invoke(storageManager, params);
if (invokes != null) {
StorageItemEntity info = null;
Log.i(TAG,"getVolumeList"+getVolumeList.getName());
for (int i = 0; i < invokes.length; i++) {
Object obj = invokes[i];
Method getPath = obj.getClass().getMethod("getPath", new Class[0]);
String path = (String) getPath.invoke(obj, new Object[0]);
info = new StorageItemEntity(path);
Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);
String state = (String) getVolumeState.invoke(storageManager, info.getUri());
info.setState(state);
Method isRemovable = obj.getClass().getMethod("isRemovable", new Class[0]);
info.setRemoveable(((Boolean) isRemovable.invoke(obj, new Object[0])).booleanValue());
Log.i(TAG,info.toString());
storages.add(info);
}
}
} catch (Exception e) {
e.printStackTrace();
}
storages.trimToSize();
return storages;
}
public static List getAvaliableStorage(List infos) {
List storages = new ArrayList();
for (StorageItemEntity info : infos) {
File file = new File(info.getUri());
Log.i(TAG+"LWL",info.toString());
Log.i(TAG+"LWL","file"+file.exists()+file.isDirectory()+file.canWrite());
if ((file.exists()) && (file.isDirectory())) {
if (info.getState() != null) {
if (info.getState().equals("mounted") && info.isRemoveable()) {
storages.add(info);
}
}
}
}
return storages;
}
}
现在在Android sdk中已经将原本可以直接调用的getVolumeState方法给隐藏了,所以我们只能通过反射的方法去调用@hide的方法,源码如下:(有兴趣的同学可以直接查看Android sdk的源码):
第一个:android.os.storage.StorageManager
/**
* Returns list of all mountable volumes.
* @hide
*/
public StorageVolume[] getVolumeList() {
if (mMountService == null) return new StorageVolume[0];
try {
Parcelable[] list = mMountService.getVolumeList();
if (list == null) return new StorageVolume[0];
int length = list.length;
StorageVolume[] result = new StorageVolume[length];
for (int i = 0; i < length; i++) {
result[i] = (StorageVolume)list[i];
}
return result;
} catch (RemoteException e) {
Log.e(TAG, "Failed to get volume list", e);
return null;
}
}
//在这里返回的是一个StorageVolume[]对象
第二个:android.os.storage.StorageVolume(这个类就是获取U盘挂载状态的核心,该类同样被隐藏)
/**
* Description of a storage volume and its capabilities, including the
* filesystem path where it may be mounted.
*
* @hide
*/
public class StorageVolume implements Parcelable {
// TODO: switch to more durable token
private int mStorageId;
private final File mPath;
private final int mDescriptionId;
private final boolean mPrimary;
private final boolean mRemovable;
private final boolean mEmulated;
private final int mMtpReserveSpace;
private final boolean mAllowMassStorage;
/** Maximum file size for the storage, or zero for no limit */
private final long mMaxFileSize;
/** When set, indicates exclusive ownership of this volume */
private final UserHandle mOwner;
private String mUuid;
private String mUserLabel;
private String mState;
// StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
// ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED,
// ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
public StorageVolume(File path, int descriptionId, boolean primary, boolean removable,
boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize,
UserHandle owner) {
mPath = path;
mDescriptionId = descriptionId;
mPrimary = primary;
mRemovable = removable;
mEmulated = emulated;
mMtpReserveSpace = mtpReserveSpace;
mAllowMassStorage = allowMassStorage;
mMaxFileSize = maxFileSize;
mOwner = owner;
}
private StorageVolume(Parcel in) {
mStorageId = in.readInt();
mPath = new File(in.readString());
mDescriptionId = in.readInt();
mPrimary = in.readInt() != 0;
mRemovable = in.readInt() != 0;
mEmulated = in.readInt() != 0;
mMtpReserveSpace = in.readInt();
mAllowMassStorage = in.readInt() != 0;
mMaxFileSize = in.readLong();
mOwner = in.readParcelable(null);
mUuid = in.readString();
mUserLabel = in.readString();
mState = in.readString();
}
public static StorageVolume fromTemplate(StorageVolume template, File path, UserHandle owner) {
return new StorageVolume(path, template.mDescriptionId, template.mPrimary,
template.mRemovable, template.mEmulated, template.mMtpReserveSpace,
template.mAllowMassStorage, template.mMaxFileSize, owner);
}
/**
* Returns the mount path for the volume.
*
* @return the mount path
*/
public String getPath() {
return mPath.toString();
}
public File getPathFile() {
return mPath;
}
/**
* Returns a user visible description of the volume.
*
* @return the volume description
*/
public String getDescription(Context context) {
return context.getResources().getString(mDescriptionId);
}
public int getDescriptionId() {
return mDescriptionId;
}
public boolean isPrimary() {
return mPrimary;
}
/**
* Returns true if the volume is removable.
*
* @return is removable
*/
public boolean isRemovable() {
return mRemovable;
}
/**
* Returns true if the volume is emulated.
*
* @return is removable
*/
public boolean isEmulated() {
return mEmulated;
}
/**
* Returns the MTP storage ID for the volume.
* this is also used for the storage_id column in the media provider.
*
* @return MTP storage ID
*/
public int getStorageId() {
return mStorageId;
}
/**
* Do not call this unless you are MountService
*/
public void setStorageId(int index) {
// storage ID is 0x00010001 for primary storage,
// then 0x00020001, 0x00030001, etc. for secondary storages
mStorageId = ((index + 1) << 16) + 1;
}
/**
* Number of megabytes of space to leave unallocated by MTP.
* MTP will subtract this value from the free space it reports back
* to the host via GetStorageInfo, and will not allow new files to
* be added via MTP if there is less than this amount left free in the storage.
* If MTP has dedicated storage this value should be zero, but if MTP is
* sharing storage with the rest of the system, set this to a positive value
* to ensure that MTP activity does not result in the storage being
* too close to full.
*
* @return MTP reserve space
*/
public int getMtpReserveSpace() {
return mMtpReserveSpace;
}
/**
* Returns true if this volume can be shared via USB mass storage.
*
* @return whether mass storage is allowed
*/
public boolean allowMassStorage() {
return mAllowMassStorage;
}
/**
* Returns maximum file size for the volume, or zero if it is unbounded.
*
* @return maximum file size
*/
public long getMaxFileSize() {
return mMaxFileSize;
}
public UserHandle getOwner() {
return mOwner;
}
public void setUuid(String uuid) {
mUuid = uuid;
}
public String getUuid() {
return mUuid;
}
/**
* Parse and return volume UUID as FAT volume ID, or return -1 if unable to
* parse or UUID is unknown.
*/
public int getFatVolumeId() {
if (mUuid == null || mUuid.length() != 9) {
return -1;
}
try {
return Integer.parseInt(mUuid.replace("-", ""), 16);
} catch (NumberFormatException e) {
return -1;
}
}
public void setUserLabel(String userLabel) {
mUserLabel = userLabel;
}
public String getUserLabel() {
return mUserLabel;
}
public void setState(String state) {
mState = state;
}
public String getState() {
return mState;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof StorageVolume && mPath != null) {
StorageVolume volume = (StorageVolume)obj;
return (mPath.equals(volume.mPath));
}
return false;
}
@Override
public int hashCode() {
return mPath.hashCode();
}
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
dump(new IndentingPrintWriter(writer, " ", 80));
return writer.toString();
}
public void dump(IndentingPrintWriter pw) {
pw.println("StorageVolume:");
pw.increaseIndent();
pw.printPair("mStorageId", mStorageId);
pw.printPair("mPath", mPath);
pw.printPair("mDescriptionId", mDescriptionId);
pw.printPair("mPrimary", mPrimary);
pw.printPair("mRemovable", mRemovable);
pw.printPair("mEmulated", mEmulated);
pw.printPair("mMtpReserveSpace", mMtpReserveSpace);
pw.printPair("mAllowMassStorage", mAllowMassStorage);
pw.printPair("mMaxFileSize", mMaxFileSize);
pw.printPair("mOwner", mOwner);
pw.printPair("mUuid", mUuid);
pw.printPair("mUserLabel", mUserLabel);
pw.printPair("mState", mState);
pw.decreaseIndent();
}
public static final Creator CREATOR = new Creator() {
@Override
public StorageVolume createFromParcel(Parcel in) {
return new StorageVolume(in);
}
@Override
public StorageVolume[] newArray(int size) {
return new StorageVolume[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mStorageId);
parcel.writeString(mPath.toString());
parcel.writeInt(mDescriptionId);
parcel.writeInt(mPrimary ? 1 : 0);
parcel.writeInt(mRemovable ? 1 : 0);
parcel.writeInt(mEmulated ? 1 : 0);
parcel.writeInt(mMtpReserveSpace);
parcel.writeInt(mAllowMassStorage ? 1 : 0);
parcel.writeLong(mMaxFileSize);
parcel.writeParcelable(mOwner, flags);
parcel.writeString(mUuid);
parcel.writeString(mUserLabel);
parcel.writeString(mState);
}
}