1 /* 2 * Copyright (C) 2022 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.settingslib.bluetooth; 18 19 import android.annotation.IntDef; 20 import android.bluetooth.BluetoothHearingAid; 21 import android.bluetooth.BluetoothLeAudio; 22 import android.util.SparseIntArray; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.util.Objects; 27 28 /** Hearing aids information and constants that shared within hearing aids related profiles */ 29 public class HearingAidInfo { 30 31 @Retention(RetentionPolicy.SOURCE) 32 @IntDef({ 33 DeviceSide.SIDE_INVALID, 34 DeviceSide.SIDE_LEFT, 35 DeviceSide.SIDE_RIGHT, 36 DeviceSide.SIDE_LEFT_AND_RIGHT, 37 DeviceSide.SIDE_MONO 38 }) 39 40 /** Side definition for hearing aids. */ 41 public @interface DeviceSide { 42 int SIDE_INVALID = -1; 43 int SIDE_LEFT = 0; 44 int SIDE_RIGHT = 1; 45 int SIDE_LEFT_AND_RIGHT = 2; 46 int SIDE_MONO = 3; 47 } 48 49 @Retention(java.lang.annotation.RetentionPolicy.SOURCE) 50 @IntDef({ 51 DeviceMode.MODE_INVALID, 52 DeviceMode.MODE_MONAURAL, 53 DeviceMode.MODE_BINAURAL, 54 DeviceMode.MODE_BANDED, 55 }) 56 57 /** Mode definition for hearing aids. */ 58 public @interface DeviceMode { 59 int MODE_INVALID = -1; 60 int MODE_MONAURAL = 0; 61 int MODE_BINAURAL = 1; 62 int MODE_BANDED = 2; 63 } 64 65 private final int mSide; 66 private final int mMode; 67 private final long mHiSyncId; 68 HearingAidInfo(int side, int mode, long hiSyncId)69 private HearingAidInfo(int side, int mode, long hiSyncId) { 70 mSide = side; 71 mMode = mode; 72 mHiSyncId = hiSyncId; 73 } 74 75 @DeviceSide getSide()76 public int getSide() { 77 return mSide; 78 } 79 80 @DeviceMode getMode()81 public int getMode() { 82 return mMode; 83 } 84 getHiSyncId()85 public long getHiSyncId() { 86 return mHiSyncId; 87 } 88 89 @Override equals(Object o)90 public boolean equals(Object o) { 91 if (this == o) { 92 return true; 93 } 94 if (!(o instanceof HearingAidInfo)) { 95 return false; 96 } 97 HearingAidInfo that = (HearingAidInfo) o; 98 return mSide == that.mSide && mMode == that.mMode && mHiSyncId == that.mHiSyncId; 99 } 100 101 @Override hashCode()102 public int hashCode() { 103 return Objects.hash(mSide, mMode, mHiSyncId); 104 } 105 106 @Override toString()107 public String toString() { 108 return "HearingAidInfo{" 109 + "mSide=" + mSide 110 + ", mMode=" + mMode 111 + ", mHiSyncId=" + mHiSyncId 112 + '}'; 113 } 114 115 @DeviceSide convertAshaDeviceSideToInternalSide(int ashaDeviceSide)116 private static int convertAshaDeviceSideToInternalSide(int ashaDeviceSide) { 117 return ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.get( 118 ashaDeviceSide, DeviceSide.SIDE_INVALID); 119 } 120 121 @DeviceMode convertAshaDeviceModeToInternalMode(int ashaDeviceMode)122 private static int convertAshaDeviceModeToInternalMode(int ashaDeviceMode) { 123 return ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.get( 124 ashaDeviceMode, DeviceMode.MODE_INVALID); 125 } 126 127 @DeviceSide convertLeAudioLocationToInternalSide(int leAudioLocation)128 private static int convertLeAudioLocationToInternalSide(int leAudioLocation) { 129 if (leAudioLocation == BluetoothLeAudio.AUDIO_LOCATION_MONO) { 130 return DeviceSide.SIDE_MONO; 131 } 132 boolean isLeft = (leAudioLocation & LE_AUDIO_LOCATION_LEFT) != 0; 133 boolean isRight = (leAudioLocation & LE_AUDIO_LOCATION_RIGHT) != 0; 134 if (isLeft && isRight) { 135 return DeviceSide.SIDE_LEFT_AND_RIGHT; 136 } else if (isLeft) { 137 return DeviceSide.SIDE_LEFT; 138 } else if (isRight) { 139 return DeviceSide.SIDE_RIGHT; 140 } 141 return DeviceSide.SIDE_INVALID; 142 } 143 144 @DeviceMode convertHapDeviceTypeToInternalMode(int hapDeviceType)145 private static int convertHapDeviceTypeToInternalMode(int hapDeviceType) { 146 return HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.get(hapDeviceType, DeviceMode.MODE_INVALID); 147 } 148 149 /** Builder class for constructing {@link HearingAidInfo} objects. */ 150 public static final class Builder { 151 private int mSide = DeviceSide.SIDE_INVALID; 152 private int mMode = DeviceMode.MODE_INVALID; 153 private long mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID; 154 155 /** 156 * Configure the hearing device mode. 157 * @param ashaDeviceMode one of the hearing aid device modes defined in HearingAidProfile 158 * {@link HearingAidProfile.DeviceMode} 159 */ setAshaDeviceMode(int ashaDeviceMode)160 public Builder setAshaDeviceMode(int ashaDeviceMode) { 161 mMode = convertAshaDeviceModeToInternalMode(ashaDeviceMode); 162 return this; 163 } 164 165 /** 166 * Configure the hearing device mode. 167 * @param hapDeviceType one of the hearing aid device types defined in HapClientProfile 168 * {@link HapClientProfile.HearingAidType} 169 */ setHapDeviceType(int hapDeviceType)170 public Builder setHapDeviceType(int hapDeviceType) { 171 mMode = convertHapDeviceTypeToInternalMode(hapDeviceType); 172 return this; 173 } 174 175 /** 176 * Configure the hearing device side. 177 * @param ashaDeviceSide one of the hearing aid device sides defined in HearingAidProfile 178 * {@link HearingAidProfile.DeviceSide} 179 */ setAshaDeviceSide(int ashaDeviceSide)180 public Builder setAshaDeviceSide(int ashaDeviceSide) { 181 mSide = convertAshaDeviceSideToInternalSide(ashaDeviceSide); 182 return this; 183 } 184 185 /** 186 * Configure the hearing device side. 187 * @param leAudioLocation one of the audio location defined in BluetoothLeAudio 188 * {@link BluetoothLeAudio.AudioLocation} 189 */ setLeAudioLocation(int leAudioLocation)190 public Builder setLeAudioLocation(int leAudioLocation) { 191 mSide = convertLeAudioLocationToInternalSide(leAudioLocation); 192 return this; 193 } 194 195 /** 196 * Configure the hearing aid hiSyncId. 197 * @param hiSyncId the ASHA hearing aid id 198 */ setHiSyncId(long hiSyncId)199 public Builder setHiSyncId(long hiSyncId) { 200 mHiSyncId = hiSyncId; 201 return this; 202 } 203 204 /** Build the configured {@link HearingAidInfo} */ build()205 public HearingAidInfo build() { 206 return new HearingAidInfo(mSide, mMode, mHiSyncId); 207 } 208 } 209 210 private static final int LE_AUDIO_LOCATION_LEFT = 211 BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT 212 | BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT 213 | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_OF_CENTER 214 | BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT 215 | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_LEFT 216 | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_LEFT 217 | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_LEFT 218 | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_LEFT 219 | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_WIDE 220 | BluetoothLeAudio.AUDIO_LOCATION_LEFT_SURROUND; 221 222 private static final int LE_AUDIO_LOCATION_RIGHT = 223 BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT 224 | BluetoothLeAudio.AUDIO_LOCATION_BACK_RIGHT 225 | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER 226 | BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT 227 | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_RIGHT 228 | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_RIGHT 229 | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_RIGHT 230 | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_RIGHT 231 | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_WIDE 232 | BluetoothLeAudio.AUDIO_LOCATION_RIGHT_SURROUND; 233 234 private static final SparseIntArray ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING; 235 private static final SparseIntArray ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING; 236 private static final SparseIntArray HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING; 237 238 static { 239 ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING = new SparseIntArray(); ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put( HearingAidProfile.DeviceSide.SIDE_INVALID, DeviceSide.SIDE_INVALID)240 ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put( 241 HearingAidProfile.DeviceSide.SIDE_INVALID, DeviceSide.SIDE_INVALID); ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put( HearingAidProfile.DeviceSide.SIDE_LEFT, DeviceSide.SIDE_LEFT)242 ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put( 243 HearingAidProfile.DeviceSide.SIDE_LEFT, DeviceSide.SIDE_LEFT); ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put( HearingAidProfile.DeviceSide.SIDE_RIGHT, DeviceSide.SIDE_RIGHT)244 ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put( 245 HearingAidProfile.DeviceSide.SIDE_RIGHT, DeviceSide.SIDE_RIGHT); 246 247 ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING = new SparseIntArray(); ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put( HearingAidProfile.DeviceMode.MODE_INVALID, DeviceMode.MODE_INVALID)248 ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put( 249 HearingAidProfile.DeviceMode.MODE_INVALID, DeviceMode.MODE_INVALID); ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put( HearingAidProfile.DeviceMode.MODE_MONAURAL, DeviceMode.MODE_MONAURAL)250 ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put( 251 HearingAidProfile.DeviceMode.MODE_MONAURAL, DeviceMode.MODE_MONAURAL); ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put( HearingAidProfile.DeviceMode.MODE_BINAURAL, DeviceMode.MODE_BINAURAL)252 ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put( 253 HearingAidProfile.DeviceMode.MODE_BINAURAL, DeviceMode.MODE_BINAURAL); 254 255 HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING = new SparseIntArray(); HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( HapClientProfile.HearingAidType.TYPE_INVALID, DeviceMode.MODE_INVALID)256 HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( 257 HapClientProfile.HearingAidType.TYPE_INVALID, DeviceMode.MODE_INVALID); HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( HapClientProfile.HearingAidType.TYPE_BINAURAL, DeviceMode.MODE_BINAURAL)258 HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( 259 HapClientProfile.HearingAidType.TYPE_BINAURAL, DeviceMode.MODE_BINAURAL); HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( HapClientProfile.HearingAidType.TYPE_MONAURAL, DeviceMode.MODE_MONAURAL)260 HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( 261 HapClientProfile.HearingAidType.TYPE_MONAURAL, DeviceMode.MODE_MONAURAL); HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( HapClientProfile.HearingAidType.TYPE_BANDED, DeviceMode.MODE_BANDED)262 HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( 263 HapClientProfile.HearingAidType.TYPE_BANDED, DeviceMode.MODE_BANDED); HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( HapClientProfile.HearingAidType.TYPE_RFU, DeviceMode.MODE_INVALID)264 HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put( 265 HapClientProfile.HearingAidType.TYPE_RFU, DeviceMode.MODE_INVALID); 266 267 } 268 } 269