1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.development; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothManager; 21 import android.bluetooth.BluetoothStatusCodes; 22 import android.content.Context; 23 import android.os.SystemProperties; 24 import android.sysprop.BluetoothProperties; 25 26 import androidx.annotation.VisibleForTesting; 27 import androidx.preference.Preference; 28 import androidx.preference.TwoStatePreference; 29 30 import com.android.settings.core.PreferenceControllerMixin; 31 import com.android.settingslib.development.DeveloperOptionsPreferenceController; 32 33 /** 34 * Preference controller to control Bluetooth LE audio feature 35 */ 36 public class BluetoothLeAudioAllowListPreferenceController 37 extends DeveloperOptionsPreferenceController 38 implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { 39 40 private static final String PREFERENCE_KEY = "bluetooth_bypass_leaudio_allowlist"; 41 42 static final String LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY = 43 "ro.bluetooth.leaudio.le_audio_connection_by_default"; 44 @VisibleForTesting 45 static final String BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY = 46 "persist.bluetooth.leaudio.bypass_allow_list"; 47 48 @VisibleForTesting 49 BluetoothAdapter mBluetoothAdapter; 50 @VisibleForTesting boolean mLeAudioConnectionByDefault; 51 BluetoothLeAudioAllowListPreferenceController(Context context)52 public BluetoothLeAudioAllowListPreferenceController(Context context) { 53 super(context); 54 mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter(); 55 mLeAudioConnectionByDefault = 56 SystemProperties.getBoolean(LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY, true); 57 } 58 59 @Override getPreferenceKey()60 public String getPreferenceKey() { 61 return PREFERENCE_KEY; 62 } 63 64 @Override isAvailable()65 public boolean isAvailable() { 66 return BluetoothProperties.isProfileBapUnicastClientEnabled().orElse(false) 67 && mLeAudioConnectionByDefault; 68 } 69 70 @Override onPreferenceChange(Preference preference, Object newValue)71 public boolean onPreferenceChange(Preference preference, Object newValue) { 72 final boolean isBypassed = (Boolean) newValue; 73 SystemProperties.set(BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, 74 isBypassed ? "true" : "false"); 75 return true; 76 } 77 78 @Override updateState(Preference preference)79 public void updateState(Preference preference) { 80 if (mBluetoothAdapter == null) { 81 mPreference.setEnabled(false); 82 return; 83 } 84 85 final boolean isLeAudioSupported = 86 (mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED); 87 if (!isLeAudioSupported) { 88 mPreference.setEnabled(false); 89 ((TwoStatePreference) mPreference).setChecked(false); 90 return; 91 } 92 93 mPreference.setEnabled(true); 94 final boolean isLeAudioAllowlistBypassed = 95 SystemProperties.getBoolean(BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, false); 96 ((TwoStatePreference) mPreference).setChecked(isLeAudioAllowlistBypassed); 97 } 98 99 @Override onDeveloperOptionsSwitchDisabled()100 protected void onDeveloperOptionsSwitchDisabled() { 101 super.onDeveloperOptionsSwitchDisabled(); 102 final boolean isBypassed = 103 SystemProperties.getBoolean(BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, false); 104 if (isBypassed) { 105 SystemProperties.set(BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, Boolean.toString(false)); 106 ((TwoStatePreference) mPreference).setChecked(false); 107 } 108 } 109 } 110