1 /* 2 * Copyright 2021 HIMSA II K/S - www.himsa.com. 3 * Represented by EHIMA - www.ehima.com 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bluetooth.leaudio; 19 20 import android.app.Application; 21 import android.bluetooth.BluetoothDevice; 22 import android.bluetooth.BluetoothLeBroadcastMetadata; 23 24 import androidx.annotation.NonNull; 25 import androidx.lifecycle.AndroidViewModel; 26 import androidx.lifecycle.LiveData; 27 import androidx.lifecycle.MutableLiveData; 28 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.List; 32 33 public class BroadcastScanViewModel extends AndroidViewModel { 34 private final String TAG = "BroadcastScanViewModel"; 35 boolean mIsActivityScanning = false; 36 BluetoothDevice mScanDelegatorDevice; 37 38 // TODO: Remove these variables if they are unnecessary 39 // // AddBroadcast context 40 // BluetoothDevice mSetSrcTargetDevice; 41 // List<BluetoothBroadcastAudioScanBaseConfig> mSetSrcConfigs; 42 // boolean mSetSrcSyncPa; 43 44 BluetoothProxy mBluetooth; 45 Application mApplication; 46 private MutableLiveData<List<BluetoothLeBroadcastMetadata>> mAllBroadcasts = 47 new MutableLiveData<>(); 48 private HashMap<Integer, BluetoothLeBroadcastMetadata> mScanSessionBroadcasts = new HashMap<>(); 49 50 private final BluetoothProxy.OnBassEventListener mBassEventListener = 51 new BluetoothProxy.OnBassEventListener() { 52 @Override 53 public void onSourceFound(BluetoothLeBroadcastMetadata source) { 54 mScanSessionBroadcasts.put(source.getBroadcastId(), source); 55 refreshBroadcasts(); 56 } 57 58 @Override 59 public void onScanningStateChanged(boolean isScanning) { 60 if (!isScanning) { 61 // Update the live broadcast list and clear scan session results 62 List<BluetoothLeBroadcastMetadata> localSessionBroadcasts = 63 mBluetooth.getAllLocalBroadcasts(); 64 ArrayList<BluetoothLeBroadcastMetadata> new_arr; 65 if (localSessionBroadcasts != null) { 66 new_arr = new ArrayList<>(localSessionBroadcasts); 67 } else { 68 new_arr = new ArrayList<>(); 69 } 70 new_arr.addAll(mScanSessionBroadcasts.values()); 71 mAllBroadcasts.postValue(new_arr); 72 73 // Continue as long as the main activity wants 74 if (mIsActivityScanning) { 75 if (mScanDelegatorDevice != null) { 76 mBluetooth.scanForBroadcasts(mScanDelegatorDevice, true); 77 } 78 } 79 } else { 80 // FIXME: Clear won't work - it would auto-update the mutable and clear it 81 // as 82 // mutable uses reference to its values 83 mScanSessionBroadcasts = new HashMap<>(); 84 } 85 } 86 }; 87 88 private final BluetoothProxy.OnLocalBroadcastEventListener mLocalBroadcastEventListener = 89 new BluetoothProxy.OnLocalBroadcastEventListener() { 90 @Override 91 public void onBroadcastStarted(int broadcastId) { 92 // FIXME: We need a finer grain control over updating individual broadcast state 93 // and not just the entire list of broadcasts 94 refreshBroadcasts(); 95 } 96 97 @Override 98 public void onBroadcastStopped(int broadcastId) { 99 refreshBroadcasts(); 100 } 101 102 @Override 103 public void onBroadcastUpdated(int broadcastId) { 104 refreshBroadcasts(); 105 } 106 107 @Override 108 public void onBroadcastMetadataChanged( 109 int broadcastId, BluetoothLeBroadcastMetadata metadata) { 110 refreshBroadcasts(); 111 } 112 }; 113 BroadcastScanViewModel(@onNull Application application)114 public BroadcastScanViewModel(@NonNull Application application) { 115 super(application); 116 mApplication = application; 117 mBluetooth = BluetoothProxy.getBluetoothProxy(application); 118 119 mBluetooth.setOnBassEventListener(mBassEventListener); 120 mBluetooth.setOnLocalBroadcastEventListener(mLocalBroadcastEventListener); 121 } 122 123 @Override onCleared()124 public void onCleared() { 125 mBluetooth.setOnBassEventListener(null); 126 mBluetooth.setOnLocalBroadcastEventListener(null); 127 } 128 getAllBroadcasts()129 public LiveData<List<BluetoothLeBroadcastMetadata>> getAllBroadcasts() { 130 return mAllBroadcasts; 131 } 132 scanForBroadcasts(BluetoothDevice delegatorDevice, boolean scan)133 public void scanForBroadcasts(BluetoothDevice delegatorDevice, boolean scan) { 134 mIsActivityScanning = scan; 135 mScanDelegatorDevice = delegatorDevice; 136 137 // First update the live broadcast list 138 List<BluetoothLeBroadcastMetadata> localSessionBroadcasts = 139 mBluetooth.getAllLocalBroadcasts(); 140 ArrayList<BluetoothLeBroadcastMetadata> new_arr; 141 if (localSessionBroadcasts != null) { 142 new_arr = new ArrayList<>(localSessionBroadcasts); 143 } else { 144 new_arr = new ArrayList<>(); 145 } 146 new_arr.addAll(mScanSessionBroadcasts.values()); 147 mAllBroadcasts.postValue(new_arr); 148 149 mBluetooth.scanForBroadcasts(mScanDelegatorDevice, scan); 150 } 151 addBroadcastSource( BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata)152 public void addBroadcastSource( 153 BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata) { 154 mBluetooth.addBroadcastSource(sink, sourceMetadata); 155 } 156 refreshBroadcasts()157 public void refreshBroadcasts() { 158 // Concatenate local broadcasts to the scanned broadcast list 159 List<BluetoothLeBroadcastMetadata> localSessionBroadcasts = 160 mBluetooth.getAllLocalBroadcasts(); 161 ArrayList<BluetoothLeBroadcastMetadata> new_arr = new ArrayList<>(localSessionBroadcasts); 162 new_arr.addAll(mScanSessionBroadcasts.values()); 163 mAllBroadcasts.postValue(new_arr); 164 } 165 } 166