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