Android USB預設連線模式為MTP
很多時候,手機專案開發,客戶都要求配置USB的預設連線方式,但是在Android 6.0以及之後的版本就直接配置USB連線模式,看到的USB連線模式還是僅充電,而這是google的預設設計。那麼對於這個問題,也看了很多網上的一些解法,如:Android 5.0可以直接配置預設值,6.0就不可行了。另外,還有在USB連線的時候進行設定,當連線之後就執行一次設定USB連線模式,將MTP設定為當前連線模式,這樣的做法在7.0上面也是可以的。
事實上,當僅充電的時候,檢視當前USB模式的配置,就算是mtp,但是還是沒有顯示SD卡和內部儲存器,主要是一個標誌的問題。
現有的一種解法
那麼這裡先說一下在連線USB的情況下,執行一次USB連線模式的設定,這裡有一位大牛的方法,並且提到Android 6.0以前的做法,Android 6.0 USB連線模式預設選為MTP ,大家去參考學習一下,那麼我說一下這位大牛的改法,在Android 6.0和7.0上面修改後不同的一個地方:
Android版本 | 在鎖屏的情況下 | 在解鎖的情況下 |
---|---|---|
6.0 | 僅充電 | MTP |
7.0 | MTP | MTP |
對於這樣的解法,我們的測試就提了一個不安全的bug,沒有解鎖就能直接訪問SD卡、內部儲存器的資料,這是不安全的。那好像也說得有道理,那麼就改。但是這個不解鎖能訪問儲存器的功能,可能又符合某些公司的客戶需求。
公司中6.0的解法
對於上面的解法不怎麼像6.0的行為,接著我就去看了一下,我們公司以前Android 6.0是怎麼修改的,是直接修改了值,將這個值修改後,就能顯示SD卡、內部儲存器了。
修改檔案frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
public class UsbDeviceManager {
···省略很多程式碼···
private boolean mConfigured;
//modified in 2017-05-22 start
//解鎖資料,連線電腦,就能看到預設連線模式為MTP
private boolean mUsbDataUnlocked = true;
//modified in 2017-05-22 end
private String mCurrentFunctions;
private String mDefaultFunctions;
······
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
mUsbConfigured = mConfigured;
if (!mConnected) {
//modified in 2017-05-22 start
//default usb connect mode as mtp
// When a disconnect occurs, relock access to sensitive user data
//斷開連線的時候,保持當前連線模式,下次連線的時候還是MTP
mUsbDataUnlocked = true;
//modified in 2017-05-22 end
}
updateUsbNotification();
updateAdbNotification();
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
} else if (!mConnected) {
//modified in 2017-05-22 start
//change default usb connect mode as mtp,do not restore
// 這裡不恢復預設連線方式,保持保持當前的連線模式
setEnabledFunctions(null, true);
//modified in 2017-05-22 end
}
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded();
updateUsbFunctions();
}
······
}
上面的這種修改方式比較簡單,在android6.0和7.0上都是可以的,但是還是有差異:
Android版本 | 在鎖屏的情況下 | 在解鎖的情況下 |
---|---|---|
6.0 | 僅充電 | MTP |
7.0 | MTP | MTP |
這中修改方式的最終結果還是跟上面那位大牛的修改方式表現結果一致。那麼應該說是Google在7.0上又修改了這一部分的程式碼,使用公司以前6.0的改法,還是不行。
現在Android 7.0的解法
但是還是對不上公司測試提的問題,那還是需要接續修改。那就仔細看看這類,再上網瞭解一下USB連線模式這塊,這一塊還是很深的...,涉及硬體的,都是稍微複雜一點,還要跟底層通訊什麼的,有一點大概的瞭解之後,再回來解決一下這個問題,那麼從切換USB連線模式的上層實現,那麼就是修改mUsbDataUnlocked的值,應該說是在適當的時候修改mUsbDataUnlocked的值,那就看到USB連線模式是MTP,那麼下面分析一下有幾種情況需要改變:
- 手機是鎖屏情況下連線USB,連線模式是僅充電。
- 手機是解鎖的情況下連線USB,連線模式是MTP。
- 手機熄屏的情況下斷開USB,連線方式要更新為僅充電。
- 手機解鎖的情況下斷開USB,連線方式要更新為僅充電。
應該就是這四種情況,那麼下面主要要解決的問題是:
- 使用者解鎖了,通過主測廣播:Intent.ACTION_USER_PRESENT判斷是否解鎖後使用者到前臺。
- USB連線狀態有對應的回撥,並且這個時候更新USB連線模式。
- 熄屏了,通過註冊廣播Intent.ACTION_SCREEN_OFF判斷,還需要註冊廣播Intent.ACTION_SCREEN_ON,作為螢幕狀態值的切換。
在UsbService.java類中註冊以上說到的廣播接收者,再對UsbDeviceManager.java類中的標識進行更新。
1.修改frameworks/base/services/usb/java/com/android/server/usb/UsbService.java
public class UsbService extends IUsbManager.Stub {
······
final IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_STOPPED);
//add by xx in 2017-06-12 for bug 169853 start
//註冊三個廣播
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
//add by xx in 2017-06-12 for bug 169853 end
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mContext.registerReceiver(mReceiver, filter, null, null);
······
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
final String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
setCurrentUser(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
synchronized (mLock) {
mSettingsByUser.remove(userId);
}
} else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
.equals(action)) {
if (mDeviceManager != null) {
mDeviceManager.updateUserRestrictions();
}
//add by xx in 2017-06-12 for bug 169853 start
//處理三個廣播
}else if (Intent.ACTION_USER_PRESENT.equals(action)) {
if (mDeviceManager != null) {
mDeviceManager.usbDataUnlocked(true);//這個方法系統有的
mDeviceManager.setUserPresent();//這個方法是新增的
}
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
if (mDeviceManager != null) {
mDeviceManager.updateScreentSate(true);//這個方法是新增的,為了更新螢幕狀態
}
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
if (mDeviceManager != null) {
mDeviceManager.updateScreentSate(false);//這個方法是新增的,為了更新螢幕狀態
}
//add by xx in 2017-06-12 for bug 169853 end
}
}
};
}
2.接下來修改frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
public class UsbDeviceManager {
·····
//新增兩個全域性變數,作為標識
//modified by xx in 2017-06-12 for bug 169853 start
private boolean mUserPresent = false;//使用者是否結果到前臺
private boolean screenOff = false;//螢幕是否是熄屏
private boolean changeByUser = false;//切換USB模式的時候,是這裡程式碼切換的,還是使用者點選切換的。
//modified by xx in 2017-06-12 for bug 169853 end
·····
//新增這兩個方法,在UsbService.java中用到,更新這邊的狀態
//modified by xx in 2017-06-12 for bug 169853 start
public void setUserPresent(){
mUserPresent = true;
}
public void updateScreentSate(boolean state){
screenOff = state;
if(!screenOff) {
mUserPresent = false;
}
if(mHandler != null){
mHandler.updateUsbMode();
}
}
public void usbDataUnlocked(){
changeByUser = false;
mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, true);
}
//modified by xx in 2017-06-12 for bug 169853 end
·····
//更新USB連線狀態
public void updateState(String state) {
int connected, configured;
if ("HWDISCONNECTED".equals(state)) {
connected = 0;
configured = 0;
mHwDisconnected = true;
//add by xx in 2017-08-03 for swtich usb mode start
changeByUser = false;
//add by xx in 2017-08-03 for swtich usb mode end
} else if ("DISCONNECTED".equals(state)) {
connected = 0;
configured = 0;
mHwDisconnected = false;
//modified by xx in 2017-06-12 for bug 169853 start
//當熄屏的情況下,更新使用者不在前臺的標識
if(screenOff){
mUserPresent = false;
}
//modified by xxx in 2017-06-12 for bug 169853 end
} else if ("CONNECTED".equals(state)) {
connected = 1;
configured = 0;
·····
private final class UsbHandler extends Handler {
·····
//在收到更新USB狀態的訊息之後,更新USB模式,當然要根據使用者是否在前臺進行判斷
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
mUsbConfigured = mConfigured;
//modified by xx in 2017-06-12 for bug 169853 start
//update usb state first
updateUsbMode();
if (mUserPresent && !changeByUser) { //使用者在前臺的
mUsbDataUnlocked = true;//解鎖資料,那麼連線電腦就能看到連線模式為MTP了
}
//modified by xx in 2017-06-12 for bug 169853 end
if (!mConnected) {
// When a disconnect occurs, relock access to sensitive user data
mUsbDataUnlocked = false;
}
updateUsbNotification();
updateAdbNotification();
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
} else if (!mConnected) {
}
·····//省略程式碼
case MSG_SET_USB_DATA_UNLOCKED:
//add by xx in 2017-08-03 for swtich usb mode start
if(!changeByUser && mUsbDataUnlocked) return;
//add by xx in 2017-08-03 for swtich usb mode end
setUsbDataUnlocked(msg.arg1 == 1);
break;
}
·····
//在UsbHandler類中的方法,主要是因為用到USB狀態值:mConnected
//add by xx in 2017-06-12 for bug 169853 start
private void updateUsbMode(){
if(!mConnected && screenOff){
mUserPresent = false;
}
}
//add by xx in 2017-06-12 for bug 169853 end
}
·····
}
//省略其他程式碼
public void setCurrentFunctions(String functions) {
if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
//add by xx in 2017-08-03 for swtich usb mode start
changeByUser = true;
//add by xx in 2017-08-03 for swtich usb mode end
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
}
//省略其他程式碼
}
主要修改上面兩個類,實現以下情況:
Android版本 | 在鎖屏的情況下 | 在解鎖的情況下 |
---|---|---|
7.0 | 僅充電 | MTP |
那麼這樣的行為就跟Android 6.0 的表現一樣了,問題可以說已經解決了。
像這些修改一個預設值的問題還是比較簡單的。事實上,對USB完全沒有接觸,還是要多看,有那麼多巨人,就借個肩膀來站站唄,就像本文一開始提到的那位大神一樣,在這裡表示感謝。
感謝 SymphonyZhang 的提醒,在Android 7.1中“只要persist.sys.usb.config這個屬性的值設為mtp,後面不要加上adb那些什麼的,就可以了”
相關文章
- Ubuntu 12.04上Android MTP連線UbuntuAndroid
- 設定USB無線網路卡為監聽模式大學霸IT達人模式
- Android MTP流程Android
- 魅族usb除錯模式開啟連線不上電腦除錯模式
- Linux 預設連線數Linux
- win10連線usb印表機的方法_win10如何連線usb印表機Win10
- Android設定加密鎖屏不可訪問MTPAndroid加密
- gdb配置預設連線遠端
- 【轉載】WSL 如何連線USB裝置
- MySQL 預設最大連線數是多少?MySql
- android USB host程式設計Android程式設計
- android開發板USB連線PC後adb口丟失 解決Android
- WSL2連線USB裝置(以USRP B210為例)
- Ubuntu下android手機通過usb連線電腦,顯示"???????????? no permissions"問題UbuntuAndroid
- win10系統不能識別Android手機MTP模式如何解決Win10Android模式
- EOSCleos連線到非預設主機/埠
- 印表機usb連線電腦無法識別怎麼辦 印表機usb連線電腦無法識別的方法
- RMAN連線與oracle連線模式的關係Oracle模式
- socket測試遠端地址能否連線併為連線設定超時
- Android客戶端網路預連線優化機制探究Android客戶端優化
- abap 列印smartforms不預覽連線列印 (設定 程式碼)ORM
- 關於MacBook Pro 15 usb連線iPhone反覆重連的解決辦法MaciPhone
- zabbix 預設item採集使用被動模式 需要改為主動模式模式
- 虛擬機器NAT模式網路連線設定ssh虛擬機模式
- Android客戶端網路預連線最佳化機制探究Android客戶端
- 外連線轉換為內連線的情況
- exists改為內連線
- not exists改為外連線
- 【Android】Socket連線-RxSocketAndroid
- Android 連線資料庫Android資料庫
- win10安裝mtp usb驅動裝置顯示感嘆最佳解決方法Win10
- 詳解Oracle的連線模式:專有模式和共享模式Oracle模式
- 預設方法的使用模式模式
- zedboard 使用OTG連線USB串列埠時出現錯誤問題ZedOTG串列埠
- 何為軟連線、何為硬連結(含圖解)圖解
- 請問jboss中預設的連線工廠名是什麼
- build libusb for AndroidUIAndroid
- android裝置連線至Android studioAndroid