最近工作中遇到一個(gè)特殊的需求,要求代碼能夠從后臺(tái)開(kāi)機(jī)android手機(jī)藍(lán)牙的可見(jiàn)性。而framework提供了一種打開(kāi)可見(jiàn)性的操作,就是通過(guò)向用戶(hù)彈出一個(gè)提示框,來(lái)詢(xún)問(wèn)是否允許開(kāi)啟可見(jiàn)性。而且限制了最長(zhǎng)時(shí)間為300秒,代碼如下:
? ? ? ? //啟動(dòng)修改藍(lán)牙可見(jiàn)性的Intent
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//設(shè)置藍(lán)牙可見(jiàn)性的時(shí)間,方法本身規(guī)定最多可見(jiàn)300秒
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(intent);
但通過(guò)android的自帶的settings程序,我們可以直接開(kāi)機(jī)藍(lán)牙可見(jiàn)性。所以下載settings的源碼,進(jìn)行分析。找到了開(kāi)啟藍(lán)牙可見(jiàn)性的代碼,如下:
private voidsetEnabled(boolean enable) {
if (enable) {
int timeout = getDiscoverableTimeout();
mLocalAdapter.setDiscoverableTimeout(timeout);
long endTimestamp = System.currentTimeMillis() + timeout * 1000L;
LocalBluetoothPreferences.persistDiscoverableEndTimestamp(mContext, endTimestamp);
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, timeout);
updateCountdownSummary();
} else {
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
}
}
這下就清楚了,是BluetoothAdapter 里面的setDiscoverableTimeout和setScanMode起到了關(guān)鍵性左右,再看BluetoothAdapter源碼,發(fā)現(xiàn)這2個(gè)方法都被隱藏(hide)了。如何能訪問(wèn)到被隱藏的方法呢?自然是用強(qiáng)大的反射:
public void setDiscoverableTimeout(int timeout) {
BluetoothAdapter adapter=BluetoothAdapter.getDefaultAdapter();
try {
Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
setDiscoverableTimeout.setAccessible(true);
Method setScanMode =BluetoothAdapter.class.getMethod("setScanMode", int.class,int.class);
setScanMode.setAccessible(true);
setDiscoverableTimeout.invoke(adapter, timeout);
setScanMode.invoke(adapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,timeout);
} catch (Exception e) {
e.printStackTrace();
}
}
用這種方法開(kāi)啟的可見(jiàn)性,還有個(gè)附件的屬性,timeout值并沒(méi)有起到作用,可見(jiàn)性是一直保持的??梢酝ㄐ邢旅骖?lèi)似的代碼進(jìn)行關(guān)閉:
public void closeDiscoverableTimeout() {
BluetoothAdapter adapter=BluetoothAdapter.getDefaultAdapter();
try {
Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
setDiscoverableTimeout.setAccessible(true);
Method setScanMode =BluetoothAdapter.class.getMethod("setScanMode", int.class,int.class);
setScanMode.setAccessible(true);
setDiscoverableTimeout.invoke(adapter, 1);
setScanMode.invoke(adapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE,1);
} catch (Exception e) {
e.printStackTrace();
}
}
改變BluetoothAdapter.SCAN_MODE_CONNECTABLE是關(guān)鍵。
如果想實(shí)現(xiàn)超時(shí)后自動(dòng)關(guān)閉可見(jiàn)性的效果,使用Handler
postDelayed(Runnable r, long delayMillis)
就可以輕松實(shí)現(xiàn)這個(gè)功能。
以上代碼在android4.2以上可以允許,4.2以下會(huì)因?yàn)槿鄙傧到y(tǒng)權(quán)限而運(yùn)行失敗。