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 static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController.A2DP_OFFLOAD_DISABLED_PROPERTY;
20 
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothManager;
23 import android.bluetooth.BluetoothStatusCodes;
24 import android.content.Context;
25 import android.os.SystemProperties;
26 
27 import androidx.annotation.Nullable;
28 import androidx.annotation.VisibleForTesting;
29 import androidx.preference.Preference;
30 import androidx.preference.TwoStatePreference;
31 
32 import com.android.settings.core.PreferenceControllerMixin;
33 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
34 
35 /**
36  * Preference controller to control Bluetooth LE audio offload
37  */
38 public class BluetoothLeAudioHwOffloadPreferenceController
39         extends DeveloperOptionsPreferenceController
40         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
41 
42     private static final String PREFERENCE_KEY = "bluetooth_disable_le_audio_hw_offload";
43     @Nullable private final DevelopmentSettingsDashboardFragment mFragment;
44 
45     static final String LE_AUDIO_OFFLOAD_DISABLED_PROPERTY =
46             "persist.bluetooth.leaudio_offload.disabled";
47     static final String LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY =
48             "ro.bluetooth.leaudio_offload.supported";
49 
50     @VisibleForTesting
51     BluetoothAdapter mBluetoothAdapter;
52 
53     @VisibleForTesting
54     boolean mChanged = false;
55 
BluetoothLeAudioHwOffloadPreferenceController(Context context, @Nullable DevelopmentSettingsDashboardFragment fragment)56     public BluetoothLeAudioHwOffloadPreferenceController(Context context,
57             @Nullable DevelopmentSettingsDashboardFragment fragment) {
58         super(context);
59         mFragment = fragment;
60         mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
61     }
62 
63     @Override
getPreferenceKey()64     public String getPreferenceKey() {
65         return PREFERENCE_KEY;
66     }
67 
68     @Override
onPreferenceChange(Preference preference, Object newValue)69     public boolean onPreferenceChange(Preference preference, Object newValue) {
70         BluetoothRebootDialog.show(mFragment);
71         mChanged = true;
72         return false;
73     }
74 
75     @Override
updateState(Preference preference)76     public void updateState(Preference preference) {
77         if (mBluetoothAdapter == null) {
78             return;
79         }
80 
81         final boolean leAudioEnabled =
82                 (mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
83         final boolean leAudioOffloadSupported =
84                 SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false);
85         final boolean a2dpOffloadDisabled =
86                 SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
87         if (leAudioEnabled && leAudioOffloadSupported && !a2dpOffloadDisabled) {
88             final boolean offloadDisabled =
89                     SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, true);
90             ((TwoStatePreference) mPreference).setChecked(offloadDisabled);
91         } else {
92             mPreference.setEnabled(false);
93             ((TwoStatePreference) mPreference).setChecked(true);
94         }
95     }
96 
97     @Override
onDeveloperOptionsSwitchDisabled()98     protected void onDeveloperOptionsSwitchDisabled() {
99         super.onDeveloperOptionsSwitchDisabled();
100         if (mBluetoothAdapter == null) {
101             return;
102         }
103 
104         final boolean leAudioEnabled =
105                 (mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
106         final boolean leAudioOffloadSupported =
107                 SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false);
108         final boolean a2dpOffloadDisabled =
109                 SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
110         if (leAudioEnabled && leAudioOffloadSupported && !a2dpOffloadDisabled) {
111             ((TwoStatePreference) mPreference).setChecked(true);
112             SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, "true");
113         } else {
114             mPreference.setEnabled(false);
115         }
116     }
117 
118     /**
119      * Check if the le audio offload setting is default value.
120      */
isDefaultValue()121     public boolean isDefaultValue() {
122         final boolean offloadSupported =
123                 !SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false)
124                 && SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false);
125         final boolean offloadDisabled =
126                     SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, false);
127         return offloadSupported ? offloadDisabled : true;
128     }
129 
130     /**
131      * Called when the RebootDialog confirm is clicked.
132      */
onRebootDialogConfirmed()133     public void onRebootDialogConfirmed() {
134         if (!mChanged) {
135             return;
136         }
137 
138         final boolean leaudioOffloadDisabled =
139                 SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY,
140                 false);
141         SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY,
142                 Boolean.toString(!leaudioOffloadDisabled));
143     }
144 
145     /**
146      * Called when the RebootDialog cancel is clicked.
147      */
onRebootDialogCanceled()148     public void onRebootDialogCanceled() {
149         mChanged = false;
150     }
151 }
152