1 /* 2 * Copyright (C) 2019 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.development.bluetooth; 18 19 import android.bluetooth.BluetoothA2dp; 20 import android.bluetooth.BluetoothCodecConfig; 21 import android.bluetooth.BluetoothDevice; 22 import android.content.Context; 23 import android.util.Log; 24 25 import androidx.annotation.VisibleForTesting; 26 import androidx.preference.PreferenceScreen; 27 28 import com.android.settings.development.BluetoothA2dpConfigStore; 29 import com.android.settingslib.core.lifecycle.Lifecycle; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * Dialog preference controller to set the Bluetooth A2DP config of codec 36 */ 37 public class BluetoothCodecDialogPreferenceController extends 38 AbstractBluetoothDialogPreferenceController { 39 40 private static final String KEY = "bluetooth_audio_codec_settings"; 41 private static final String TAG = "BtCodecCtr"; 42 43 private final Callback mCallback; 44 BluetoothCodecDialogPreferenceController(Context context, Lifecycle lifecycle, BluetoothA2dpConfigStore store, Callback callback)45 public BluetoothCodecDialogPreferenceController(Context context, Lifecycle lifecycle, 46 BluetoothA2dpConfigStore store, 47 Callback callback) { 48 super(context, lifecycle, store); 49 mCallback = callback; 50 } 51 52 @Override getPreferenceKey()53 public String getPreferenceKey() { 54 return KEY; 55 } 56 57 @Override displayPreference(PreferenceScreen screen)58 public void displayPreference(PreferenceScreen screen) { 59 super.displayPreference(screen); 60 ((BaseBluetoothDialogPreference) mPreference).setCallback(this); 61 } 62 63 @Override onHDAudioEnabled(boolean enabled)64 public void onHDAudioEnabled(boolean enabled) { 65 if (!enabled) { 66 // If option codec is disabled, SBC is the only only one available codec. 67 onIndexUpdated(convertCfgToBtnIndex(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC)); 68 } 69 } 70 71 @Override getSelectableIndex()72 public List<Integer> getSelectableIndex() { 73 List<Integer> index = new ArrayList<>(); 74 final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp; 75 76 index.add(getDefaultIndex()); 77 if (bluetoothA2dp == null) { 78 return index; 79 } 80 final BluetoothDevice activeDevice = bluetoothA2dp.getActiveDevice(); 81 if (activeDevice == null) { 82 Log.d(TAG, "Unable to get selectable index. No Active Bluetooth device"); 83 return index; 84 } 85 // Check HD audio is enabled, display the available list. 86 if (bluetoothA2dp.isOptionalCodecsEnabled(activeDevice) 87 == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) { 88 BluetoothCodecConfig[] configs = getSelectableConfigs(activeDevice); 89 if (configs != null) { 90 return getIndexFromConfig(configs); 91 } 92 } 93 // If HD audio is disabled, SBC is the only one available codec. 94 index.add(convertCfgToBtnIndex(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC)); 95 return index; 96 } 97 98 @Override writeConfigurationValues(final int index)99 protected void writeConfigurationValues(final int index) { 100 int codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC; // default 101 int codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; 102 switch (index) { 103 case 0: 104 codecTypeValue = getHighestCodec(getSelectableConfigs( 105 mBluetoothA2dp.getActiveDevice())); 106 codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; 107 break; 108 case 1: 109 codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC; 110 codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; 111 break; 112 case 2: 113 codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC; 114 codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; 115 break; 116 case 3: 117 codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX; 118 codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; 119 break; 120 case 4: 121 codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD; 122 codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; 123 break; 124 case 5: 125 codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC; 126 codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; 127 break; 128 default: 129 break; 130 } 131 mBluetoothA2dpConfigStore.setCodecType(codecTypeValue); 132 mBluetoothA2dpConfigStore.setCodecPriority(codecPriorityValue); 133 134 // Once user changes codec, to reset configs with highest quality. 135 final BluetoothCodecConfig config = getSelectableByCodecType(codecTypeValue); 136 if (config == null) { 137 Log.d(TAG, "Selectable config is null. Unable to reset"); 138 } 139 mBluetoothA2dpConfigStore.setSampleRate(getHighestSampleRate(config)); 140 mBluetoothA2dpConfigStore.setBitsPerSample(getHighestBitsPerSample(config)); 141 mBluetoothA2dpConfigStore.setChannelMode(getHighestChannelMode(config)); 142 } 143 144 @Override getCurrentIndexByConfig(BluetoothCodecConfig config)145 protected int getCurrentIndexByConfig(BluetoothCodecConfig config) { 146 if (config == null) { 147 Log.e(TAG, "Unable to get current config index. Config is null."); 148 } 149 return convertCfgToBtnIndex(config.getCodecType()); 150 } 151 152 @Override onIndexUpdated(int index)153 public void onIndexUpdated(int index) { 154 super.onIndexUpdated(index); 155 mCallback.onBluetoothCodecChanged(); 156 } 157 getIndexFromConfig(BluetoothCodecConfig[] configs)158 private List<Integer> getIndexFromConfig(BluetoothCodecConfig[] configs) { 159 List<Integer> indexArray = new ArrayList<>(); 160 for (int i = 0; i < configs.length; i++) { 161 indexArray.add(convertCfgToBtnIndex(configs[i].getCodecType())); 162 } 163 return indexArray; 164 } 165 166 @VisibleForTesting convertCfgToBtnIndex(int config)167 int convertCfgToBtnIndex(int config) { 168 int index = getDefaultIndex(); 169 switch (config) { 170 case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC: 171 index = 1; 172 break; 173 case BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC: 174 index = 2; 175 break; 176 case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX: 177 index = 3; 178 break; 179 case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD: 180 index = 4; 181 break; 182 case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC: 183 index = 5; 184 break; 185 default: 186 Log.e(TAG, "Unsupported config:" + config); 187 break; 188 } 189 return index; 190 } 191 } 192