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