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