Android OTG U盘开发相关文档
Android OTG U盘相关文档
Media Team
2017-03-02
目录
Android OTG U盘相关文档.. 1
1. 使用OTG模 式 播放U盘音乐… 4
1.1需要完成的任务列表.. 4
1.2代码参照… 4
2. 预研Android USB Digital Audio. 9
参考文档.. 9
车机中,可能需要对支持以下几种音频输入模式,并且拥有优先级,根据自已的使用经验播放音乐的优先级如下
1. 苹果底座
2. Aux-in
3. U盘
4. 蓝牙
注:此文档只记录U盘的使用方式
1. 使用OTG模 式 播放U盘音乐
1.1需要完成的任务列表
1. 需要的权限
2. 监控OTG USB的插入和弹出
3. 得到U盘挂载的路径
4. 通知系统媒体管理器扫描系统文件
5. 通过ContentProvider得到U盘上所有音频文件的ID3标签信息(包括,标题,艺术家,封面),显示 在播放器界面上,并进行播放
6. 处理USB的弹出事件
1.2代码参照
1. 需要的权限:
经过测试需要系统签名,
Mainifest添加 android:sharedUserId=”android.uid.system”
使用权限:
<uses-permission
android:name=”android.permission.WRITE_MEDIA_STORAGE” />
使用功能:
<uses-feature
android:name=”android.hardware.usb.host” />
<uses-permission android:name=”android.permission.USB_PERMISSION” />
2. 全局的广播接收器
<!–USB–>
<receiver android:name=”.receiver.USBBroadcastReceiver”>
<intent-filter>
<action android:name=”android.hardware.usb.action.USB_DEVICE_ATTACHED” />
<action android:name=”android.hardware.usb.action.USB_DEVICE_DETACHED” />
</intent-filter>
</receiver>
android.hardware.usb.action.USB_DEVICE_ATTACHED : USB的插入
android.hardware.usb.action.USB_DEVICE_DETACHED
: USB弹出
具体的BroadcastReceiver
public class USBBroadcastReceiver extends
BroadcastReceiver {
@Override
public void onReceive(final
Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED))
{
Toast.makeText(context, “USB插入”, Toast.LENGTH_SHORT).show();
Intent
scanService = new Intent(context, ScanUSBService.class);
scanService.setAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
context.startService(scanService);
} else
if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED))
{
Toast.makeText(context, “USB拨出”, Toast.LENGTH_SHORT).show();
intent.setAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
Intent
scanService = new Intent(context, ScanUSBService.class);
scanService.setAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
context.startService(scanService);
}
}
}
Service中处理插入和弹出事件写法:
@Override
protected void onHandleIntent(Intent intent) {
if (intent == null)
return;
String action = intent.getAction();
NextevLog.d(“mp3”, “action=” + action);
if (TextUtils.isEmpty(action))
return;
if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED) || action.equals(Intent.ACTION_BOOT_COMPLETED)) {
MediaCenterApplication.getInstance().mHandler.postDelayed(new Runnable() {
@Override
public void run() {
onInsertUSB();
}
}, 3000);
} else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
onEjectUSB();
}
}
3. 得到U盘的挂载路径
暂时无法通过公开的API得到U盘的挂载路径,只能通过Framework的私有API得到路径,需要通过系统层去做
com.android.systemui. StorageNotification
系统层私有@Hide API : VolumeInfo
type=PUBLIC diskId=disk:8_16
partGuid=null mountFlags=0 mountUserId=0
state=MOUNTED
fsType=vfat fsUuid=A884-8764
fsLabel=usbdisk
path=/mnt/media_rw/A884-8764 internalPath=/mnt/media_rw/
以下是VolumeInfo中的路径的字段
public final String id;
public final int type;
public final DiskInfo disk;
public final String partGuid;
public int mountFlags = 0;
public int mountUserId = -1;
public int state = STATE_UNMOUNTED;
public String fsType;
public String fsUuid;
public String fsLabel;
public String path;
public String internalPath; //路径地址
注:在三星平板上没有系统权限不能动态得到路径,使用固定的路径
String mUSBRootDirPath =
“/mnt/media_rw/A884-8764/”;
4. 得到U盘 中所有文件的url,并添加到系统媒体管理器中扫描
private void getMp3File(final List<File> list, File file) {
file.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
String name = file.getName();
NextevLog.d(“mp3”, “扫描文件” + name);
int i = name.lastIndexOf(“.”);
if (i != -1) {
name = name.substring(i);
if (name.equalsIgnoreCase(“.mp3”)) {
list.add(file);
return true;
}
} else if (file.isDirectory()) {
getMp3File(list, file);
}
return false;
}
});
}
void scanOneFile() {
if (files.size() < 1)
return;
String[] mimeTypes = new String[]{“audio/mpeg”};
MediaScannerConnection.scanFile(this, new String[]{files.get(i).getAbsolutePath()}, mimeTypes, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
if (i == files.size() – 1) {
onScanFinished();
} else {
i++;
scanOneFile();
}
}
});
}
scanMusic()
public List<TrackItem> scanMusic() {
List<TrackItem> list = new ArrayList<>();
Cursor cursor = this.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
if (cursor == null) {
return list;
}
while (cursor.moveToNext()) {
// 是否为音乐
int isMusic = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC));
NextevLog.e(“mp3”, “file.isMusic=” + isMusic);
if (isMusic == 0) {
continue;
}
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
String title = cursor.getString((cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String unknown = this.getString(R.string.unknown_album_name);
artist = artist.equals(“<unknown>”) ? unknown : artist;
String album = cursor.getString((cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)));
long duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
String uri = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
long albumId = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
String coverUri = getCoverUri(this, albumId);
String fileName = cursor.getString((cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)));
long fileSize = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE));
String year = cursor.getString((cursor.getColumnIndex(MediaStore.Audio.Media.YEAR)));
String filePath = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
// depend on mediaType add music
if (filePath.contains(“mnt/media_rw/A884-8764”)) {
TrackItem music = new TrackItem();
music.setId(id);
music.setType(SoundType.LOCAL_TRACK.intValue());
music.setTrackTitle(title);
music.setArtistName(artist);
music.setAlbumName(album);
music.setDuration(duration);
music.setLocalPath(uri);
music.setCoverUrl(coverUri);
list.add(music);
}
}
cursor.close();
return list;
}
2. 预研Android USB Digital Audio
如果想让车机上使用苹果的lighting的底座接口,需要两个条件
条件一:需要苹果官方的授权,市面上出售的支持苹果底座的音箱,包括飞利普和部分汽车的车机系统(like 别克)),有了苹果的授权,可以USB连上苹果手机后,直接播放苹果手机里的音乐,优先极高于蓝牙连接
条件二: 开发针对Lighting底座的协议的硬件
另外,Android设备是可以直接通过otg来当成一个音频输入或者输出设备的,在
在三星平板上通过OTG线连接苹果手机尝试通过Android输出苹果的音频,尝试失败,应该是不能如此简单的连接,因为与我们车机硬件不匹配,不再进入下一步更深入的调研
参考文档
1. https://developer.android.com/guide/topics/connectivity/usb/host.html
2. https://source.android.com/devices/audio/usb.html
3. 在 Nexus 上使用 USB 主机模式录制和播放音频
https://support.google.com/nexus/answer/6127700