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 (mBluetoothAdapter == null) { 136 return null; 137 } 138 final List<BluetoothDevice> activeDevices = mBluetoothAdapter 139 .getActiveDevices(BluetoothProfile.HEADSET); 140 return (activeDevices.size() > 0) ? activeDevices.get(0) : null; 141 } 142 getAudioState(BluetoothDevice device)143 public int getAudioState(BluetoothDevice device) { 144 if (mService == null) { 145 return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 146 } 147 return mService.getAudioState(device); 148 } 149 150 @Override isEnabled(BluetoothDevice device)151 public boolean isEnabled(BluetoothDevice device) { 152 if (mService == null) { 153 return false; 154 } 155 return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN; 156 } 157 158 @Override getConnectionPolicy(BluetoothDevice device)159 public int getConnectionPolicy(BluetoothDevice device) { 160 if (mService == null) { 161 return CONNECTION_POLICY_FORBIDDEN; 162 } 163 return mService.getConnectionPolicy(device); 164 } 165 166 @Override setEnabled(BluetoothDevice device, boolean enabled)167 public boolean setEnabled(BluetoothDevice device, boolean enabled) { 168 boolean isEnabled = false; 169 if (mService == null) { 170 return false; 171 } 172 if (enabled) { 173 if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) { 174 isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); 175 } 176 } else { 177 isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN); 178 } 179 180 return isEnabled; 181 } 182 getConnectedDevices()183 public List<BluetoothDevice> getConnectedDevices() { 184 if (mService == null) { 185 return new ArrayList<BluetoothDevice>(0); 186 } 187 return mService.getDevicesMatchingConnectionStates( 188 new int[] {BluetoothProfile.STATE_CONNECTED, 189 BluetoothProfile.STATE_CONNECTING, 190 BluetoothProfile.STATE_DISCONNECTING}); 191 } 192 toString()193 public String toString() { 194 return NAME; 195 } 196 getOrdinal()197 public int getOrdinal() { 198 return ORDINAL; 199 } 200 getNameResource(BluetoothDevice device)201 public int getNameResource(BluetoothDevice device) { 202 return R.string.bluetooth_profile_headset; 203 } 204 getSummaryResourceForDevice(BluetoothDevice device)205 public int getSummaryResourceForDevice(BluetoothDevice device) { 206 int state = getConnectionStatus(device); 207 switch (state) { 208 case BluetoothProfile.STATE_DISCONNECTED: 209 return R.string.bluetooth_headset_profile_summary_use_for; 210 211 case BluetoothProfile.STATE_CONNECTED: 212 return R.string.bluetooth_headset_profile_summary_connected; 213 214 default: 215 return BluetoothUtils.getConnectionStateSummary(state); 216 } 217 } 218 getDrawableResource(BluetoothClass btClass)219 public int getDrawableResource(BluetoothClass btClass) { 220 return com.android.internal.R.drawable.ic_bt_headset_hfp; 221 } 222 finalize()223 protected void finalize() { 224 Log.d(TAG, "finalize()"); 225 if (mService != null) { 226 try { 227 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEADSET, 228 mService); 229 mService = null; 230 }catch (Throwable t) { 231 Log.w(TAG, "Error cleaning up HID proxy", t); 232 } 233 } 234 } 235 } 236