1 /*
2  * Copyright (C) 2024 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;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.util.Log;
25 
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.VisibleForTesting;
29 import androidx.lifecycle.DefaultLifecycleObserver;
30 import androidx.lifecycle.LifecycleOwner;
31 import androidx.preference.Preference;
32 import androidx.preference.PreferenceScreen;
33 
34 import com.android.settings.bluetooth.Utils;
35 import com.android.settings.core.BasePreferenceController;
36 import com.android.settingslib.bluetooth.LocalBluetoothManager;
37 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
38 
39 public class StreamSettingsCategoryController extends BasePreferenceController
40         implements DefaultLifecycleObserver, LocalBluetoothProfileManager.ServiceListener {
41     private static final String TAG = "StreamSettingsCategoryController";
42     private final BluetoothAdapter mBluetoothAdapter;
43     @Nullable private final LocalBluetoothManager mBtManager;
44     @Nullable private final LocalBluetoothProfileManager mProfileManager;
45     @Nullable private Preference mPreference;
46     @VisibleForTesting final IntentFilter mIntentFilter;
47 
48     @VisibleForTesting
49     BroadcastReceiver mReceiver =
50             new BroadcastReceiver() {
51                 @Override
52                 public void onReceive(Context context, Intent intent) {
53                     if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) return;
54                     updateVisibility();
55                 }
56             };
57 
StreamSettingsCategoryController(Context context, String key)58     public StreamSettingsCategoryController(Context context, String key) {
59         super(context, key);
60         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
61         mBtManager = Utils.getLocalBtManager(context);
62         mProfileManager = mBtManager == null ? null : mBtManager.getProfileManager();
63         mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
64     }
65 
66     @Override
onStart(@onNull LifecycleOwner owner)67     public void onStart(@NonNull LifecycleOwner owner) {
68         if (!isAvailable()) return;
69         mContext.registerReceiver(mReceiver, mIntentFilter, Context.RECEIVER_EXPORTED_UNAUDITED);
70         if (!isProfileReady() && mProfileManager != null) {
71             mProfileManager.addServiceListener(this);
72         }
73     }
74 
75     @Override
onStop(@onNull LifecycleOwner owner)76     public void onStop(@NonNull LifecycleOwner owner) {
77         if (!isAvailable()) return;
78         mContext.unregisterReceiver(mReceiver);
79         if (mProfileManager != null) {
80             mProfileManager.removeServiceListener(this);
81         }
82     }
83 
84     @Override
displayPreference(PreferenceScreen screen)85     public void displayPreference(PreferenceScreen screen) {
86         super.displayPreference(screen);
87         mPreference = screen.findPreference(getPreferenceKey());
88         updateVisibility();
89     }
90 
91     @Override
getAvailabilityStatus()92     public int getAvailabilityStatus() {
93         return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
94     }
95 
96     @Override
onServiceConnected()97     public void onServiceConnected() {
98         if (isAvailable() && isProfileReady()) {
99             updateVisibility();
100             if (mProfileManager != null) {
101                 mProfileManager.removeServiceListener(this);
102             }
103         }
104     }
105 
106     @Override
onServiceDisconnected()107     public void onServiceDisconnected() {
108         // Do nothing
109     }
110 
updateVisibility()111     private void updateVisibility() {
112         if (mPreference == null) {
113             Log.w(TAG, "Skip updateVisibility, null preference");
114             return;
115         }
116         if (!isAvailable()) {
117             Log.w(TAG, "Skip updateVisibility, unavailable preference");
118             AudioSharingUtils.postOnMainThread(
119                     mContext,
120                     () -> { // Check nullability to pass NullAway check
121                         if (mPreference != null) {
122                             mPreference.setVisible(false);
123                         }
124                     });
125             return;
126         }
127         boolean visible = isBluetoothOn() && isProfileReady();
128         AudioSharingUtils.postOnMainThread(
129                 mContext,
130                 () -> { // Check nullability to pass NullAway check
131                     if (mPreference != null) {
132                         mPreference.setVisible(visible);
133                     }
134                 });
135     }
136 
isBluetoothOn()137     private boolean isBluetoothOn() {
138         return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
139     }
140 
isProfileReady()141     private boolean isProfileReady() {
142         return AudioSharingUtils.isAudioSharingProfileReady(mProfileManager);
143     }
144 }
145