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