LocalBluetoothProfileManager.java revision d63c0112251ab4e4e977545368dd703d875012a4
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.BluetoothError; 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 64 sProfileMap.put(profile, profileManager); 65 } 66 } 67 68 return profileManager; 69 } 70 71 /** 72 * Temporary method to fill profiles based on a device's class. 73 * 74 * NOTE: This list happens to define the connection order. We should put this logic in a more 75 * well known place when this method is no longer temporary. 76 * 77 * @param btClass The class 78 * @param profiles The list of profiles to fill 79 */ 80 public static void fill(int btClass, List<Profile> profiles) { 81 profiles.clear(); 82 83 if (BluetoothHeadset.doesClassMatch(btClass)) { 84 profiles.add(Profile.HEADSET); 85 } 86 87 if (BluetoothA2dp.doesClassMatchSink(btClass)) { 88 profiles.add(Profile.A2DP); 89 } 90 } 91 92 protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) { 93 mLocalManager = localManager; 94 } 95 96 public abstract int connect(BluetoothDevice device); 97 98 public abstract int disconnect(BluetoothDevice device); 99 100 public abstract int getConnectionStatus(BluetoothDevice device); 101 102 public abstract int getSummary(BluetoothDevice device); 103 104 public abstract int convertState(int a2dpState); 105 106 public abstract boolean isPreferred(BluetoothDevice device); 107 108 public abstract void setPreferred(BluetoothDevice device, boolean preferred); 109 110 public boolean isConnected(BluetoothDevice device) { 111 return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device)); 112 } 113 114 // TODO: int instead of enum 115 public enum Profile { 116 HEADSET(R.string.bluetooth_profile_headset), 117 A2DP(R.string.bluetooth_profile_a2dp); 118 119 public final int localizedString; 120 121 private Profile(int localizedString) { 122 this.localizedString = localizedString; 123 } 124 } 125 126 /** 127 * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service. 128 */ 129 private static class A2dpProfileManager extends LocalBluetoothProfileManager { 130 private BluetoothA2dp mService; 131 132 public A2dpProfileManager(LocalBluetoothManager localManager) { 133 super(localManager); 134 mService = new BluetoothA2dp(localManager.getContext()); 135 } 136 137 @Override 138 public int connect(BluetoothDevice device) { 139 Set<BluetoothDevice> sinks = mService.getConnectedSinks(); 140 if (sinks != null) { 141 for (BluetoothDevice sink : sinks) { 142 mService.disconnectSink(sink); 143 } 144 } 145 return mService.connectSink(device); 146 } 147 148 @Override 149 public int disconnect(BluetoothDevice device) { 150 return mService.disconnectSink(device); 151 } 152 153 @Override 154 public int getConnectionStatus(BluetoothDevice device) { 155 return convertState(mService.getSinkState(device)); 156 } 157 158 @Override 159 public int getSummary(BluetoothDevice device) { 160 int connectionStatus = getConnectionStatus(device); 161 162 if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) { 163 return R.string.bluetooth_a2dp_profile_summary_connected; 164 } else { 165 return SettingsBtStatus.getConnectionStatusSummary(connectionStatus); 166 } 167 } 168 169 @Override 170 public boolean isPreferred(BluetoothDevice device) { 171 return mService.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF; 172 } 173 174 @Override 175 public void setPreferred(BluetoothDevice device, boolean preferred) { 176 mService.setSinkPriority(device, 177 preferred ? BluetoothA2dp.PRIORITY_AUTO : BluetoothA2dp.PRIORITY_OFF); 178 } 179 180 @Override 181 public int convertState(int a2dpState) { 182 switch (a2dpState) { 183 case BluetoothA2dp.STATE_CONNECTED: 184 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED; 185 case BluetoothA2dp.STATE_CONNECTING: 186 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 187 case BluetoothA2dp.STATE_DISCONNECTED: 188 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 189 case BluetoothA2dp.STATE_DISCONNECTING: 190 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING; 191 case BluetoothA2dp.STATE_PLAYING: 192 return SettingsBtStatus.CONNECTION_STATUS_ACTIVE; 193 default: 194 return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN; 195 } 196 } 197 } 198 199 /** 200 * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service. 201 */ 202 private static class HeadsetProfileManager extends LocalBluetoothProfileManager 203 implements BluetoothHeadset.ServiceListener { 204 private BluetoothHeadset mService; 205 private Handler mUiHandler = new Handler(); 206 207 public HeadsetProfileManager(LocalBluetoothManager localManager) { 208 super(localManager); 209 mService = new BluetoothHeadset(localManager.getContext(), this); 210 } 211 212 public void onServiceConnected() { 213 // This could be called on a non-UI thread, funnel to UI thread. 214 mUiHandler.post(new Runnable() { 215 public void run() { 216 /* 217 * We just bound to the service, so refresh the UI of the 218 * headset device. 219 */ 220 BluetoothDevice device = mService.getCurrentHeadset(); 221 if (device == null) return; 222 mLocalManager.getCachedDeviceManager() 223 .onProfileStateChanged(device, Profile.HEADSET, 224 BluetoothHeadset.STATE_CONNECTED); 225 } 226 }); 227 } 228 229 public void onServiceDisconnected() { 230 } 231 232 @Override 233 public int connect(BluetoothDevice device) { 234 // Since connectHeadset fails if already connected to a headset, we 235 // disconnect from any headset first 236 mService.disconnectHeadset(); 237 return mService.connectHeadset(device) 238 ? BluetoothError.SUCCESS : BluetoothError.ERROR; 239 } 240 241 @Override 242 public int disconnect(BluetoothDevice device) { 243 if (mService.getCurrentHeadset().equals(device)) { 244 return mService.disconnectHeadset() ? BluetoothError.SUCCESS : BluetoothError.ERROR; 245 } else { 246 return BluetoothError.SUCCESS; 247 } 248 } 249 250 @Override 251 public int getConnectionStatus(BluetoothDevice device) { 252 BluetoothDevice currentDevice = mService.getCurrentHeadset(); 253 return currentDevice != null && currentDevice.equals(device) 254 ? convertState(mService.getState()) 255 : SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 256 } 257 258 @Override 259 public int getSummary(BluetoothDevice device) { 260 int connectionStatus = getConnectionStatus(device); 261 262 if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) { 263 return R.string.bluetooth_headset_profile_summary_connected; 264 } else { 265 return SettingsBtStatus.getConnectionStatusSummary(connectionStatus); 266 } 267 } 268 269 @Override 270 public boolean isPreferred(BluetoothDevice device) { 271 return mService.getPriority(device) > BluetoothHeadset.PRIORITY_OFF; 272 } 273 274 @Override 275 public void setPreferred(BluetoothDevice device, boolean preferred) { 276 mService.setPriority(device, 277 preferred ? BluetoothHeadset.PRIORITY_AUTO : BluetoothHeadset.PRIORITY_OFF); 278 } 279 280 @Override 281 public int convertState(int headsetState) { 282 switch (headsetState) { 283 case BluetoothHeadset.STATE_CONNECTED: 284 return SettingsBtStatus.CONNECTION_STATUS_CONNECTED; 285 case BluetoothHeadset.STATE_CONNECTING: 286 return SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 287 case BluetoothHeadset.STATE_DISCONNECTED: 288 return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED; 289 default: 290 return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN; 291 } 292 } 293 } 294} 295