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.Nullable;
27 import androidx.annotation.VisibleForTesting;
28 import androidx.preference.Preference;
29 import androidx.preference.TwoStatePreference;
30 
31 import com.android.settings.core.PreferenceControllerMixin;
32 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
33 
34 /**
35  * Preference controller to control Bluetooth LE audio feature
36  */
37 public class BluetoothLeAudioPreferenceController
38         extends DeveloperOptionsPreferenceController
39         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
40 
41     private static final String PREFERENCE_KEY = "bluetooth_disable_leaudio";
42 
43     private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY =
44             "ro.bluetooth.leaudio_switcher.supported";
45     @VisibleForTesting
46     static final String LE_AUDIO_SWITCHER_DISABLED_PROPERTY =
47             "persist.bluetooth.leaudio_switcher.disabled";
48 
49     @Nullable private final DevelopmentSettingsDashboardFragment mFragment;
50 
51     @VisibleForTesting
52     BluetoothAdapter mBluetoothAdapter;
53 
54     @VisibleForTesting
55     boolean mChanged = false;
56 
BluetoothLeAudioPreferenceController(Context context, @Nullable DevelopmentSettingsDashboardFragment fragment)57     public BluetoothLeAudioPreferenceController(Context context,
58             @Nullable DevelopmentSettingsDashboardFragment fragment) {
59         super(context);
60         mFragment = fragment;
61         mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
62     }
63 
64     @Override
getPreferenceKey()65     public String getPreferenceKey() {
66         return PREFERENCE_KEY;
67     }
68 
69     @Override
isAvailable()70     public boolean isAvailable() {
71         return BluetoothProperties.isProfileBapUnicastClientEnabled().orElse(false)
72                 && !BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false);
73     }
74 
75     @Override
onPreferenceChange(Preference preference, Object newValue)76     public boolean onPreferenceChange(Preference preference, Object newValue) {
77         BluetoothRebootDialog.show(mFragment);
78         mChanged = true;
79         return false;
80     }
81 
82     @Override
updateState(Preference preference)83     public void updateState(Preference preference) {
84         if (mBluetoothAdapter == null) {
85             return;
86         }
87 
88         final boolean leAudioSwitchSupported =
89                 SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false);
90 
91         final int isLeAudioSupportedStatus = mBluetoothAdapter.isLeAudioSupported();
92         final boolean leAudioEnabled =
93                 (isLeAudioSupportedStatus == BluetoothStatusCodes.FEATURE_SUPPORTED);
94 
95         ((TwoStatePreference) mPreference).setChecked(!leAudioEnabled);
96 
97         // Disable option if Bluetooth is disabled or if switch is not supported
98         if (isLeAudioSupportedStatus == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
99                 || !leAudioSwitchSupported) {
100             mPreference.setEnabled(false);
101         }
102     }
103 
104     /**
105      * Called when the RebootDialog confirm is clicked.
106      */
onRebootDialogConfirmed()107     public void onRebootDialogConfirmed() {
108         if (!mChanged || mBluetoothAdapter == null) {
109             return;
110         }
111 
112         final boolean leAudioDisabled =
113                 (mBluetoothAdapter.isLeAudioSupported() != BluetoothStatusCodes.FEATURE_SUPPORTED);
114         SystemProperties.set(LE_AUDIO_SWITCHER_DISABLED_PROPERTY,
115                 Boolean.toString(!leAudioDisabled));
116     }
117 
118     /**
119      * Called when the RebootDialog cancel is clicked.
120      */
onRebootDialogCanceled()121     public void onRebootDialogCanceled() {
122         mChanged = false;
123     }
124 }
125