Android 7.0 本文章可以参考解决绕过android下apk使用usb设备权限查询相应问题,自动获取usb权限,主要是在Android 7.0系统上,当插入USB 耳机或者音频输入设备的时候,就会报出如下对话框和消息提示,在我们开发的时候很不爽,需要手动去点很麻烦,如下图所示:
提示消息即Toast,当插入USB耳机或者麦时就会弹出“USB音频输入设备接入”,当拔掉时就会弹出“切换之原始的默认通道”
这个问题需要修改系统源码其位置在Android 7.0
/android/device/softwinner/common/addons/framework/audio/java/AudioManagerPolicy.java
这AudioManagerPolicy.java就是就是相关的代码源文件,而在此之前还有个xml文件来说明那就是strings_custom.xml
其实这个位置的方法很简单只要在源码目录下使用命令:
grep 'USB音频输入设备接入' ./ -Rn
就能找到strings_custom.xml,其内容如下所示:
进入鼠标模式
退出鼠标模式
鼠标模式
当前处于鼠标模式
"USB音频输出设备接入"
"可在‘通用设置-高级设置-提示音和通知-音频输出模式‘选择输出通道"
"切换至原始的默认通道"
"USB音频输出设备拔出"
"USB音频输入设备接入"
"USB音频输入设备拔出"
"耳机插入"
"耳机拔出"
"切换至耳机"
"切换至原始的默认通道"
"USB音频输出选择"
"USB音频输出设备已接入,请选择是否切换到USB音频设备输出,\n在 %1$s 秒后自动切换到USB音频设备"
"是"
"否"
"升级提示"
"确定"
"取消"
"错误提示"
看到没有所有字符串对应的变量都列举出来了,在根据对应的字符串变量,来搜索Java源码文件:
grep 'usb_audio_in_plug_in_title' ./ -Rn
这样就找到了AudioManagerPolicy.java,其他Android系统版本也可以用这个方法去做,下面来看这个源码怎么修改,其实很简单,看字面意思就能看懂,先去掉对话框
1.在代码的527行有段方法:private void chooseUsbAudioDeviceDialog(final ArrayList
private void chooseUsbAudioDeviceDialog(final ArrayList usb_device)
{
String str = mCtx.getResources().getString(com.android.internal.R.string.usb_output_message);
//获取对话框的内容,也就是在上面那个xml内usb_output_message对应的:USB音频输出设备已接入,请选择是否切换到USB音频设备输出,\n在 %1$s 秒后自动切换到USB音频设备
alertDialog = new AlertDialog.Builder(mCtx).//创建对话框
setTitle(com.android.internal.R.string.usb_output_title).//设置对话框的标题为"USB音频输出选择"
setMessage(String.format(str, Integer.toString(USB_TOAST_TIME))).
setPositiveButton(com.android.internal.R.string.usb_yes, new DialogInterface.OnClickListener() {//设置当点击“是”按钮的监听时间
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
mAudioManagerEx.setAudioDeviceActive(usb_device, AudioManagerEx.AUDIO_OUTPUT_ACTIVE);//设置为usb为音频输入设备
}
}).
setNegativeButton(com.android.internal.R.string.usb_no, new DialogInterface.OnClickListener() {/设置当点击“否”按钮的监听时间
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
//Log.v(TAG, "setNegativeButton ");
String message = mCtx.getResources().getString(R.string.usb_audio_plug_in_message);
toastPlugInNotification(message, AUDIO_OUT_NOTIFY);
//点击“否”,弹出提示消息:"可在‘通用设置-高级设置-提示音和通知-音频输出模式‘选择输出通道"
}
}).
create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
alertDialog.show();//喷出对话框
new AsyncTask() {
@Override
protected Object doInBackground(Object... arg0) {
int time = USB_TOAST_TIME;//设置10秒等待时间
while(time >= 0 && alertDialog != null && alertDialog.isShowing()){
publishProgress(time);
try {
Thread.sleep(1000);
} catch(Exception e) {
// do nothing
}
time--;
}
return null;
}
@Override
protected void onPostExecute(Object result) {//当超过10秒没有点击时触发
super.onPostExecute(result);
if (alertDialog != null && alertDialog.isShowing()) {
alertDialog.dismiss();
mAudioManagerEx.setAudioDeviceActive(usb_device, AudioManagerEx.AUDIO_OUTPUT_ACTIVE);//设置为USB 设备为输入设备,这个逻辑很关键,是默认的情况,当去掉对话框时这个陆机要保留
alertDialog = null;
}
}
@Override
protected void onProgressUpdate(Object... values) {
super.onProgressUpdate(values);
int time = (Integer)values[0];
String str = mCtx.getResources().getString(com.android.internal.R.string.usb_output_message);
if(alertDialog != null)
alertDialog.setMessage(String.format(str, Integer.toString(time)));
}
}.execute();
}
根据上面的对话框的代码,我们知道,对话框是默认点击“是”按钮的因此,我们需要在代码中也要保持这个逻辑:
那么这个对话框方法调用的位置在方法handleExternalDevice内,这个代码看着很长,但很简单,我就不分析了,把主要的贴出来,在634行调用了这个方法因此只要注释掉并添加一行:
//chooseUsbAudioDeviceDialog(audio_out);
mAudioManagerEx.setAudioDeviceActive(audio_out, AudioManagerEx.AUDIO_OUTPUT_ACTIVE);
添加的就是跳过对话框而直接设置usb音频设备为输入设备
2.去掉相关的提示信息
在上面去掉对话框是就已经去掉了
对方法handleExternalDevice分析可知,每一个对应的消息都会调用方法 toastPlugInNotification和toastPlugOutNotification
这两个方法从字面意思就知道是:挂在消息通知和挂出消息通知,源码如下:
private void toastPlugOutNotification(String title,String mng, int id){
NotificationManager notificationManager = (NotificationManager) mCtx
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
handleToastMessage(mng);
}
private void toastPlugInNotification(String title, int id){
Notification notification = new Notification(com.android.internal.R.drawable.stat_sys_data_usb,
title,System.currentTimeMillis());
String contentTitle = title;
String contextText = title;
notification.setLatestEventInfo(mCtx, contentTitle, contextText, null);
notification.defaults &= ~Notification.DEFAULT_SOUND;
notification.flags = Notification.FLAG_AUTO_CANCEL;
NotificationManager notificationManager = (NotificationManager) mCtx
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, notification);
handleToastMessage(title);
}
其实到这里解决消息通知的方法就有很多了,你可以在AudioManagerPolicy.java搜索这两个方法,只要调用了这两个方法,就统统注释了就可以了,但是我在此的 做法是去研究这段代码,这两个代码内都有方法handleToastMessage,而这个方法如下:
private void handleToastMessage(String message){
if(mHandler == null) return;
Message mng = mHandler.obtainMessage();
mng.obj = message;
mHandler.sendMessage(mng);//发送消息
}
然后去找mHandler如下:
private void toastMessage(String message){//产生Toast,并喷发出来
Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show();
}
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
String message = (String)msg.obj;
//toastMessage(message);//屏蔽这个Toast的喷发
}
};
因此我们就可以找到着个最内层的一句话,Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show(); 屏蔽掉,所有的相关音频输入的消息通知都没有了