Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -163,6 +163,16 @@ public interface BluetoothCallback { default void onAclConnectionStateChanged( default void onAclConnectionStateChanged( @NonNull CachedBluetoothDevice cachedDevice, int state) {} @NonNull CachedBluetoothDevice cachedDevice, int state) {} /** * Called when the Auto-on state is changed for any user. Listens to intent * {@link android.bluetooth.BluetoothAdapter#ACTION_AUTO_ON_STATE_CHANGED } * * @param state the Auto-on state, the possible values are: * {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_ENABLED}, * {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_DISABLED} */ default void onAutoOnStateChanged(int state) {} @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "STATE_" }, value = { @IntDef(prefix = { "STATE_" }, value = { STATE_DISCONNECTED, STATE_DISCONNECTED, Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +19 −0 Original line number Original line Diff line number Diff line Loading @@ -133,6 +133,8 @@ public class BluetoothEventManager { addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler()); addHandler(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED, new AutoOnStateChangedHandler()); registerAdapterIntentReceiver(); registerAdapterIntentReceiver(); } } Loading Loading @@ -552,4 +554,21 @@ public class BluetoothEventManager { dispatchAudioModeChanged(); dispatchAudioModeChanged(); } } } } private class AutoOnStateChangedHandler implements Handler { @Override public void onReceive(Context context, Intent intent, BluetoothDevice device) { String action = intent.getAction(); if (action == null) { Log.w(TAG, "AutoOnStateChangedHandler() action is null"); return; } int state = intent.getIntExtra(BluetoothAdapter.EXTRA_AUTO_ON_STATE, BluetoothAdapter.ERROR); for (BluetoothCallback callback : mCallbacks) { callback.onAutoOnStateChanged(state); } } } } } packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java +14 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.never; Loading Loading @@ -489,4 +490,17 @@ public class BluetoothEventManagerTest { verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME), verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME), eq(R.string.bluetooth_pairing_pin_error_message)); eq(R.string.bluetooth_pairing_pin_error_message)); } } /** * Intent ACTION_AUTO_ON_STATE_CHANGED should dispatch to callback. */ @Test public void intentWithExtraState_autoOnStateChangedShouldDispatchToRegisterCallback() { mBluetoothEventManager.registerCallback(mBluetoothCallback); mIntent = new Intent(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED); mContext.sendBroadcast(mIntent); verify(mBluetoothCallback).onAutoOnStateChanged(anyInt()); } } } packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt +5 −14 Original line number Original line Diff line number Diff line Loading @@ -19,8 +19,6 @@ package com.android.systemui.qs.tiles.dialog.bluetooth import android.util.Log import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map /** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */ /** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */ @SysUISingleton @SysUISingleton Loading @@ -30,14 +28,10 @@ constructor( private val bluetoothAutoOnRepository: BluetoothAutoOnRepository, private val bluetoothAutoOnRepository: BluetoothAutoOnRepository, ) { ) { val isEnabled = bluetoothAutoOnRepository.isAutoOn.map { it == ENABLED }.distinctUntilChanged() val isEnabled = bluetoothAutoOnRepository.isAutoOn /** /** Checks if the auto on feature is supported. */ * Checks if the auto on value is present in the repository. suspend fun isAutoOnSupported(): Boolean = bluetoothAutoOnRepository.isAutoOnSupported() * * @return `true` if a value is present (i.e, the feature is enabled by the Bluetooth server). */ suspend fun isValuePresent(): Boolean = bluetoothAutoOnRepository.isValuePresent() /** /** * Sets enabled or disabled based on the provided value. * Sets enabled or disabled based on the provided value. Loading @@ -45,17 +39,14 @@ constructor( * @param value `true` to enable the feature, `false` to disable it. * @param value `true` to enable the feature, `false` to disable it. */ */ suspend fun setEnabled(value: Boolean) { suspend fun setEnabled(value: Boolean) { if (!isValuePresent()) { if (!isAutoOnSupported()) { Log.e(TAG, "Trying to set toggle value while feature not available.") Log.e(TAG, "Trying to set toggle value while feature not available.") } else { } else { val newValue = if (value) ENABLED else DISABLED bluetoothAutoOnRepository.setAutoOn(value) bluetoothAutoOnRepository.setAutoOn(newValue) } } } } companion object { companion object { private const val TAG = "BluetoothAutoOnInteractor" private const val TAG = "BluetoothAutoOnInteractor" const val DISABLED = 0 const val ENABLED = 1 } } } } packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt +76 −49 Original line number Original line Diff line number Diff line Loading @@ -16,22 +16,23 @@ package com.android.systemui.qs.tiles.dialog.bluetooth package com.android.systemui.qs.tiles.dialog.bluetooth import android.bluetooth.BluetoothAdapter import android.util.Log import com.android.settingslib.bluetooth.BluetoothCallback import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext Loading @@ -44,61 +45,87 @@ import kotlinx.coroutines.withContext class BluetoothAutoOnRepository class BluetoothAutoOnRepository @Inject @Inject constructor( constructor( private val secureSettings: SecureSettings, localBluetoothManager: LocalBluetoothManager?, private val userRepository: UserRepository, private val bluetoothAdapter: BluetoothAdapter?, @Application private val coroutineScope: CoroutineScope, @Application private val coroutineScope: CoroutineScope, @Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, ) { ) { // Flow representing the auto on setting value for the current user // Flow representing the auto on state for the current user @OptIn(ExperimentalCoroutinesApi::class) internal val isAutoOn: Flow<Boolean> = internal val isAutoOn: StateFlow<Int> = localBluetoothManager?.eventManager?.let { eventManager -> userRepository.selectedUserInfo conflatedCallbackFlow { .flatMapLatest { userInfo -> val listener = secureSettings object : BluetoothCallback { .observerFlow(userInfo.id, SETTING_NAME) override fun onAutoOnStateChanged(autoOnState: Int) { .onStart { emit(Unit) } super.onAutoOnStateChanged(autoOnState) .map { secureSettings.getIntForUser(SETTING_NAME, UNSET, userInfo.id) } if ( autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED || autoOnState == BluetoothAdapter.AUTO_ON_STATE_DISABLED ) { trySendWithFailureLogging( autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED, TAG, "onAutoOnStateChanged" ) } } } } .distinctUntilChanged() eventManager.registerCallback(listener) awaitClose { eventManager.unregisterCallback(listener) } } .onStart { emit(isAutoOnEnabled()) } .flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher) .stateIn( .stateIn( coroutineScope, coroutineScope, SharingStarted.WhileSubscribed(replayExpirationMillis = 0), SharingStarted.WhileSubscribed(replayExpirationMillis = 0), UNSET initialValue = false ) ) } ?: flowOf(false) /** /** * Checks if the auto on setting value is ever set for the current user. * Checks if the auto on feature is supported for the current user. * * * @return `true` if the setting value is not UNSET, `false` otherwise. * @throws Exception if an error occurs while checking auto-on support. */ */ suspend fun isValuePresent(): Boolean = suspend fun isAutoOnSupported(): Boolean = withContext(backgroundDispatcher) { withContext(backgroundDispatcher) { secureSettings.getIntForUser( try { SETTING_NAME, bluetoothAdapter?.isAutoOnSupported ?: false UNSET, } catch (e: Exception) { userRepository.getSelectedUserInfo().id // Server could throw TimeoutException, InterruptedException or ExecutionException ) != UNSET Log.e(TAG, "Error calling isAutoOnSupported", e) false } } } /** /** Sets the Bluetooth Auto-On for the current user. */ * Sets the Bluetooth Auto-On setting value for the current user. suspend fun setAutoOn(value: Boolean) { * * @param value The new setting value to be applied. */ suspend fun setAutoOn(value: Int) { withContext(backgroundDispatcher) { withContext(backgroundDispatcher) { secureSettings.putIntForUser( try { SETTING_NAME, bluetoothAdapter?.setAutoOnEnabled(value) value, } catch (e: Exception) { userRepository.getSelectedUserInfo().id // Server could throw IllegalStateException, TimeoutException, InterruptedException ) // or ExecutionException Log.e(TAG, "Error calling setAutoOnEnabled", e) } } } private suspend fun isAutoOnEnabled() = withContext(backgroundDispatcher) { try { bluetoothAdapter?.isAutoOnEnabled ?: false } catch (e: Exception) { // Server could throw IllegalStateException, TimeoutException, InterruptedException // or ExecutionException Log.e(TAG, "Error calling isAutoOnEnabled", e) false } } } } companion object { private companion object { const val SETTING_NAME = "bluetooth_automatic_turn_on" const val TAG = "BluetoothAutoOnRepository" const val UNSET = -1 } } } } Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -163,6 +163,16 @@ public interface BluetoothCallback { default void onAclConnectionStateChanged( default void onAclConnectionStateChanged( @NonNull CachedBluetoothDevice cachedDevice, int state) {} @NonNull CachedBluetoothDevice cachedDevice, int state) {} /** * Called when the Auto-on state is changed for any user. Listens to intent * {@link android.bluetooth.BluetoothAdapter#ACTION_AUTO_ON_STATE_CHANGED } * * @param state the Auto-on state, the possible values are: * {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_ENABLED}, * {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_DISABLED} */ default void onAutoOnStateChanged(int state) {} @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "STATE_" }, value = { @IntDef(prefix = { "STATE_" }, value = { STATE_DISCONNECTED, STATE_DISCONNECTED, Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +19 −0 Original line number Original line Diff line number Diff line Loading @@ -133,6 +133,8 @@ public class BluetoothEventManager { addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler()); addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler()); addHandler(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED, new AutoOnStateChangedHandler()); registerAdapterIntentReceiver(); registerAdapterIntentReceiver(); } } Loading Loading @@ -552,4 +554,21 @@ public class BluetoothEventManager { dispatchAudioModeChanged(); dispatchAudioModeChanged(); } } } } private class AutoOnStateChangedHandler implements Handler { @Override public void onReceive(Context context, Intent intent, BluetoothDevice device) { String action = intent.getAction(); if (action == null) { Log.w(TAG, "AutoOnStateChangedHandler() action is null"); return; } int state = intent.getIntExtra(BluetoothAdapter.EXTRA_AUTO_ON_STATE, BluetoothAdapter.ERROR); for (BluetoothCallback callback : mCallbacks) { callback.onAutoOnStateChanged(state); } } } } }
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java +14 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.never; Loading Loading @@ -489,4 +490,17 @@ public class BluetoothEventManagerTest { verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME), verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME), eq(R.string.bluetooth_pairing_pin_error_message)); eq(R.string.bluetooth_pairing_pin_error_message)); } } /** * Intent ACTION_AUTO_ON_STATE_CHANGED should dispatch to callback. */ @Test public void intentWithExtraState_autoOnStateChangedShouldDispatchToRegisterCallback() { mBluetoothEventManager.registerCallback(mBluetoothCallback); mIntent = new Intent(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED); mContext.sendBroadcast(mIntent); verify(mBluetoothCallback).onAutoOnStateChanged(anyInt()); } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt +5 −14 Original line number Original line Diff line number Diff line Loading @@ -19,8 +19,6 @@ package com.android.systemui.qs.tiles.dialog.bluetooth import android.util.Log import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map /** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */ /** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */ @SysUISingleton @SysUISingleton Loading @@ -30,14 +28,10 @@ constructor( private val bluetoothAutoOnRepository: BluetoothAutoOnRepository, private val bluetoothAutoOnRepository: BluetoothAutoOnRepository, ) { ) { val isEnabled = bluetoothAutoOnRepository.isAutoOn.map { it == ENABLED }.distinctUntilChanged() val isEnabled = bluetoothAutoOnRepository.isAutoOn /** /** Checks if the auto on feature is supported. */ * Checks if the auto on value is present in the repository. suspend fun isAutoOnSupported(): Boolean = bluetoothAutoOnRepository.isAutoOnSupported() * * @return `true` if a value is present (i.e, the feature is enabled by the Bluetooth server). */ suspend fun isValuePresent(): Boolean = bluetoothAutoOnRepository.isValuePresent() /** /** * Sets enabled or disabled based on the provided value. * Sets enabled or disabled based on the provided value. Loading @@ -45,17 +39,14 @@ constructor( * @param value `true` to enable the feature, `false` to disable it. * @param value `true` to enable the feature, `false` to disable it. */ */ suspend fun setEnabled(value: Boolean) { suspend fun setEnabled(value: Boolean) { if (!isValuePresent()) { if (!isAutoOnSupported()) { Log.e(TAG, "Trying to set toggle value while feature not available.") Log.e(TAG, "Trying to set toggle value while feature not available.") } else { } else { val newValue = if (value) ENABLED else DISABLED bluetoothAutoOnRepository.setAutoOn(value) bluetoothAutoOnRepository.setAutoOn(newValue) } } } } companion object { companion object { private const val TAG = "BluetoothAutoOnInteractor" private const val TAG = "BluetoothAutoOnInteractor" const val DISABLED = 0 const val ENABLED = 1 } } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt +76 −49 Original line number Original line Diff line number Diff line Loading @@ -16,22 +16,23 @@ package com.android.systemui.qs.tiles.dialog.bluetooth package com.android.systemui.qs.tiles.dialog.bluetooth import android.bluetooth.BluetoothAdapter import android.util.Log import com.android.settingslib.bluetooth.BluetoothCallback import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext Loading @@ -44,61 +45,87 @@ import kotlinx.coroutines.withContext class BluetoothAutoOnRepository class BluetoothAutoOnRepository @Inject @Inject constructor( constructor( private val secureSettings: SecureSettings, localBluetoothManager: LocalBluetoothManager?, private val userRepository: UserRepository, private val bluetoothAdapter: BluetoothAdapter?, @Application private val coroutineScope: CoroutineScope, @Application private val coroutineScope: CoroutineScope, @Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, ) { ) { // Flow representing the auto on setting value for the current user // Flow representing the auto on state for the current user @OptIn(ExperimentalCoroutinesApi::class) internal val isAutoOn: Flow<Boolean> = internal val isAutoOn: StateFlow<Int> = localBluetoothManager?.eventManager?.let { eventManager -> userRepository.selectedUserInfo conflatedCallbackFlow { .flatMapLatest { userInfo -> val listener = secureSettings object : BluetoothCallback { .observerFlow(userInfo.id, SETTING_NAME) override fun onAutoOnStateChanged(autoOnState: Int) { .onStart { emit(Unit) } super.onAutoOnStateChanged(autoOnState) .map { secureSettings.getIntForUser(SETTING_NAME, UNSET, userInfo.id) } if ( autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED || autoOnState == BluetoothAdapter.AUTO_ON_STATE_DISABLED ) { trySendWithFailureLogging( autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED, TAG, "onAutoOnStateChanged" ) } } } } .distinctUntilChanged() eventManager.registerCallback(listener) awaitClose { eventManager.unregisterCallback(listener) } } .onStart { emit(isAutoOnEnabled()) } .flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher) .stateIn( .stateIn( coroutineScope, coroutineScope, SharingStarted.WhileSubscribed(replayExpirationMillis = 0), SharingStarted.WhileSubscribed(replayExpirationMillis = 0), UNSET initialValue = false ) ) } ?: flowOf(false) /** /** * Checks if the auto on setting value is ever set for the current user. * Checks if the auto on feature is supported for the current user. * * * @return `true` if the setting value is not UNSET, `false` otherwise. * @throws Exception if an error occurs while checking auto-on support. */ */ suspend fun isValuePresent(): Boolean = suspend fun isAutoOnSupported(): Boolean = withContext(backgroundDispatcher) { withContext(backgroundDispatcher) { secureSettings.getIntForUser( try { SETTING_NAME, bluetoothAdapter?.isAutoOnSupported ?: false UNSET, } catch (e: Exception) { userRepository.getSelectedUserInfo().id // Server could throw TimeoutException, InterruptedException or ExecutionException ) != UNSET Log.e(TAG, "Error calling isAutoOnSupported", e) false } } } /** /** Sets the Bluetooth Auto-On for the current user. */ * Sets the Bluetooth Auto-On setting value for the current user. suspend fun setAutoOn(value: Boolean) { * * @param value The new setting value to be applied. */ suspend fun setAutoOn(value: Int) { withContext(backgroundDispatcher) { withContext(backgroundDispatcher) { secureSettings.putIntForUser( try { SETTING_NAME, bluetoothAdapter?.setAutoOnEnabled(value) value, } catch (e: Exception) { userRepository.getSelectedUserInfo().id // Server could throw IllegalStateException, TimeoutException, InterruptedException ) // or ExecutionException Log.e(TAG, "Error calling setAutoOnEnabled", e) } } } private suspend fun isAutoOnEnabled() = withContext(backgroundDispatcher) { try { bluetoothAdapter?.isAutoOnEnabled ?: false } catch (e: Exception) { // Server could throw IllegalStateException, TimeoutException, InterruptedException // or ExecutionException Log.e(TAG, "Error calling isAutoOnEnabled", e) false } } } } companion object { private companion object { const val SETTING_NAME = "bluetooth_automatic_turn_on" const val TAG = "BluetoothAutoOnRepository" const val UNSET = -1 } } } }