2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.bluetooth;
19 import java.util.List;
20 import java.util.ArrayList;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.RemoteException;
26 import android.os.IBinder;
27 import android.os.ServiceManager;
28 import android.util.Log;
31 * This class provides the APIs to control the Bluetooth MAP
35 public final class BluetoothMap implements BluetoothProfile {
37 private static final String TAG = "BluetoothMap";
38 private static final boolean DBG = true;
39 private static final boolean VDBG = false;
41 public static final String ACTION_CONNECTION_STATE_CHANGED =
42 "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
44 private IBluetoothMap mService;
45 private final Context mContext;
46 private ServiceListener mServiceListener;
47 private BluetoothAdapter mAdapter;
49 /** There was an error trying to obtain the state */
50 public static final int STATE_ERROR = -1;
52 public static final int RESULT_FAILURE = 0;
53 public static final int RESULT_SUCCESS = 1;
54 /** Connection canceled before completion. */
55 public static final int RESULT_CANCELED = 2;
57 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
58 new IBluetoothStateChangeCallback.Stub() {
59 public void onBluetoothStateChange(boolean up) {
60 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
62 if (VDBG) Log.d(TAG,"Unbinding service...");
63 synchronized (mConnection) {
66 mContext.unbindService(mConnection);
67 } catch (Exception re) {
72 synchronized (mConnection) {
74 if (mService == null) {
75 if (VDBG) Log.d(TAG,"Binding service...");
78 } catch (Exception re) {
87 * Create a BluetoothMap proxy object.
89 /*package*/ BluetoothMap(Context context, ServiceListener l) {
90 if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
93 mAdapter = BluetoothAdapter.getDefaultAdapter();
94 IBluetoothManager mgr = mAdapter.getBluetoothManager();
97 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
98 } catch (RemoteException e) {
106 Intent intent = new Intent(IBluetoothMap.class.getName());
107 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
108 intent.setComponent(comp);
109 if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
110 Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
116 protected void finalize() throws Throwable {
125 * Close the connection to the backing service.
126 * Other public functions of BluetoothMap will return default error
127 * results once close() has been called. Multiple invocations of close()
130 public synchronized void close() {
131 IBluetoothManager mgr = mAdapter.getBluetoothManager();
134 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
135 } catch (Exception e) {
140 synchronized (mConnection) {
141 if (mService != null) {
144 mContext.unbindService(mConnection);
145 } catch (Exception re) {
150 mServiceListener = null;
154 * Get the current state of the BluetoothMap service.
155 * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
156 * object is currently not connected to the Map service.
158 public int getState() {
159 if (VDBG) log("getState()");
160 if (mService != null) {
162 return mService.getState();
163 } catch (RemoteException e) {Log.e(TAG, e.toString());}
165 Log.w(TAG, "Proxy not attached to service");
166 if (DBG) log(Log.getStackTraceString(new Throwable()));
168 return BluetoothMap.STATE_ERROR;
172 * Get the currently connected remote Bluetooth device (PCE).
173 * @return The remote Bluetooth device, or null if not in connected or
174 * connecting state, or if this proxy object is not connected to
177 public BluetoothDevice getClient() {
178 if (VDBG) log("getClient()");
179 if (mService != null) {
181 return mService.getClient();
182 } catch (RemoteException e) {Log.e(TAG, e.toString());}
184 Log.w(TAG, "Proxy not attached to service");
185 if (DBG) log(Log.getStackTraceString(new Throwable()));
191 * Returns true if the specified Bluetooth device is connected.
192 * Returns false if not connected, or if this proxy object is not
193 * currently connected to the Map service.
195 public boolean isConnected(BluetoothDevice device) {
196 if (VDBG) log("isConnected(" + device + ")");
197 if (mService != null) {
199 return mService.isConnected(device);
200 } catch (RemoteException e) {Log.e(TAG, e.toString());}
202 Log.w(TAG, "Proxy not attached to service");
203 if (DBG) log(Log.getStackTraceString(new Throwable()));
209 * Initiate connection. Initiation of outgoing connections is not
210 * supported for MAP server.
212 public boolean connect(BluetoothDevice device) {
213 if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
218 * Initiate disconnect.
220 * @param device Remote Bluetooth Device
221 * @return false on error,
224 public boolean disconnect(BluetoothDevice device) {
225 if (DBG) log("disconnect(" + device + ")");
226 if (mService != null && isEnabled() &&
227 isValidDevice(device)) {
229 return mService.disconnect(device);
230 } catch (RemoteException e) {
231 Log.e(TAG, Log.getStackTraceString(new Throwable()));
235 if (mService == null) Log.w(TAG, "Proxy not attached to service");
240 * Check class bits for possible Map support.
241 * This is a simple heuristic that tries to guess if a device with the
242 * given class bits might support Map. It is not accurate for all
243 * devices. It tries to err on the side of false positives.
244 * @return True if this device might support Map.
246 public static boolean doesClassMatchSink(BluetoothClass btClass) {
247 // TODO optimize the rule
248 switch (btClass.getDeviceClass()) {
249 case BluetoothClass.Device.COMPUTER_DESKTOP:
250 case BluetoothClass.Device.COMPUTER_LAPTOP:
251 case BluetoothClass.Device.COMPUTER_SERVER:
252 case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
260 * Get the list of connected devices. Currently at most one.
262 * @return list of connected devices
264 public List<BluetoothDevice> getConnectedDevices() {
265 if (DBG) log("getConnectedDevices()");
266 if (mService != null && isEnabled()) {
268 return mService.getConnectedDevices();
269 } catch (RemoteException e) {
270 Log.e(TAG, Log.getStackTraceString(new Throwable()));
271 return new ArrayList<BluetoothDevice>();
274 if (mService == null) Log.w(TAG, "Proxy not attached to service");
275 return new ArrayList<BluetoothDevice>();
279 * Get the list of devices matching specified states. Currently at most one.
281 * @return list of matching devices
283 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
284 if (DBG) log("getDevicesMatchingStates()");
285 if (mService != null && isEnabled()) {
287 return mService.getDevicesMatchingConnectionStates(states);
288 } catch (RemoteException e) {
289 Log.e(TAG, Log.getStackTraceString(new Throwable()));
290 return new ArrayList<BluetoothDevice>();
293 if (mService == null) Log.w(TAG, "Proxy not attached to service");
294 return new ArrayList<BluetoothDevice>();
298 * Get connection state of device
300 * @return device connection state
302 public int getConnectionState(BluetoothDevice device) {
303 if (DBG) log("getConnectionState(" + device + ")");
304 if (mService != null && isEnabled() &&
305 isValidDevice(device)) {
307 return mService.getConnectionState(device);
308 } catch (RemoteException e) {
309 Log.e(TAG, Log.getStackTraceString(new Throwable()));
310 return BluetoothProfile.STATE_DISCONNECTED;
313 if (mService == null) Log.w(TAG, "Proxy not attached to service");
314 return BluetoothProfile.STATE_DISCONNECTED;
318 * Set priority of the profile
320 * <p> The device should already be paired.
321 * Priority can be one of {@link #PRIORITY_ON} or
322 * {@link #PRIORITY_OFF},
324 * @param device Paired bluetooth device
326 * @return true if priority is set, false on error
328 public boolean setPriority(BluetoothDevice device, int priority) {
329 if (DBG) log("setPriority(" + device + ", " + priority + ")");
330 if (mService != null && isEnabled() &&
331 isValidDevice(device)) {
332 if (priority != BluetoothProfile.PRIORITY_OFF &&
333 priority != BluetoothProfile.PRIORITY_ON) {
337 return mService.setPriority(device, priority);
338 } catch (RemoteException e) {
339 Log.e(TAG, Log.getStackTraceString(new Throwable()));
343 if (mService == null) Log.w(TAG, "Proxy not attached to service");
348 * Get the priority of the profile.
350 * <p> The priority can be any of:
351 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
352 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
354 * @param device Bluetooth device
355 * @return priority of the device
357 public int getPriority(BluetoothDevice device) {
358 if (VDBG) log("getPriority(" + device + ")");
359 if (mService != null && isEnabled() &&
360 isValidDevice(device)) {
362 return mService.getPriority(device);
363 } catch (RemoteException e) {
364 Log.e(TAG, Log.getStackTraceString(new Throwable()));
368 if (mService == null) Log.w(TAG, "Proxy not attached to service");
372 private final ServiceConnection mConnection = new ServiceConnection() {
373 public void onServiceConnected(ComponentName className, IBinder service) {
374 if (DBG) log("Proxy object connected");
375 mService = IBluetoothMap.Stub.asInterface(service);
376 if (mServiceListener != null) {
377 mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
380 public void onServiceDisconnected(ComponentName className) {
381 if (DBG) log("Proxy object disconnected");
383 if (mServiceListener != null) {
384 mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
389 private static void log(String msg) {
393 private boolean isEnabled() {
394 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
395 if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
396 log("Bluetooth is Not enabled");
399 private boolean isValidDevice(BluetoothDevice device) {
400 if (device == null) return false;
402 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;