1 /* 2 * Copyright (C) 2016 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.bluetooth.avrcpcontroller; 18 19 import android.bluetooth.BluetoothAvrcpPlayerSettings; 20 import android.util.Log; 21 22 import java.util.ArrayList; 23 import java.util.HashMap; 24 import java.util.Map; 25 26 /* 27 * Contains information Player Application Setting extended from BluetootAvrcpPlayerSettings 28 */ 29 class PlayerApplicationSettings { 30 private static final String TAG = "PlayerApplicationSettings"; 31 32 /* 33 * Values for SetPlayerApplicationSettings from AVRCP Spec V1.6 Appendix F. 34 */ 35 private static final byte JNI_ATTRIB_EQUALIZER_STATUS = 0x01; 36 private static final byte JNI_ATTRIB_REPEAT_STATUS = 0x02; 37 private static final byte JNI_ATTRIB_SHUFFLE_STATUS = 0x03; 38 private static final byte JNI_ATTRIB_SCAN_STATUS = 0x04; 39 40 private static final byte JNI_EQUALIZER_STATUS_OFF = 0x01; 41 private static final byte JNI_EQUALIZER_STATUS_ON = 0x02; 42 43 private static final byte JNI_REPEAT_STATUS_OFF = 0x01; 44 private static final byte JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT = 0x02; 45 private static final byte JNI_REPEAT_STATUS_ALL_TRACK_REPEAT = 0x03; 46 private static final byte JNI_REPEAT_STATUS_GROUP_REPEAT = 0x04; 47 48 private static final byte JNI_SHUFFLE_STATUS_OFF = 0x01; 49 private static final byte JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE = 0x02; 50 private static final byte JNI_SHUFFLE_STATUS_GROUP_SHUFFLE = 0x03; 51 52 private static final byte JNI_SCAN_STATUS_OFF = 0x01; 53 private static final byte JNI_SCAN_STATUS_ALL_TRACK_SCAN = 0x02; 54 private static final byte JNI_SCAN_STATUS_GROUP_SCAN = 0x03; 55 56 private static final byte JNI_STATUS_INVALID = -1; 57 58 59 /* 60 * Hash map of current settings. 61 */ 62 private Map<Integer, Integer> mSettings = new HashMap<Integer, Integer>(); 63 64 /* 65 * Hash map of supported values, a setting should be supported by the remote in order to enable 66 * in mSettings. 67 */ 68 private Map<Integer, ArrayList<Integer>> mSupportedValues = 69 new HashMap<Integer, ArrayList<Integer>>(); 70 71 /* Convert from JNI array to Java classes. */ 72 static PlayerApplicationSettings makeSupportedSettings(byte[] btAvrcpAttributeList) { 73 PlayerApplicationSettings newObj = new PlayerApplicationSettings(); 74 try { 75 for (int i = 0; i < btAvrcpAttributeList.length; ) { 76 byte attrId = btAvrcpAttributeList[i++]; 77 byte numSupportedVals = btAvrcpAttributeList[i++]; 78 ArrayList<Integer> supportedValues = new ArrayList<Integer>(); 79 80 for (int j = 0; j < numSupportedVals; j++) { 81 // Yes, keep using i for array indexing. 82 supportedValues.add( 83 mapAttribIdValtoAvrcpPlayerSetting(attrId, btAvrcpAttributeList[i++])); 84 } 85 newObj.mSupportedValues.put(mapBTAttribIdToAvrcpPlayerSettings(attrId), 86 supportedValues); 87 } 88 } catch (ArrayIndexOutOfBoundsException exception) { 89 Log.e(TAG, "makeSupportedSettings attributeList index error."); 90 } 91 return newObj; 92 } 93 94 public BluetoothAvrcpPlayerSettings getAvrcpSettings() { 95 int supportedSettings = 0; 96 for (Integer setting : mSettings.keySet()) { 97 supportedSettings |= setting; 98 } 99 BluetoothAvrcpPlayerSettings result = new BluetoothAvrcpPlayerSettings(supportedSettings); 100 for (Integer setting : mSettings.keySet()) { 101 result.addSettingValue(setting, mSettings.get(setting)); 102 } 103 return result; 104 } 105 106 static PlayerApplicationSettings makeSettings(byte[] btAvrcpAttributeList) { 107 PlayerApplicationSettings newObj = new PlayerApplicationSettings(); 108 try { 109 for (int i = 0; i < btAvrcpAttributeList.length; ) { 110 byte attrId = btAvrcpAttributeList[i++]; 111 112 newObj.mSettings.put(mapBTAttribIdToAvrcpPlayerSettings(attrId), 113 mapAttribIdValtoAvrcpPlayerSetting(attrId, btAvrcpAttributeList[i++])); 114 } 115 } catch (ArrayIndexOutOfBoundsException exception) { 116 Log.e(TAG, "makeSettings JNI_ATTRIButeList index error."); 117 } 118 return newObj; 119 } 120 121 public void setSupport(PlayerApplicationSettings updates) { 122 mSettings = updates.mSettings; 123 mSupportedValues = updates.mSupportedValues; 124 } 125 126 public void setValues(BluetoothAvrcpPlayerSettings updates) { 127 int supportedSettings = updates.getSettings(); 128 for (int i = 1; i <= BluetoothAvrcpPlayerSettings.SETTING_SCAN; i++) { 129 if ((i & supportedSettings) > 0) { 130 mSettings.put(i, updates.getSettingValue(i)); 131 } 132 } 133 } 134 135 /* 136 * Check through all settings to ensure that they are all available to be set and then check 137 * that the desired value is in fact supported by our remote player. 138 */ 139 public boolean supportsSettings(BluetoothAvrcpPlayerSettings settingsToCheck) { 140 int settingSubset = settingsToCheck.getSettings(); 141 int supportedSettings = 0; 142 for (Integer setting : mSupportedValues.keySet()) { 143 supportedSettings |= setting; 144 } 145 try { 146 if ((supportedSettings & settingSubset) == settingSubset) { 147 for (Integer settingId : mSettings.keySet()) { 148 // The setting is in both settings to check and supported settings but the 149 // value is not supported. 150 if ((settingId & settingSubset) == settingId && (!mSupportedValues.get( 151 settingId).contains(settingsToCheck.getSettingValue(settingId)))) { 152 return false; 153 } 154 } 155 return true; 156 } 157 } catch (NullPointerException e) { 158 Log.e(TAG, 159 "supportsSettings received a supported setting that has no supported values."); 160 } 161 return false; 162 } 163 164 // Convert currently desired settings into an attribute array to pass to the native layer to 165 // enable them. 166 public ArrayList<Byte> getNativeSettings() { 167 int i = 0; 168 ArrayList<Byte> attribArray = new ArrayList<Byte>(); 169 for (Integer settingId : mSettings.keySet()) { 170 switch (settingId) { 171 case BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER: 172 attribArray.add(JNI_ATTRIB_EQUALIZER_STATUS); 173 attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId, 174 mSettings.get(settingId))); 175 break; 176 case BluetoothAvrcpPlayerSettings.SETTING_REPEAT: 177 attribArray.add(JNI_ATTRIB_REPEAT_STATUS); 178 attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId, 179 mSettings.get(settingId))); 180 break; 181 case BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE: 182 attribArray.add(JNI_ATTRIB_SHUFFLE_STATUS); 183 attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId, 184 mSettings.get(settingId))); 185 break; 186 case BluetoothAvrcpPlayerSettings.SETTING_SCAN: 187 attribArray.add(JNI_ATTRIB_SCAN_STATUS); 188 attribArray.add(mapAvrcpPlayerSettingstoBTattribVal(settingId, 189 mSettings.get(settingId))); 190 break; 191 default: 192 Log.w(TAG, "Unknown setting found in getNativeSettings: " + settingId); 193 } 194 } 195 return attribArray; 196 } 197 198 // Convert a native Attribute Id/Value pair into the AVRCP equivalent value. 199 private static int mapAttribIdValtoAvrcpPlayerSetting(byte attribId, byte attribVal) { 200 if (attribId == JNI_ATTRIB_EQUALIZER_STATUS) { 201 switch (attribVal) { 202 case JNI_EQUALIZER_STATUS_OFF: 203 return BluetoothAvrcpPlayerSettings.STATE_OFF; 204 case JNI_EQUALIZER_STATUS_ON: 205 return BluetoothAvrcpPlayerSettings.STATE_ON; 206 } 207 } else if (attribId == JNI_ATTRIB_REPEAT_STATUS) { 208 switch (attribVal) { 209 case JNI_REPEAT_STATUS_ALL_TRACK_REPEAT: 210 return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK; 211 case JNI_REPEAT_STATUS_GROUP_REPEAT: 212 return BluetoothAvrcpPlayerSettings.STATE_GROUP; 213 case JNI_REPEAT_STATUS_OFF: 214 return BluetoothAvrcpPlayerSettings.STATE_OFF; 215 case JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT: 216 return BluetoothAvrcpPlayerSettings.STATE_SINGLE_TRACK; 217 } 218 } else if (attribId == JNI_ATTRIB_SCAN_STATUS) { 219 switch (attribVal) { 220 case JNI_SCAN_STATUS_ALL_TRACK_SCAN: 221 return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK; 222 case JNI_SCAN_STATUS_GROUP_SCAN: 223 return BluetoothAvrcpPlayerSettings.STATE_GROUP; 224 case JNI_SCAN_STATUS_OFF: 225 return BluetoothAvrcpPlayerSettings.STATE_OFF; 226 } 227 } else if (attribId == JNI_ATTRIB_SHUFFLE_STATUS) { 228 switch (attribVal) { 229 case JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE: 230 return BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK; 231 case JNI_SHUFFLE_STATUS_GROUP_SHUFFLE: 232 return BluetoothAvrcpPlayerSettings.STATE_GROUP; 233 case JNI_SHUFFLE_STATUS_OFF: 234 return BluetoothAvrcpPlayerSettings.STATE_OFF; 235 } 236 } 237 return BluetoothAvrcpPlayerSettings.STATE_INVALID; 238 } 239 240 // Convert an AVRCP Setting/Value pair into the native equivalent value; 241 private static byte mapAvrcpPlayerSettingstoBTattribVal(int mSetting, int mSettingVal) { 242 if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER) { 243 switch (mSettingVal) { 244 case BluetoothAvrcpPlayerSettings.STATE_OFF: 245 return JNI_EQUALIZER_STATUS_OFF; 246 case BluetoothAvrcpPlayerSettings.STATE_ON: 247 return JNI_EQUALIZER_STATUS_ON; 248 } 249 } else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_REPEAT) { 250 switch (mSettingVal) { 251 case BluetoothAvrcpPlayerSettings.STATE_OFF: 252 return JNI_REPEAT_STATUS_OFF; 253 case BluetoothAvrcpPlayerSettings.STATE_SINGLE_TRACK: 254 return JNI_REPEAT_STATUS_SINGLE_TRACK_REPEAT; 255 case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK: 256 return JNI_REPEAT_STATUS_ALL_TRACK_REPEAT; 257 case BluetoothAvrcpPlayerSettings.STATE_GROUP: 258 return JNI_REPEAT_STATUS_GROUP_REPEAT; 259 } 260 } else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE) { 261 switch (mSettingVal) { 262 case BluetoothAvrcpPlayerSettings.STATE_OFF: 263 return JNI_SHUFFLE_STATUS_OFF; 264 case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK: 265 return JNI_SHUFFLE_STATUS_ALL_TRACK_SHUFFLE; 266 case BluetoothAvrcpPlayerSettings.STATE_GROUP: 267 return JNI_SHUFFLE_STATUS_GROUP_SHUFFLE; 268 } 269 } else if (mSetting == BluetoothAvrcpPlayerSettings.SETTING_SCAN) { 270 switch (mSettingVal) { 271 case BluetoothAvrcpPlayerSettings.STATE_OFF: 272 return JNI_SCAN_STATUS_OFF; 273 case BluetoothAvrcpPlayerSettings.STATE_ALL_TRACK: 274 return JNI_SCAN_STATUS_ALL_TRACK_SCAN; 275 case BluetoothAvrcpPlayerSettings.STATE_GROUP: 276 return JNI_SCAN_STATUS_GROUP_SCAN; 277 } 278 } 279 return JNI_STATUS_INVALID; 280 } 281 282 // convert a native Attribute Id into the AVRCP Setting equivalent value; 283 private static int mapBTAttribIdToAvrcpPlayerSettings(byte attribId) { 284 switch (attribId) { 285 case JNI_ATTRIB_EQUALIZER_STATUS: 286 return BluetoothAvrcpPlayerSettings.SETTING_EQUALIZER; 287 case JNI_ATTRIB_REPEAT_STATUS: 288 return BluetoothAvrcpPlayerSettings.SETTING_REPEAT; 289 case JNI_ATTRIB_SHUFFLE_STATUS: 290 return BluetoothAvrcpPlayerSettings.SETTING_SHUFFLE; 291 case JNI_ATTRIB_SCAN_STATUS: 292 return BluetoothAvrcpPlayerSettings.SETTING_SCAN; 293 default: 294 return BluetoothAvrcpPlayerSettings.STATE_INVALID; 295 } 296 } 297 298 } 299 300