1 /*
2  * Copyright (C) 2023 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.connecteddevice.audiosharing.audiostreams;
18 
19 import android.bluetooth.BluetoothProfile;
20 import android.content.Context;
21 import android.util.Log;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 import androidx.lifecycle.LifecycleOwner;
26 
27 import com.android.settings.bluetooth.Utils;
28 import com.android.settings.connecteddevice.audiosharing.AudioSharingBasePreferenceController;
29 import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
30 import com.android.settingslib.bluetooth.BluetoothCallback;
31 import com.android.settingslib.bluetooth.BluetoothUtils;
32 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
33 import com.android.settingslib.bluetooth.LocalBluetoothManager;
34 import com.android.settingslib.flags.Flags;
35 
36 import java.util.concurrent.Executor;
37 import java.util.concurrent.Executors;
38 
39 public class AudioStreamsCategoryController extends AudioSharingBasePreferenceController {
40     private static final String TAG = "AudioStreamsCategoryController";
41     private static final boolean DEBUG = BluetoothUtils.D;
42     private final LocalBluetoothManager mLocalBtManager;
43     private final Executor mExecutor;
44     private final BluetoothCallback mBluetoothCallback =
45             new BluetoothCallback() {
46                 @Override
47                 public void onActiveDeviceChanged(
48                         @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
49                     if (bluetoothProfile == BluetoothProfile.LE_AUDIO) {
50                         updateVisibility();
51                     }
52                 }
53             };
54 
AudioStreamsCategoryController(Context context, String key)55     public AudioStreamsCategoryController(Context context, String key) {
56         super(context, key);
57         mLocalBtManager = Utils.getLocalBtManager(mContext);
58         mExecutor = Executors.newSingleThreadExecutor();
59     }
60 
61     @Override
onStart(@onNull LifecycleOwner owner)62     public void onStart(@NonNull LifecycleOwner owner) {
63         if (!isAvailable()) return;
64         super.onStart(owner);
65         if (mLocalBtManager != null) {
66             mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback);
67         }
68     }
69 
70     @Override
onStop(@onNull LifecycleOwner owner)71     public void onStop(@NonNull LifecycleOwner owner) {
72         if (!isAvailable()) return;
73         super.onStop(owner);
74         if (mLocalBtManager != null) {
75             mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback);
76         }
77     }
78 
79     @Override
getAvailabilityStatus()80     public int getAvailabilityStatus() {
81         return Flags.enableLeAudioQrCodePrivateBroadcastSharing()
82                 ? AVAILABLE
83                 : UNSUPPORTED_ON_DEVICE;
84     }
85 
86     @Override
updateVisibility()87     public void updateVisibility() {
88         if (mPreference == null) return;
89         mExecutor.execute(
90                 () -> {
91                     if (!isAvailable()) {
92                         Log.d(TAG, "skip updateVisibility, unavailable preference");
93                         AudioSharingUtils.postOnMainThread(
94                                 mContext,
95                                 () -> { // Check nullability to pass NullAway check
96                                     if (mPreference != null) {
97                                         mPreference.setVisible(false);
98                                     }
99                                 });
100                         return;
101                     }
102                     boolean hasConnectedLe =
103                             AudioStreamsHelper.getCachedBluetoothDeviceInSharingOrLeConnected(
104                                             mLocalBtManager)
105                                     .isPresent();
106                     boolean isProfileReady =
107                             AudioSharingUtils.isAudioSharingProfileReady(
108                                     mLocalBtManager.getProfileManager());
109                     boolean isBroadcasting = isBroadcasting();
110                     boolean isBluetoothOn = isBluetoothStateOn();
111                     if (DEBUG) {
112                         Log.d(
113                                 TAG,
114                                 "updateVisibility() isBroadcasting : "
115                                         + isBroadcasting
116                                         + " hasConnectedLe : "
117                                         + hasConnectedLe
118                                         + " is BT on : "
119                                         + isBluetoothOn
120                                         + " is profile ready : "
121                                         + isProfileReady);
122                     }
123                     AudioSharingUtils.postOnMainThread(
124                             mContext,
125                             () -> { // Check nullability to pass NullAway check
126                                 if (mPreference != null) {
127                                     mPreference.setVisible(
128                                             isProfileReady
129                                                     && isBluetoothOn
130                                                     && hasConnectedLe
131                                                     && !isBroadcasting);
132                                 }
133                             });
134                 });
135     }
136 }
137