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.audiostreams; 18 19 import android.bluetooth.BluetoothLeBroadcastMetadata; 20 import android.content.Context; 21 import android.content.SharedPreferences; 22 import android.util.Log; 23 24 import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt; 25 import com.android.settingslib.bluetooth.BluetoothUtils; 26 import com.android.settingslib.utils.ThreadUtils; 27 28 import java.util.concurrent.ConcurrentHashMap; 29 30 import javax.annotation.Nullable; 31 32 /** Manages the caching and storage of Bluetooth audio stream metadata. */ 33 public class AudioStreamsRepository { 34 35 private static final String TAG = "AudioStreamsRepository"; 36 private static final boolean DEBUG = BluetoothUtils.D; 37 38 private static final String PREF_KEY = "bluetooth_audio_stream_pref"; 39 private static final String METADATA_KEY = "bluetooth_audio_stream_metadata"; 40 41 @Nullable private static AudioStreamsRepository sInstance = null; 42 AudioStreamsRepository()43 private AudioStreamsRepository() {} 44 45 /** 46 * Gets the single instance of AudioStreamsRepository. 47 * 48 * @return The AudioStreamsRepository instance. 49 */ getInstance()50 public static synchronized AudioStreamsRepository getInstance() { 51 if (sInstance == null) { 52 sInstance = new AudioStreamsRepository(); 53 } 54 return sInstance; 55 } 56 57 private final ConcurrentHashMap<Integer, BluetoothLeBroadcastMetadata> 58 mBroadcastIdToMetadataCacheMap = new ConcurrentHashMap<>(); 59 60 /** 61 * Caches BluetoothLeBroadcastMetadata in a local cache. 62 * 63 * @param metadata The BluetoothLeBroadcastMetadata to be cached. 64 */ cacheMetadata(BluetoothLeBroadcastMetadata metadata)65 void cacheMetadata(BluetoothLeBroadcastMetadata metadata) { 66 if (DEBUG) { 67 Log.d( 68 TAG, 69 "cacheMetadata(): broadcastId " 70 + metadata.getBroadcastId() 71 + " saved in local cache."); 72 } 73 mBroadcastIdToMetadataCacheMap.put(metadata.getBroadcastId(), metadata); 74 } 75 76 /** 77 * Gets cached BluetoothLeBroadcastMetadata by broadcastId. 78 * 79 * @param broadcastId The broadcastId to look up in the cache. 80 * @return The cached BluetoothLeBroadcastMetadata or null if not found. 81 */ 82 @Nullable getCachedMetadata(int broadcastId)83 BluetoothLeBroadcastMetadata getCachedMetadata(int broadcastId) { 84 var metadata = mBroadcastIdToMetadataCacheMap.get(broadcastId); 85 if (metadata == null) { 86 Log.w( 87 TAG, 88 "getCachedMetadata(): broadcastId not found in" 89 + " mBroadcastIdToMetadataCacheMap."); 90 return null; 91 } 92 return metadata; 93 } 94 95 /** 96 * Saves metadata to SharedPreferences asynchronously. 97 * 98 * @param context The context. 99 * @param metadata The BluetoothLeBroadcastMetadata to be saved. 100 */ saveMetadata(Context context, BluetoothLeBroadcastMetadata metadata)101 void saveMetadata(Context context, BluetoothLeBroadcastMetadata metadata) { 102 var unused = 103 ThreadUtils.postOnBackgroundThread( 104 () -> { 105 SharedPreferences sharedPref = 106 context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE); 107 if (sharedPref != null) { 108 SharedPreferences.Editor editor = sharedPref.edit(); 109 editor.putString( 110 METADATA_KEY, 111 BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString( 112 metadata)); 113 editor.apply(); 114 if (DEBUG) { 115 Log.d( 116 TAG, 117 "saveMetadata(): broadcastId " 118 + metadata.getBroadcastId() 119 + " metadata saved in storage."); 120 } 121 } 122 }); 123 } 124 125 /** 126 * Gets saved metadata from SharedPreferences. 127 * 128 * @param context The context. 129 * @param broadcastId The broadcastId to retrieve metadata for. 130 * @return The saved BluetoothLeBroadcastMetadata or null if not found. 131 */ 132 @Nullable getSavedMetadata(Context context, int broadcastId)133 BluetoothLeBroadcastMetadata getSavedMetadata(Context context, int broadcastId) { 134 SharedPreferences sharedPref = context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE); 135 if (sharedPref != null) { 136 String savedMetadataStr = sharedPref.getString(METADATA_KEY, null); 137 if (savedMetadataStr == null) { 138 Log.w(TAG, "getSavedMetadata(): savedMetadataStr is null"); 139 return null; 140 } 141 var savedMetadata = 142 BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata( 143 savedMetadataStr); 144 if (savedMetadata == null || savedMetadata.getBroadcastId() != broadcastId) { 145 Log.w(TAG, "getSavedMetadata(): savedMetadata doesn't match broadcast Id."); 146 return null; 147 } 148 if (DEBUG) { 149 Log.d( 150 TAG, 151 "getSavedMetadata(): broadcastId " 152 + savedMetadata.getBroadcastId() 153 + " metadata found in storage."); 154 } 155 return savedMetadata; 156 } 157 return null; 158 } 159 } 160