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.annotation.VisibleForTesting;
26 import androidx.lifecycle.DefaultLifecycleObserver;
27 import androidx.lifecycle.LifecycleOwner;
28 import androidx.preference.Preference;
29 import androidx.preference.PreferenceScreen;
30 
31 import com.android.settings.R;
32 import com.android.settings.bluetooth.Utils;
33 import com.android.settings.core.BasePreferenceController;
34 import com.android.settings.core.SubSettingLauncher;
35 import com.android.settingslib.bluetooth.BluetoothCallback;
36 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
37 import com.android.settingslib.bluetooth.LocalBluetoothManager;
38 import com.android.settingslib.utils.ThreadUtils;
39 
40 public class AudioStreamsScanQrCodeController extends BasePreferenceController
41         implements DefaultLifecycleObserver {
42     static final int REQUEST_SCAN_BT_BROADCAST_QR_CODE = 0;
43     private static final String TAG = "AudioStreamsProgressCategoryController";
44     @VisibleForTesting static final String KEY = "audio_streams_scan_qr_code";
45 
46     @VisibleForTesting
47     final BluetoothCallback mBluetoothCallback =
48             new BluetoothCallback() {
49                 @Override
50                 public void onActiveDeviceChanged(
51                         @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
52                     if (bluetoothProfile == BluetoothProfile.LE_AUDIO) {
53                         updateVisibility();
54                     }
55                 }
56             };
57 
58     @Nullable private final LocalBluetoothManager mLocalBtManager;
59     @Nullable private AudioStreamsDashboardFragment mFragment;
60     @Nullable private Preference mPreference;
61 
AudioStreamsScanQrCodeController(Context context, String preferenceKey)62     public AudioStreamsScanQrCodeController(Context context, String preferenceKey) {
63         super(context, preferenceKey);
64         mLocalBtManager = Utils.getLocalBtManager(mContext);
65     }
66 
setFragment(AudioStreamsDashboardFragment fragment)67     public void setFragment(AudioStreamsDashboardFragment fragment) {
68         mFragment = fragment;
69     }
70 
71     @Override
onStart(@onNull LifecycleOwner owner)72     public void onStart(@NonNull LifecycleOwner owner) {
73         if (mLocalBtManager != null) {
74             mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback);
75         }
76     }
77 
78     @Override
onStop(@onNull LifecycleOwner owner)79     public void onStop(@NonNull LifecycleOwner owner) {
80         if (mLocalBtManager != null) {
81             mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback);
82         }
83     }
84 
85     @Override
getAvailabilityStatus()86     public int getAvailabilityStatus() {
87         return AVAILABLE;
88     }
89 
90     @Override
getPreferenceKey()91     public String getPreferenceKey() {
92         return KEY;
93     }
94 
95     @Override
displayPreference(PreferenceScreen screen)96     public void displayPreference(PreferenceScreen screen) {
97         super.displayPreference(screen);
98         mPreference = screen.findPreference(getPreferenceKey());
99         if (mPreference == null) {
100             Log.w(TAG, "displayPreference() mPreference is null!");
101             return;
102         }
103         mPreference.setOnPreferenceClickListener(
104                 preference -> {
105                     if (mFragment == null) {
106                         Log.w(TAG, "displayPreference() mFragment is null!");
107                         return false;
108                     }
109                     if (preference.getKey().equals(KEY)) {
110                         new SubSettingLauncher(mContext)
111                                 .setTitleRes(R.string.audio_streams_main_page_scan_qr_code_title)
112                                 .setDestination(AudioStreamsQrCodeScanFragment.class.getName())
113                                 .setResultListener(mFragment, REQUEST_SCAN_BT_BROADCAST_QR_CODE)
114                                 .setSourceMetricsCategory(mFragment.getMetricsCategory())
115                                 .launch();
116                         return true;
117                     }
118                     return false;
119                 });
120     }
121 
updateVisibility()122     private void updateVisibility() {
123         var unused =
124                 ThreadUtils.postOnBackgroundThread(
125                         () -> {
126                             boolean hasConnectedLe =
127                                     AudioStreamsHelper
128                                             .getCachedBluetoothDeviceInSharingOrLeConnected(
129                                                     mLocalBtManager)
130                                             .isPresent();
131                             ThreadUtils.postOnMainThread(
132                                     () -> {
133                                         if (mPreference != null) {
134                                             mPreference.setVisible(hasConnectedLe);
135                                         }
136                                     });
137                         });
138     }
139 }
140