通過暗碼去打開/關閉usb debug開關
1. Description
通過在dialer輸入暗碼,打開/關閉usb debug開關。
其實這個功能本來在settings下面就有的,如果是正式版的設備需要連續點擊幾次版本號才能將usb debug開關顯示出來,通過暗碼來打開估計是為了更加方便后續的操作吧。
2. Analysis
首先在dialer處進行邏輯判斷,如果接收到的是usb debug開關的暗碼,則發送對應的廣播。在mtk自帶的dialer就有相關的邏輯了,如handleSecretCode方法就會接收
*#*#<code>#*#*
格式的暗碼,然后發送廣播,其相關代碼如下所示:static boolean handleSecretCode(Context context, String input) {
// Secret codes are accessed by dialing *#*#<code>#*#*
/// M: add for handle reboot meta secret code @{
if (FK_SUPPORTED.equals(SystemProperties.get(FK_REBOOT_META_SUPPORT))) {
if (handleRebootMetaSecretCode(context, input)) {
return true;
}
}
/// @}
int len = input.length();
if (len <= 8 || !input.startsWith("*#*#") || !input.endsWith("#*#*")) {
return false;
}
String secretCode = input.substring(4, len - 4);
TelephonyManagerCompat.handleSecretCode(context, secretCode);
return true;
}
/*handleSecretCode這個方法在TelephonyManagerCompat.java文件中,它會將輸入的暗碼以廣播的形式發送出去*/
public static void handleSecretCode(Context context, String secretCode) {
// Must use system service on O+ to avoid using broadcasts, which are not allowed on O+.
if (BuildCompat.isAtLeastO()) {
if (!TelecomUtil.isDefaultDialer(context)) {
LogUtil.e(
"TelephonyManagerCompat.handleSecretCode",
"not default dialer, cannot send special code");
return;
}
context.getSystemService(TelephonyManager.class).sendDialerSpecialCode(secretCode);
} else {
// System service call is not supported pre-O, so must use a broadcast for N-.
Intent intent =
new Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://" + secretCode));
context.sendBroadcast(intent);
}
}
在廣播接收器中進行對應的邏輯處理:
usb debug的狀態信息是存儲在ContentProvider中的,對應的標識:/**
* Whether ADB is enabled.
*/
public static final String ADB_ENABLED = "adb_enabled";
只要將存儲在ContentProvider的狀態值拿出來,然后進行判斷,如果為0則表示當前usb debug是關閉的,如果為1則表示當前usb debug是打開的。只需要將狀態值取反后再存入ContentProvider就可以改變usb debug狀態。
3. Solution
- 添加USB接收器USBDebugBroadcastReceiver,具體代碼如下:
package com.android.settings;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
import com.android.internal.telephony.TelephonyIntents;
public class USBDebugBroadcastReceiver extends BroadcastReceiver {
private static final String TAG="USBDebugBroadcastReceiver";
private Toast debugOpenToast;
@Override
public void onReceive(Context context, Intent intent) {
if(TelephonyIntents.SECRET_CODE_ACTION.equals(intent.getAction()) && "0000".equals(intent.getData().getHost())){
boolean mEnableAdb = false;
final ContentResolver mContentResolver = context.getContentResolver();
mEnableAdb = Settings.Global.getInt(mContentResolver,
Settings.Global.ADB_ENABLED, 0) > 0;
Resources resources=context.getResources();
if (debugOpenToast != null) {
debugOpenToast.cancel();
}
if(!mEnableAdb){
// make sure the ADB_ENABLED setting value matches the current state
try {
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_ENABLED, 1 );
debugOpenToast = Toast.makeText(context,resources.getString(R.string.enable_adb)+" "+resources.getString(R.string.gadget_state_on)
+" "+resources.getString(R.string.band_mode_succeeded),
Toast.LENGTH_SHORT);
debugOpenToast.show();
} catch (SecurityException e) {
// If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
Log.d(TAG, "ADB_ENABLED is restricted.");
debugOpenToast = Toast.makeText(context,resources.getString(R.string.enable_adb)+" "+resources.getString(R.string.gadget_state_on)
+" "+resources.getString(R.string.band_mode_failed),
Toast.LENGTH_SHORT);
debugOpenToast.show();
}
}else{
try {
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_ENABLED, 0 );
debugOpenToast = Toast.makeText(context,resources.getString(R.string.enable_adb)+" "+resources.getString(R.string.gadget_state_off)
+" "+resources.getString(R.string.band_mode_succeeded),
Toast.LENGTH_SHORT);
debugOpenToast.show();
} catch (SecurityException e) {
// If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
Log.d(TAG, "ADB_DISENABLED is restricted.");
debugOpenToast = Toast.makeText(context,resources.getString(R.string.enable_adb)+" "+resources.getString(R.string.gadget_state_off)
+" "+resources.getString(R.string.band_mode_failed),
Toast.LENGTH_SHORT);
debugOpenToast.show();
}
}
}
}
}
- 在對應的AndroidManifest.xml中為該接收器進行注冊,具體如下:
<receiver android:name=".USBDebugBroadcastReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SECRET_CODE"/>
<data android:scheme="android_secret_code" android:host="33284"/>
</intent-filter>
</receiver>
4. Summary
這個問題相對簡單,只要將期望的狀態只存入對應的ContentProvider中就可與改變usb debug狀態。之所以通過廣播來處理,是因為與activity相比,通過intent啟動指定activity組件時,如果沒有找到合適的activity組件,會導致程序異常中止,但是通過intent啟動BroadcastReceiver組件時不會有該問題出現。