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.BluetoothLeBroadcastMetadata; 20 import android.bluetooth.BluetoothLeBroadcastReceiveState; 21 import android.content.Context; 22 import android.util.AttributeSet; 23 import android.view.View; 24 25 import androidx.annotation.Nullable; 26 import androidx.annotation.VisibleForTesting; 27 import androidx.preference.PreferenceViewHolder; 28 29 import com.android.settings.R; 30 import com.android.settingslib.utils.ThreadUtils; 31 import com.android.settingslib.widget.TwoTargetPreference; 32 33 /** 34 * Custom preference class for managing audio stream preferences with an optional lock icon. Extends 35 * {@link TwoTargetPreference}. 36 */ 37 class AudioStreamPreference extends TwoTargetPreference { 38 private boolean mIsConnected = false; 39 private boolean mIsEncrypted = true; 40 @Nullable private AudioStream mAudioStream; 41 42 /** 43 * Update preference UI based on connection status 44 * 45 * @param isConnected Is this stream connected 46 * @param summary Summary text 47 * @param onPreferenceClickListener Click listener for the preference 48 */ setIsConnected( boolean isConnected, String summary, @Nullable OnPreferenceClickListener onPreferenceClickListener)49 void setIsConnected( 50 boolean isConnected, 51 String summary, 52 @Nullable OnPreferenceClickListener onPreferenceClickListener) { 53 if (mIsConnected == isConnected 54 && getSummary() == summary 55 && getOnPreferenceClickListener() == onPreferenceClickListener) { 56 // Nothing to update. 57 return; 58 } 59 mIsConnected = isConnected; 60 setSummary(summary); 61 setOnPreferenceClickListener(onPreferenceClickListener); 62 notifyChanged(); 63 } 64 65 @VisibleForTesting AudioStreamPreference(Context context, @Nullable AttributeSet attrs)66 AudioStreamPreference(Context context, @Nullable AttributeSet attrs) { 67 super(context, attrs); 68 setIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing); 69 } 70 setAudioStreamState(AudioStreamsProgressCategoryController.AudioStreamState state)71 void setAudioStreamState(AudioStreamsProgressCategoryController.AudioStreamState state) { 72 if (mAudioStream != null) { 73 mAudioStream.setState(state); 74 } 75 } 76 setAudioStreamMetadata(BluetoothLeBroadcastMetadata metadata)77 void setAudioStreamMetadata(BluetoothLeBroadcastMetadata metadata) { 78 if (mAudioStream != null) { 79 mAudioStream.setMetadata(metadata); 80 // Update title based on the metadata 81 String broadcastName = AudioStreamsHelper.getBroadcastName(metadata); 82 ThreadUtils.postOnMainThread(() -> setTitle(broadcastName)); 83 } 84 } 85 getAudioStreamBroadcastId()86 int getAudioStreamBroadcastId() { 87 return mAudioStream != null ? mAudioStream.getBroadcastId() : -1; 88 } 89 90 @Nullable getAudioStreamBroadcastName()91 String getAudioStreamBroadcastName() { 92 return mAudioStream != null ? mAudioStream.getBroadcastName() : null; 93 } 94 getAudioStreamRssi()95 int getAudioStreamRssi() { 96 return mAudioStream != null ? mAudioStream.getRssi() : -1; 97 } 98 99 @Nullable getAudioStreamMetadata()100 BluetoothLeBroadcastMetadata getAudioStreamMetadata() { 101 return mAudioStream != null ? mAudioStream.getMetadata() : null; 102 } 103 getAudioStreamState()104 AudioStreamsProgressCategoryController.AudioStreamState getAudioStreamState() { 105 return mAudioStream != null 106 ? mAudioStream.getState() 107 : AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN; 108 } 109 getSourceOriginForLogging()110 SourceOriginForLogging getSourceOriginForLogging() { 111 return mAudioStream != null 112 ? mAudioStream.getSourceOriginForLogging() 113 : SourceOriginForLogging.UNKNOWN; 114 } 115 116 @Override shouldHideSecondTarget()117 protected boolean shouldHideSecondTarget() { 118 return mIsConnected || !mIsEncrypted; 119 } 120 121 @Override getSecondTargetResId()122 protected int getSecondTargetResId() { 123 return R.layout.preference_widget_lock; 124 } 125 126 @Override onBindViewHolder(PreferenceViewHolder holder)127 public void onBindViewHolder(PreferenceViewHolder holder) { 128 super.onBindViewHolder(holder); 129 View divider = 130 holder.findViewById( 131 com.android.settingslib.widget.preference.twotarget.R.id 132 .two_target_divider); 133 if (divider != null) { 134 divider.setVisibility(View.GONE); 135 } 136 } 137 fromMetadata( Context context, BluetoothLeBroadcastMetadata source, SourceOriginForLogging sourceOriginForLogging)138 static AudioStreamPreference fromMetadata( 139 Context context, 140 BluetoothLeBroadcastMetadata source, 141 SourceOriginForLogging sourceOriginForLogging) { 142 AudioStreamPreference preference = new AudioStreamPreference(context, /* attrs= */ null); 143 preference.setIsEncrypted(source.isEncrypted()); 144 preference.setTitle(AudioStreamsHelper.getBroadcastName(source)); 145 preference.setAudioStream(new AudioStream(source, sourceOriginForLogging)); 146 return preference; 147 } 148 fromReceiveState( Context context, BluetoothLeBroadcastReceiveState receiveState)149 static AudioStreamPreference fromReceiveState( 150 Context context, BluetoothLeBroadcastReceiveState receiveState) { 151 AudioStreamPreference preference = new AudioStreamPreference(context, /* attrs= */ null); 152 preference.setTitle(AudioStreamsHelper.getBroadcastName(receiveState)); 153 preference.setAudioStream(new AudioStream(receiveState)); 154 return preference; 155 } 156 setAudioStream(AudioStream audioStream)157 private void setAudioStream(AudioStream audioStream) { 158 mAudioStream = audioStream; 159 } 160 setIsEncrypted(boolean isEncrypted)161 private void setIsEncrypted(boolean isEncrypted) { 162 mIsEncrypted = isEncrypted; 163 } 164 165 private static final class AudioStream { 166 private static final int UNAVAILABLE = -1; 167 @Nullable private BluetoothLeBroadcastMetadata mMetadata; 168 @Nullable private BluetoothLeBroadcastReceiveState mReceiveState; 169 private SourceOriginForLogging mSourceOriginForLogging = SourceOriginForLogging.UNKNOWN; 170 private AudioStreamsProgressCategoryController.AudioStreamState mState = 171 AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN; 172 AudioStream( BluetoothLeBroadcastMetadata metadata, SourceOriginForLogging sourceOriginForLogging)173 private AudioStream( 174 BluetoothLeBroadcastMetadata metadata, 175 SourceOriginForLogging sourceOriginForLogging) { 176 mMetadata = metadata; 177 mSourceOriginForLogging = sourceOriginForLogging; 178 } 179 AudioStream(BluetoothLeBroadcastReceiveState receiveState)180 private AudioStream(BluetoothLeBroadcastReceiveState receiveState) { 181 mReceiveState = receiveState; 182 } 183 getBroadcastId()184 private int getBroadcastId() { 185 return mMetadata != null 186 ? mMetadata.getBroadcastId() 187 : mReceiveState != null ? mReceiveState.getBroadcastId() : UNAVAILABLE; 188 } 189 getBroadcastName()190 private @Nullable String getBroadcastName() { 191 return mMetadata != null 192 ? AudioStreamsHelper.getBroadcastName(mMetadata) 193 : mReceiveState != null 194 ? AudioStreamsHelper.getBroadcastName(mReceiveState) 195 : null; 196 } 197 getRssi()198 private int getRssi() { 199 return mMetadata != null ? mMetadata.getRssi() : Integer.MAX_VALUE; 200 } 201 getState()202 private AudioStreamsProgressCategoryController.AudioStreamState getState() { 203 return mState; 204 } 205 getSourceOriginForLogging()206 private SourceOriginForLogging getSourceOriginForLogging() { 207 return mSourceOriginForLogging; 208 } 209 210 @Nullable getMetadata()211 private BluetoothLeBroadcastMetadata getMetadata() { 212 return mMetadata; 213 } 214 setState(AudioStreamsProgressCategoryController.AudioStreamState state)215 private void setState(AudioStreamsProgressCategoryController.AudioStreamState state) { 216 mState = state; 217 } 218 setMetadata(BluetoothLeBroadcastMetadata metadata)219 private void setMetadata(BluetoothLeBroadcastMetadata metadata) { 220 mMetadata = metadata; 221 } 222 } 223 } 224