该代码片段展示了如何通过编程方式关闭设备上的蓝牙功能。这里有两种方法,disable()
和 disable(boolean persist)
,它们都涉及到蓝牙的关闭操作,但有一些关键的不同点:
-
disable()
方法:- 这是一个公开的方法,意味着它可以在任何遵循了适当权限设置的应用中使用。
- 关闭蓝牙前需要得到用户的明确同意,因为这会影响到用户当前可能依赖蓝牙进行的各种连接和服务。
- 调用该方法后会立即返回结果,但实际的蓝牙关闭过程是异步完成的。这意味着你需要监听
ACTION_STATE_CHANGED
广播来跟踪蓝牙状态的变化。 - 如果方法调用成功(返回
true
),蓝牙状态将从STATE_ON
变为STATE_TURNING_OFF
,最终变为STATE_OFF
或者回到STATE_ON
(如果关闭过程中出现了问题)。
-
disable(boolean persist)
方法:- 这个方法有一个额外的参数
persist
,用来指示是否保存这个设置。这个方法被标记为隐藏(@hide
),通常不建议外部应用直接使用。 - 与
disable()
类似,也需要适当的权限才能调用。 - 当
persist
设置为false
时,关闭蓝牙的操作不会被记住,也就是说,如果设备重启,蓝牙的状态不会保持关闭状态。
- 这个方法有一个额外的参数
这两个方法都需要特定的权限来执行,如 BLUETOOTH_CONNECT
权限,并且需要处理可能发生的 RemoteException
异常。在实现涉及蓝牙控制的功能时,开发者应确保获得了用户的明确同意,并适当地处理各种可能的错误情况。
最后都会调到frameworks\base\services\core\java\com\android\server\BluetoothManagerService.java
可以看到第一个不带参的disable调用时直接给true,第二个带参可选择是否记忆开关
false:不记忆
true:记忆
public boolean disable(AttributionSource attributionSource, boolean persist)
throws RemoteException {
final String packageName = attributionSource.getPackageName();
if (!checkBluetoothPermissions(attributionSource, "disable", true)) {
if (DBG) {
Slog.d(TAG, "disable(): not disabling - bluetooth disallowed");
}
return false;
}
final int callingUid = Binder.getCallingUid();
final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
if (!callerSystem && isEnabled() && mWirelessConsentRequired
&& startConsentUiIfNeeded(packageName,
callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
return false;
}
if (DBG) {
Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding);
}
synchronized (mReceiver) {
if (!isBluetoothPersistedStateOnAirplane()) {
if (persist) {
persistBluetoothSetting(BLUETOOTH_OFF);
}
mEnableExternal = false;
}
sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
packageName);
}
return true;
}
进入同步块(针对 mReceiver
对象),进行以下检查和操作:
如果蓝牙不在飞行模式下持久化状态,则根据 persist
参数决定是否保存蓝牙关闭设置。
/**
* Save the Bluetooth on/off state
*/
private void persistBluetoothSetting(int value) {
if (DBG) {
Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
}
// waive WRITE_SECURE_SETTINGS permission check
final long callingIdentity = Binder.clearCallingIdentity();
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, value);
Binder.restoreCallingIdentity(callingIdentity);
}
这段代码定义了一个名为 persistBluetoothSetting
的私有方法,用于保存蓝牙的开关状态。该方法接收一个整型参数 value
,表示要保存的蓝牙状态(例如:开启或关闭)。以下是这个方法的主要逻辑和操作步骤:
-
调试信息输出:
- 在调试模式下(当
DBG
墫量为真时),通过Slog.d
方法记录一条日志,显示正在保存的蓝牙设置值。
- 在调试模式下(当
-
权限处理:
- 使用
Binder.clearCallingIdentity
方法暂时清除调用者的身份标识,这样可以在不检查WRITE_SECURE_SETTINGS
权限的情况下执行接下来的操作。这一步主要是为了能够在系统级别修改设置而不受限于应用的权限。
- 使用
-
保存蓝牙状态:
- 通过
Settings.Global.putInt
方法将蓝牙的状态值写入系统的全局设置中。这里使用了mContext.getContentResolver()
获取内容解析器,并将其与Settings.Global.BLUETOOTH_ON
键一起使用来更新蓝牙的状态值。
- 通过
-
恢复调用者身份:
- 最后,通过
Binder.restoreCallingIdentity
方法恢复原来的调用者身份标识,确保后续的操作能够正确识别调用者及其权限。
- 最后,通过