1 /* 2 * Copyright (C) 2012 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 static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL; 20 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; 21 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; 22 23 import android.bluetooth.BluetoothAdapter; 24 import android.bluetooth.BluetoothClass; 25 import android.bluetooth.BluetoothDevice; 26 import android.bluetooth.BluetoothHeadset; 27 import android.bluetooth.BluetoothProfile; 28 import android.bluetooth.BluetoothUuid; 29 import android.content.Context; 30 import android.os.ParcelUuid; 31 import android.util.Log; 32 33 import com.android.settingslib.R; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * HeadsetProfile handles Bluetooth HFP and Headset profiles. 40 */ 41 public class HeadsetProfile implements LocalBluetoothProfile { 42 private static final String TAG = "HeadsetProfile"; 43 44 private BluetoothHeadset mService; 45 private boolean mIsProfileReady; 46 47 private final CachedBluetoothDeviceManager mDeviceManager; 48 private final LocalBluetoothProfileManager mProfileManager; 49 private final BluetoothAdapter mBluetoothAdapter; 50 51 static final ParcelUuid[] UUIDS = { 52 BluetoothUuid.HSP, 53 BluetoothUuid.HFP, 54 }; 55 56 static final String NAME = "HEADSET"; 57 58 // Order of this profile in device profiles list 59 private static final int ORDINAL = 0; 60 61 // These callbacks run on the main thread. 62 private final class HeadsetServiceListener 63 implements BluetoothProfile.ServiceListener { 64 onServiceConnected(int profile, BluetoothProfile proxy)65 public void onServiceConnected(int profile, BluetoothProfile proxy) { 66 mService = (BluetoothHeadset) proxy; 67 // We just bound to the service, so refresh the UI for any connected HFP devices. 68 List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 69 while (!deviceList.isEmpty()) { 70 BluetoothDevice nextDevice = deviceList.remove(0); 71 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); 72 // we may add a new device here, but generally this should not happen 73 if (device == null) { 74 Log.w(TAG, "HeadsetProfile found new device: " + nextDevice); 75 device = mDeviceManager.addDevice(nextDevice); 76 } 77 device.onProfileStateChanged(HeadsetProfile.this, 78 BluetoothProfile.STATE_CONNECTED); 79 device.refresh(); 80 } 81 mIsProfileReady=true; 82 mProfileManager.callServiceConnectedListeners(); 83 } 84 onServiceDisconnected(int profile)85 public void onServiceDisconnected(int profile) { 86 mProfileManager.callServiceDisconnectedListeners(); 87 mIsProfileReady=false; 88 } 89 } 90 isProfileReady()91 public boolean isProfileReady() { 92 return mIsProfileReady; 93 } 94 95 @Override getProfileId()96 public int getProfileId() { 97 return BluetoothProfile.HEADSET; 98 } 99 HeadsetProfile(Context context, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)100 HeadsetProfile(Context context, CachedBluetoothDeviceManager deviceManager, 101 LocalBluetoothProfileManager profileManager) { 102 mDeviceManager = deviceManager; 103 mProfileManager = profileManager; 104 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 105 mBluetoothAdapter.getProfileProxy(context, new HeadsetServiceListener(), 106 BluetoothProfile.HEADSET); 107 } 108 accessProfileEnabled()109 public boolean accessProfileEnabled() { 110 return true; 111 } 112 isAutoConnectable()113 public boolean isAutoConnectable() { 114 return true; 115 } 116 getConnectionStatus(BluetoothDevice device)117 public int getConnectionStatus(BluetoothDevice device) { 118 if (mService == null) { 119 return BluetoothProfile.STATE_DISCONNECTED; 120 } 121 return mService.getConnectionState(device); 122 } 123 setActiveDevice(BluetoothDevice device)124 public boolean setActiveDevice(BluetoothDevice device) { 125 if (mBluetoothAdapter == null) { 126 return false; 127 } 128 129 return device == null 130 ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_PHONE_CALL) 131 : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_PHONE_CALL); 132 } 133 getActiveDevice()134 public BluetoothDevice getActiveDevice() { 135 if (mService == null) { 136 return null; 137 } 138 return mService.getActiveDevice(); 139 } 140 isAudioOn()141 public boolean isAudioOn() { 142 if (mService == null) { 143 return false; 144 } 145 return mService.isAudioOn(); 146 } 147 getAudioState(BluetoothDevice device)148 public int getAudioState(BluetoothDevice device) { 149 if (mService == null) { 150 return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 151 } 152 return mService.getAudioState(device); 153 } 154 155 @Override isEnabled(BluetoothDevice device)156 public boolean isEnabled(BluetoothDevice device) { 157 if (mService == null) { 158 return false; 159 } 160 return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN; 161 } 162 163 @Override getConnectionPolicy(BluetoothDevice device)164 public int getConnectionPolicy(BluetoothDevice device) { 165 if (mService == null) { 166 return CONNECTION_POLICY_FORBIDDEN; 167 } 168 return mService.getConnectionPolicy(device); 169 } 170 171 @Override setEnabled(BluetoothDevice device, boolean enabled)172 public boolean setEnabled(BluetoothDevice device, boolean enabled) { 173 boolean isEnabled = false; 174 if (mService == null) { 175 return false; 176 } 177 if (enabled) { 178 if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) { 179 isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); 180 } 181 } else { 182 isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN); 183 } 184 185 return isEnabled; 186 } 187 getConnectedDevices()188 public List<BluetoothDevice> getConnectedDevices() { 189 if (mService == null) { 190 return new ArrayList<BluetoothDevice>(0); 191 } 192 return mService.getDevicesMatchingConnectionStates( 193 new int[] {BluetoothProfile.STATE_CONNECTED, 194 BluetoothProfile.STATE_CONNECTING, 195 BluetoothProfile.STATE_DISCONNECTING}); 196 } 197 toString()198 public String toString() { 199 return NAME; 200 } 201 getOrdinal()202 public int getOrdinal() { 203 return ORDINAL; 204 } 205 getNameResource(BluetoothDevice device)206 public int getNameResource(BluetoothDevice device) { 207 return R.string.bluetooth_profile_headset; 208 } 209 getSummaryResourceForDevice(BluetoothDevice device)210 public int getSummaryResourceForDevice(BluetoothDevice device) { 211 int state = getConnectionStatus(device); 212 switch (state) { 213 case BluetoothProfile.STATE_DISCONNECTED: 214 return R.string.bluetooth_headset_profile_summary_use_for; 215 216 case BluetoothProfile.STATE_CONNECTED: 217 return R.string.bluetooth_headset_profile_summary_connected; 218 219 default: 220 return BluetoothUtils.getConnectionStateSummary(state); 221 } 222 } 223 getDrawableResource(BluetoothClass btClass)224 public int getDrawableResource(BluetoothClass btClass) { 225 return com.android.internal.R.drawable.ic_bt_headset_hfp; 226 } 227 finalize()228 protected void finalize() { 229 Log.d(TAG, "finalize()"); 230 if (mService != null) { 231 try { 232 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEADSET, 233 mService); 234 mService = null; 235 }catch (Throwable t) { 236 Log.w(TAG, "Error cleaning up HID proxy", t); 237 } 238 } 239 } 240 } 241