1. 程式人生 > >關於android藍芽可見性設定

關於android藍芽可見性設定

framework提供了一種開啟可見性的操作,就是通過向用戶彈出一個提示框,來詢問是否允許開啟可見性。而且限制了最長時間為300秒,程式碼如下:

		//啟動修改藍芽可見性的Intent
		Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
		//設定藍芽可見性的時間,方法本身規定最多可見300秒
		intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
		startActivity(intent);

但通過android的自帶的settings程式,我們可以直接開機藍芽可見性。所以下載settings的原始碼,進行分析。找到了開啟藍芽可見性的程式碼,如下:

private void setEnabled(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起到了關鍵性左右,再看BluetoothAdapter原始碼,發現這2個方法都被隱藏(hide)了。如何能訪問到被隱藏的方法呢?自然是用強大的反射:
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();
		}
	}

用這種方法開啟的可見性,還有個附件的屬性,timeout值並沒有起到作用,可見性是一直保持的。可以通行下面類似的程式碼進行關閉:
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是關鍵。

如果想實現超時後自動關閉可見性的效果,使用Handler

postDelayed(Runnable r, long delayMillis)
就可以輕鬆實現這個功能。

以上程式碼在android4.2以上可以允許,4.2以下會因為缺少系統許可權而執行失敗。