LocalBluetoothProfileManager.java revision 16cc86315d7a8e1f6a0f3083d0a810a7cb097832
1/* 2 * Copyright (C) 2008 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 17package com.android.settings.bluetooth; 18 19import android.bluetooth.BluetoothA2dp; 20import android.bluetooth.BluetoothDevice; 21import android.bluetooth.BluetoothClass; 22import android.bluetooth.BluetoothHeadset; 23import android.os.Handler; 24import android.text.TextUtils; 25 26import com.android.settings.R; 27 28import java.util.HashMap; 29import java.util.List; 30import java.util.Map; 31import java.util.Set; 32 33/** 34 * LocalBluetoothProfileManager is an abstract class defining the basic 35 * functionality related to a profile. 36 */ 37public abstract class LocalBluetoothProfileManager { 38 39 // TODO: close profiles when we're shutting down 40 private static Map<Profile, LocalBluetoothProfileManager> sProfileMap = 41 new HashMap<Profile, LocalBluetoothProfileManager>(); 42 43 protected LocalBluetoothManager mLocalManager; 44 45 public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager, 46 Profile profile) { 47 48 LocalBluetoothProfileManager profileManager; 49 50 synchronized (sProfileMap) { 51 profileManager = sProfileMap.get(profile); 52 53 if (profileManager == null) { 54 switch (profile) { 55 case A2DP: 56 profileManager = new A2dpProfileManager(localManager); 57 break; 58 59 case HEADSET: 60 profileManager = new HeadsetProfileManager(localManager); 61 break; 62 63 case OPP: 64 profileManager = new OppProfileManager(localManager); 65 break; 66 } 67 68 sProfileMap.put(profile, profileManager); 69 } 70 } 71 72 return profileManager; 73 } 74 75 /** 76 * Temporary method to fill profiles based on a device's class. 77 * 78 * NOTE: This list happens to define the connection order. We should put this logic in a more 79 * well known place when this method is no longer temporary. 80 * 81 * @param btClass The class 82 * @param profiles The list of profiles to fill 83 */ 84 public static void fill(BluetoothClass btClass, List<Profile> profiles) { 85 profiles.clear(); 86 87 if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { 88 profiles.add(Profile.HEADSET); 89 } 90 91 if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { 92 profiles.add(Profile.A2DP); 93 } 94 95 if (btClass.doesClassMatch(BluetoothClass.PROFILE_OPP)) { 96 profiles.add(Profile.OPP); 97 } 98 } 99 100 protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) { 101 mLocalManager = localManager; 102 } 103 104 public abstract boolean connect(BluetoothDevice device); 105 106 public abstract boolean disconnect(BluetoothDevice device); 107 108 public abstract int getConnectionStatus(BluetoothDevice device); 109 110 public abstract int getSummary(BluetoothDevice device); 111 112 public abstract int convertState(int a2dpState); 113 114 public abstract boolean isPreferred(BluetoothDevice device); 115 116 public abstract void setPreferred(BluetoothDevice device, boolean preferred); 117 118 public boolean isConnected(BluetoothDevice device) { 119 return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device)); 120 } 121 122 // TODO: int instead of enum 123 public enum Profile { 124 HEADSET(R.string.bluetooth_profile_headset), 125 A2DP(R.string.bluetooth_profile_a2dp), 126 OPP(R.string.bluetooth_profile_opp); 127 128 public final int localizedString; 129 130 private Profile(int localizedString) { 131 this.localizedString = localizedString; 132 } 133 } 134 135 /** 136 * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service. 137 */ 138 private static class A2dpProfileManager extends LocalBluetoothProfileManager { 139 private BluetoothA2dp mService; 140 141 public A2dpProfileManager(LocalBluetoothManager localManager) { 142 super(localManager); 143 mService = new BluetoothA2dp(localManager.getContext()); 144 } 145 146 @Override 147 public boolean connect(BluetoothDevice device) { 148 Set<BluetoothDevice> sinks = mService.getConnectedSinks(); 149 if (sinks != null) { 150 for (BluetoothDevice sink : sinks) { 151 mService.disconnectSink(sink); 152 } 153 } 154 return mService.connectSink(device); 155 } 156 157 @Override 158 public boolean disconnect(BluetoothDevice device) { 159 return mService.disconnectSink(device); 160 } 161 162 @Override 163 public int getConnectionStatus(BluetoothDevice device) { 164 return convertState(mService.getSinkState(device)); 165 } 166 167 @Override 168 public int getSummary(BluetoothDevice device) { 169 int connectionStatus = getConnectionStatus(device); 170 171 if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) { 172 return R.string.bluetooth_a2dp_profile_summary_connected; 173 } else { 174 return SettingsBtStatus.getConnectionStatusSummary(connectionStatus); 175 } 176 } 177 178 @Override 179 public boolean isPreferred(BluetoothDevice device) { 180 return mService.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF; 181 } 182 183 @Override 184 public void setPreferred(BluetoothDevice device, boolean preferred) { 185 mService.setSinkPriority(device, 186 preferred ? BluetoothA2dp.PRIORITY_AUTO : BluetoothA2dp.PRIORITY_OFF); 187 } 188 189 @Override 190 public int convertState(int a2dpState) { 191 switch (a2dpState) { 192 case BluetoothA2dp.STATE_CONNECTED: 193 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED; 194 case BluetoothA2dp.STATE_CONNECTING: 195 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 196 case BluetoothA2dp.STATE_DISCONNECTED: 197 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 198 case BluetoothA2dp.STATE_DISCONNECTING: 199 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING; 200 case BluetoothA2dp.STATE_PLAYING: 201 return SettingsBtStatus.CONNECTION_STATUS_ACTIVE; 202 default: 203 return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN; 204 } 205 } 206 } 207 208 /** 209 * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service. 210 */ 211 private static class HeadsetProfileManager extends LocalBluetoothProfileManager 212 implements BluetoothHeadset.ServiceListener { 213 private BluetoothHeadset mService; 214 private Handler mUiHandler = new Handler(); 215 216 public HeadsetProfileManager(LocalBluetoothManager localManager) { 217 super(localManager); 218 mService = new BluetoothHeadset(localManager.getContext(), this); 219 } 220 221 public void onServiceConnected() { 222 // This could be called on a non-UI thread, funnel to UI thread. 223 mUiHandler.post(new Runnable() { 224 public void run() { 225 /* 226 * We just bound to the service, so refresh the UI of the 227 * headset device. 228 */ 229 BluetoothDevice device = mService.getCurrentHeadset(); 230 if (device == null) return; 231 mLocalManager.getCachedDeviceManager() 232 .onProfileStateChanged(device, Profile.HEADSET, 233 BluetoothHeadset.STATE_CONNECTED); 234 } 235 }); 236 } 237 238 public void onServiceDisconnected() { 239 } 240 241 @Override 242 public boolean connect(BluetoothDevice device) { 243 // Since connectHeadset fails if already connected to a headset, we 244 // disconnect from any headset first 245 mService.disconnectHeadset(); 246 return mService.connectHeadset(device); 247 } 248 249 @Override 250 public boolean disconnect(BluetoothDevice device) { 251 if (mService.getCurrentHeadset().equals(device)) { 252 return mService.disconnectHeadset(); 253 } else { 254 return false; 255 } 256 } 257 258 @Override 259 public int getConnectionStatus(BluetoothDevice device) { 260 BluetoothDevice currentDevice = mService.getCurrentHeadset(); 261 return currentDevice != null && currentDevice.equals(device) 262 ? convertState(mService.getState()) 263 : SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 264 } 265 266 @Override 267 public int getSummary(BluetoothDevice device) { 268 int connectionStatus = getConnectionStatus(device); 269 270 if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) { 271 return R.string.bluetooth_headset_profile_summary_connected; 272 } else { 273 return SettingsBtStatus.getConnectionStatusSummary(connectionStatus); 274 } 275 } 276 277 @Override 278 public boolean isPreferred(BluetoothDevice device) { 279 return mService.getPriority(device) > BluetoothHeadset.PRIORITY_OFF; 280 } 281 282 @Override 283 public void setPreferred(BluetoothDevice device, boolean preferred) { 284 mService.setPriority(device, 285 preferred ? BluetoothHeadset.PRIORITY_AUTO : BluetoothHeadset.PRIORITY_OFF); 286 } 287 288 @Override 289 public int convertState(int headsetState) { 290 switch (headsetState) { 291 case BluetoothHeadset.STATE_CONNECTED: 292 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED; 293 case BluetoothHeadset.STATE_CONNECTING: 294 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 295 case BluetoothHeadset.STATE_DISCONNECTED: 296 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 297 default: 298 return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN; 299 } 300 } 301 } 302 303 /** 304 * OppProfileManager 305 */ 306 private static class OppProfileManager extends LocalBluetoothProfileManager { 307 308 public OppProfileManager(LocalBluetoothManager localManager) { 309 super(localManager); 310 } 311 312 @Override 313 public boolean connect(BluetoothDevice device) { 314 return false; 315 } 316 317 @Override 318 public boolean disconnect(BluetoothDevice device) { 319 return false; 320 } 321 322 @Override 323 public int getConnectionStatus(BluetoothDevice device) { 324 return -1; 325 } 326 327 @Override 328 public int getSummary(BluetoothDevice device) { 329 int connectionStatus = getConnectionStatus(device); 330 331 if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) { 332 return R.string.bluetooth_opp_profile_summary_connected; 333 } else { 334 return R.string.bluetooth_opp_profile_summary_not_connected; 335 } 336 } 337 338 @Override 339 public boolean isPreferred(BluetoothDevice device) { 340 return false; 341 } 342 343 @Override 344 public void setPreferred(BluetoothDevice device, boolean preferred) { 345 } 346 347 @Override 348 public int convertState(int oppState) { 349 switch (oppState) { 350 case 0: 351 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED; 352 case 1: 353 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 354 case 2: 355 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 356 default: 357 return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN; 358 } 359 } 360 } 361} 362