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 static android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE; 20 21 import android.os.Handler; 22 import android.os.Looper; 23 import android.text.SpannableString; 24 import android.text.style.ForegroundColorSpan; 25 import android.util.Log; 26 27 import androidx.annotation.Nullable; 28 import androidx.annotation.StringRes; 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.Preference; 31 32 import com.android.settings.overlay.FeatureFactory; 33 import com.android.settingslib.Utils; 34 import com.android.settingslib.bluetooth.BluetoothUtils; 35 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 36 import com.android.settingslib.utils.ThreadUtils; 37 38 class AudioStreamStateHandler { 39 private static final String TAG = "AudioStreamStateHandler"; 40 private static final boolean DEBUG = BluetoothUtils.D; 41 @VisibleForTesting static final int EMPTY_STRING_RES = 0; 42 43 final Handler mHandler = new Handler(Looper.getMainLooper()); 44 final MetricsFeatureProvider mMetricsFeatureProvider = 45 FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); 46 AudioStreamsRepository mAudioStreamsRepository = AudioStreamsRepository.getInstance(); 47 AudioStreamStateHandler()48 AudioStreamStateHandler() {} 49 handleStateChange( AudioStreamPreference preference, AudioStreamsProgressCategoryController controller, AudioStreamsHelper helper)50 void handleStateChange( 51 AudioStreamPreference preference, 52 AudioStreamsProgressCategoryController controller, 53 AudioStreamsHelper helper) { 54 var newState = getStateEnum(); 55 if (preference.getAudioStreamState() == newState) { 56 return; 57 } 58 if (DEBUG) { 59 Log.d( 60 TAG, 61 "moveToState() : moving preference : [" 62 + preference.getAudioStreamBroadcastId() 63 + ", " 64 + preference.getAudioStreamBroadcastName() 65 + "] from state : " 66 + preference.getAudioStreamState() 67 + " to state : " 68 + newState); 69 } 70 preference.setAudioStreamState(newState); 71 72 performAction(preference, controller, helper); 73 74 // Update UI 75 ThreadUtils.postOnMainThread( 76 () -> { 77 String summary = 78 getSummary() != EMPTY_STRING_RES 79 ? preference.getContext().getString(getSummary()) 80 : ""; 81 if (newState 82 == AudioStreamsProgressCategoryController.AudioStreamState 83 .ADD_SOURCE_BAD_CODE) { 84 SpannableString summarySpan = new SpannableString(summary); 85 int colorError = Utils.getColorErrorDefaultColor(preference.getContext()); 86 summarySpan.setSpan( 87 new ForegroundColorSpan(colorError), 88 0, 89 summary.length(), 90 SPAN_EXCLUSIVE_INCLUSIVE); 91 preference.setSummary(summarySpan); 92 } else { 93 preference.setSummary(summary); 94 } 95 preference.setIsConnected( 96 newState 97 == AudioStreamsProgressCategoryController 98 .AudioStreamState.SOURCE_ADDED 99 || (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable( 100 preference.getContext()) 101 && newState 102 == AudioStreamsProgressCategoryController 103 .AudioStreamState.SOURCE_PRESENT)); 104 preference.setOnPreferenceClickListener(getOnClickListener(controller)); 105 }); 106 } 107 108 /** 109 * Perform action related to the audio stream state (e.g, addSource) This method is intended to 110 * be optionally overridden by subclasses to provide custom behavior based on the audio stream 111 * state change. 112 */ performAction( AudioStreamPreference preference, AudioStreamsProgressCategoryController controller, AudioStreamsHelper helper)113 void performAction( 114 AudioStreamPreference preference, 115 AudioStreamsProgressCategoryController controller, 116 AudioStreamsHelper helper) {} 117 118 /** 119 * The preference summary for the audio stream state (e.g, Scanning...) This method is intended 120 * to be optionally overridden. 121 */ 122 @StringRes getSummary()123 int getSummary() { 124 return EMPTY_STRING_RES; 125 } 126 127 /** 128 * The preference on click event for the audio stream state (e.g, open up a dialog) This method 129 * is intended to be optionally overridden. 130 */ 131 @Nullable getOnClickListener( AudioStreamsProgressCategoryController controller)132 Preference.OnPreferenceClickListener getOnClickListener( 133 AudioStreamsProgressCategoryController controller) { 134 return null; 135 } 136 137 /** Subclasses should always override. */ getStateEnum()138 AudioStreamsProgressCategoryController.AudioStreamState getStateEnum() { 139 return AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN; 140 } 141 142 @VisibleForTesting setAudioStreamsRepositoryForTesting(AudioStreamsRepository repository)143 void setAudioStreamsRepositoryForTesting(AudioStreamsRepository repository) { 144 mAudioStreamsRepository = repository; 145 } 146 } 147