转载请注明:http://blog.youkuaiyun.com/hubbybob1/article/details/50263925
很多android的应用在使用usb设备时,尤其是usb摄像头,前段时间编写了一个有关usb设备的apk,但是在使用时总是会跳出系统对话框,用户体验很差,如下图所示,所以一直想要解决这个问题,在网上说了很多办法,但是我的能力有限都没有走通,在同事的帮助下终于解决的这个问题,非常感谢他们无私的帮助,在此记录下来。
希望android设备中,自动获得操作usb设备的权限。不希望弹出对话框让用户点击,才允许有操作权限。即,不需要用户操心usb操作权限的事情。
一,首先解决这个问题,需要学习这方面的知识,小编是个小白,所以只能在网上学习这方面的知识,那么来提供几个网站的学习 android usb主机模式:
如果英文看的不太懂,可以去看这个翻译过的文章,还是很不错的:
http://blog.youkuaiyun.com/wizardmly/article/details/8350137
当然下面这位仁兄也给出了很好的学习的网站,但是他最后的答案是无法绕开这个对话框,最后也不了了之了:http://www.crifan.com/android_try_to_auto_grant_usb_device_operation_permission/
http://www.crifan.com/android_as_usb_host_detect_usb_device_insert_attached/
大概了解之后我们就能发现弹出这个对话框的关键语句就是代码中的
myself.mUsbManager.requestPermission(device, mPermissionIntent); // Wait for permission with a timeout.
myself.deviceToFdMap.get(mapKey).wait(Constants.usbDevicePermissionTimeout);
这句话中的.requestPermission是必须要有的,就是询问usb权限的作用。
那怎么解决这问题呢,起初我定了两个方案:
方案一:在代码中绕给这个对话框,使其默认允许权限。
方案二:在android源码中去掉这个对话框。
下面振幅这两种方法来阐述:
二,在apk中解决这个问题
首先这个方案我没有走通,在此只能提供一个解决的方案思路也是参考了被人的博客来做的:
http://stackoverflow.com/questions/13726583/bypass-android-usb-host-permission-confirmation-dialog
这是国外的网站,写的很不错,但是里面谈到由于android版本的不同,可能代码不同,其解决方案可以是针对android版本4.0.3和4.2.2的。有兴趣的可以研究一下,方法是个好方法,操作起来也不麻烦的,但是由于我是小白,没办法,不会修改
那么还有一个翻译过的博客:http://blog.youkuaiyun.com/mlj1668956679/article/details/14122787
也不知道作者有没有走通,反正我按他的方法调试了,无法解决,主要原因是我没有搞懂,他在广播接收器里面的有段代码:
new OpenTask().execute(device);
}
} else {
if (device != null) {
logMsg("Permission no EXTRA_PERMISSION_GRANTED for device "
+ device.getDeviceName());
}
}
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
synchronized (this) {
// Close reader
/* logMsg("Closing reader..."); */
new CloseTask().execute();
}
}
}
};
new OpenTask().execute(device);这句话是干什么的,没有看懂。
因此在apk中无法解决,那只好到系统里面看看了.
三,android中解决问题
这个方法已经实现了,其实很简单,那么一步一步的来看吧
A,首先为了查看到这个对话框,我们可以使用eclipse下的一个工具来查看那就是/sdk/tools/hierarchyviewer,,HierarchyViewer能够可视化的角度直观地获得UI布局设计结构和各种属性的信息,帮助 我们优化布局设计,就是我们在操作adroid系统时能在这里面看到信息如线图所示:
可以看到当上面的对话框弹出时,这个工具里面都会多出这句话:
com.android.systemui/com.android.systemui.usb.UsbPermissionActivity
这就是应用的位置,当然我们也可以是用grep命令来查找这个对话框的.xml文件,进入android源码然后输入命令:
grep '默认情况下用于' ./ -Rn
其实我们可以直接在frameworks目录下查找,这样会节省好多时间,查找的结果是:
那么这个对话框的路径在
/android/frameworks/base/packages/SystemUI/res/values-zh-rCN/strings.xml
其相关的内容如下:
<string name="always_use_device" msgid="1450287437017315906">"默认情况下用于该 USB 设备"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"允许应用“<xliff:g id="APPLICATION">%1$s</xliff:g>”访问该 USB 设备吗?"
B,然后我们根据eclipse工具hierarchyviewer找到的应用路径找到.java文件来修改,其位置在:
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
这就是那个讨厌的对话框对应的java程序,那么来看看这个程序如下:
public class UsbPermissionActivity extends AlertActivity
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
private static final String TAG = "UsbPermissionActivity";
private CheckBox mAlwaysUse;
private TextView mClearDefaultHint;
private UsbDevice mDevice;
private UsbAccessory mAccessory;
private PendingIntent mPendingIntent;
private String mPackageName;
private int mUid;
private boolean mPermissionGranted;
private UsbDisconnectedReceiver mDisconnectedReceiver;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
mPackageName = intent.getStringExtra("package");
PackageManager packageManager = getPackageManager();
ApplicationInfo aInfo;
try {
aInfo = packageManager.getApplicationInfo(mPackageName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "unable to look up package name", e);
finish();
return;
}
String appName = aInfo.loadLabel(packageManager).toString();
这段代码是获取应用的包名,我们可以通过包名对比来决定是否弹出对话框。
final AlertController.AlertParams ap = mAlertParams;
ap.mIcon = aInfo.loadIcon(packageManager);
ap.mTitle = appName;
if (mDevice == null) {
ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}
ap.mPositiveButtonText = getString(android.R.string.ok);
ap.mNegativeButtonText = getString(android.R.string.cancel);
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this;
// add "always use" checkbox
LayoutInflater inflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
if (mDevice == null) {
mAlwaysUse.setText(R.string.always_use_accessory);
} else {
mAlwaysUse.setText(R.string.always_use_device);
}
mAlwaysUse.setOnCheckedChangeListener(this);
mClearDefaultHint = (TextView)ap.mView.findViewById(
com.android.internal.R.id.clearDefaultHint);
mClearDefaultHint.setVisibility(View.GONE);
在上面的代码就是对话框了,接下来就是要修该的东西了
setupAlert();
对就是这句话,代码堆里寻他千百处,他就在灯火栏栅处,这句话就是弹出对话的意思,那么怎么修改呢,如下:
if(!mPackageName.equals("com.vaultmicro.camerafi"))//双引号内为你要给权限的包名
setupAlert();
else
{
mPermissionGranted = true;
finish();
}
这里函数finish();很重要,如果不加上的话会出现下面的内容
就是“系统用户界面”,虽然你的apk已经获得权限,但是出这个对话框还是很烦人的。
上面的代码是指定你的apk获取权限,当然你也可以使所有的类似usb权限的apk都获得同样的权限,那么就可以如下编写:
//setupAlert();//不使用窗口
mPermissionGranted = true;
finish();
这样所有的软件都获取了uab权限,是不是很简单啊。
这种处理方法来自这个文件的按钮点击回应函数
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
mPermissionGranted = true;
}
finish();
}
那么到这里usb权限窗口问题就解决了,自己去编译源码和android源码吧,第一次编译需要很长时间,再次感谢帮助过我的同事和朋友。