1 /* 2 * Copyright (C) 2018 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.bluetooth.BluetoothHearingAid; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothClass; 22 import android.bluetooth.BluetoothCodecConfig; 23 import android.bluetooth.BluetoothCodecStatus; 24 import android.bluetooth.BluetoothDevice; 25 import android.bluetooth.BluetoothProfile; 26 import android.bluetooth.BluetoothUuid; 27 import android.content.Context; 28 import android.os.ParcelUuid; 29 import android.util.Log; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.settingslib.R; 33 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.List; 37 38 public class HearingAidProfile implements LocalBluetoothProfile { 39 private static final String TAG = "HearingAidProfile"; 40 private static boolean V = true; 41 42 private Context mContext; 43 44 private BluetoothHearingAid mService; 45 private boolean mIsProfileReady; 46 47 private final LocalBluetoothAdapter mLocalAdapter; 48 private final CachedBluetoothDeviceManager mDeviceManager; 49 50 static final String NAME = "HearingAid"; 51 private final LocalBluetoothProfileManager mProfileManager; 52 53 // Order of this profile in device profiles list 54 private static final int ORDINAL = 1; 55 56 // These callbacks run on the main thread. 57 private final class HearingAidServiceListener 58 implements BluetoothProfile.ServiceListener { 59 onServiceConnected(int profile, BluetoothProfile proxy)60 public void onServiceConnected(int profile, BluetoothProfile proxy) { 61 if (V) Log.d(TAG,"Bluetooth service connected"); 62 mService = (BluetoothHearingAid) proxy; 63 // We just bound to the service, so refresh the UI for any connected HearingAid devices. 64 List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 65 while (!deviceList.isEmpty()) { 66 BluetoothDevice nextDevice = deviceList.remove(0); 67 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); 68 // we may add a new device here, but generally this should not happen 69 if (device == null) { 70 if (V) { 71 Log.d(TAG, "HearingAidProfile found new device: " + nextDevice); 72 } 73 device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); 74 } 75 device.onProfileStateChanged(HearingAidProfile.this, 76 BluetoothProfile.STATE_CONNECTED); 77 device.refresh(); 78 } 79 80 // Check current list of CachedDevices to see if any are Hearing Aid devices. 81 mDeviceManager.updateHearingAidsDevices(mProfileManager); 82 83 mIsProfileReady=true; 84 } 85 onServiceDisconnected(int profile)86 public void onServiceDisconnected(int profile) { 87 if (V) Log.d(TAG,"Bluetooth service disconnected"); 88 mIsProfileReady=false; 89 } 90 } 91 isProfileReady()92 public boolean isProfileReady() { 93 return mIsProfileReady; 94 } 95 96 @Override getProfileId()97 public int getProfileId() { 98 return BluetoothProfile.HEARING_AID; 99 } 100 HearingAidProfile(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)101 HearingAidProfile(Context context, LocalBluetoothAdapter adapter, 102 CachedBluetoothDeviceManager deviceManager, 103 LocalBluetoothProfileManager profileManager) { 104 mContext = context; 105 mLocalAdapter = adapter; 106 mDeviceManager = deviceManager; 107 mProfileManager = profileManager; 108 mLocalAdapter.getProfileProxy(context, new HearingAidServiceListener(), 109 BluetoothProfile.HEARING_AID); 110 } 111 isConnectable()112 public boolean isConnectable() { 113 return false; 114 } 115 isAutoConnectable()116 public boolean isAutoConnectable() { 117 return true; 118 } 119 getConnectedDevices()120 public List<BluetoothDevice> getConnectedDevices() { 121 if (mService == null) return new ArrayList<BluetoothDevice>(0); 122 return mService.getDevicesMatchingConnectionStates( 123 new int[] {BluetoothProfile.STATE_CONNECTED, 124 BluetoothProfile.STATE_CONNECTING, 125 BluetoothProfile.STATE_DISCONNECTING}); 126 } 127 connect(BluetoothDevice device)128 public boolean connect(BluetoothDevice device) { 129 if (mService == null) return false; 130 return mService.connect(device); 131 } 132 disconnect(BluetoothDevice device)133 public boolean disconnect(BluetoothDevice device) { 134 if (mService == null) return false; 135 // Downgrade priority as user is disconnecting the hearing aid. 136 if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ 137 mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 138 } 139 return mService.disconnect(device); 140 } 141 getConnectionStatus(BluetoothDevice device)142 public int getConnectionStatus(BluetoothDevice device) { 143 if (mService == null) { 144 return BluetoothProfile.STATE_DISCONNECTED; 145 } 146 return mService.getConnectionState(device); 147 } 148 setActiveDevice(BluetoothDevice device)149 public boolean setActiveDevice(BluetoothDevice device) { 150 if (mService == null) return false; 151 return mService.setActiveDevice(device); 152 } 153 getActiveDevices()154 public List<BluetoothDevice> getActiveDevices() { 155 if (mService == null) return new ArrayList<>(); 156 return mService.getActiveDevices(); 157 } 158 isPreferred(BluetoothDevice device)159 public boolean isPreferred(BluetoothDevice device) { 160 if (mService == null) return false; 161 return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 162 } 163 getPreferred(BluetoothDevice device)164 public int getPreferred(BluetoothDevice device) { 165 if (mService == null) return BluetoothProfile.PRIORITY_OFF; 166 return mService.getPriority(device); 167 } 168 setPreferred(BluetoothDevice device, boolean preferred)169 public void setPreferred(BluetoothDevice device, boolean preferred) { 170 if (mService == null) return; 171 if (preferred) { 172 if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 173 mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 174 } 175 } else { 176 mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 177 } 178 } 179 getVolume()180 public int getVolume() { 181 if (mService == null) { 182 return 0; 183 } 184 return mService.getVolume(); 185 } 186 setVolume(int volume)187 public void setVolume(int volume) { 188 if (mService == null) { 189 return; 190 } 191 mService.setVolume(volume); 192 } 193 getHiSyncId(BluetoothDevice device)194 public long getHiSyncId(BluetoothDevice device) { 195 if (mService == null) { 196 return BluetoothHearingAid.HI_SYNC_ID_INVALID; 197 } 198 return mService.getHiSyncId(device); 199 } 200 getDeviceSide(BluetoothDevice device)201 public int getDeviceSide(BluetoothDevice device) { 202 if (mService == null) { 203 return BluetoothHearingAid.SIDE_LEFT; 204 } 205 return mService.getDeviceSide(device); 206 } 207 getDeviceMode(BluetoothDevice device)208 public int getDeviceMode(BluetoothDevice device) { 209 if (mService == null) { 210 return BluetoothHearingAid.MODE_MONAURAL; 211 } 212 return mService.getDeviceMode(device); 213 } 214 toString()215 public String toString() { 216 return NAME; 217 } 218 getOrdinal()219 public int getOrdinal() { 220 return ORDINAL; 221 } 222 getNameResource(BluetoothDevice device)223 public int getNameResource(BluetoothDevice device) { 224 return R.string.bluetooth_profile_hearing_aid; 225 } 226 getSummaryResourceForDevice(BluetoothDevice device)227 public int getSummaryResourceForDevice(BluetoothDevice device) { 228 int state = getConnectionStatus(device); 229 switch (state) { 230 case BluetoothProfile.STATE_DISCONNECTED: 231 return R.string.bluetooth_hearing_aid_profile_summary_use_for; 232 233 case BluetoothProfile.STATE_CONNECTED: 234 return R.string.bluetooth_hearing_aid_profile_summary_connected; 235 236 default: 237 return Utils.getConnectionStateSummary(state); 238 } 239 } 240 getDrawableResource(BluetoothClass btClass)241 public int getDrawableResource(BluetoothClass btClass) { 242 return R.drawable.ic_bt_hearing_aid; 243 } 244 finalize()245 protected void finalize() { 246 if (V) Log.d(TAG, "finalize()"); 247 if (mService != null) { 248 try { 249 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID, 250 mService); 251 mService = null; 252 }catch (Throwable t) { 253 Log.w(TAG, "Error cleaning up Hearing Aid proxy", t); 254 } 255 } 256 } 257 } 258