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