• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.bluetooth;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.os.Binder;
22 import android.os.IBinder;
23 import android.os.RemoteException;
24 import android.util.Log;
25 
26 import java.util.ArrayList;
27 import java.util.List;
28 
29 /**
30  * This class provides the APIs to control the Bluetooth MAP
31  * Profile.
32  *
33  * @hide
34  */
35 public final class BluetoothMap implements BluetoothProfile {
36 
37     private static final String TAG = "BluetoothMap";
38     private static final boolean DBG = true;
39     private static final boolean VDBG = false;
40 
41     public static final String ACTION_CONNECTION_STATE_CHANGED =
42             "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
43 
44     /** There was an error trying to obtain the state */
45     public static final int STATE_ERROR = -1;
46 
47     public static final int RESULT_FAILURE = 0;
48     public static final int RESULT_SUCCESS = 1;
49     /** Connection canceled before completion. */
50     public static final int RESULT_CANCELED = 2;
51 
52     private BluetoothAdapter mAdapter;
53     private final BluetoothProfileConnector<IBluetoothMap> mProfileConnector =
54             new BluetoothProfileConnector(this, BluetoothProfile.MAP,
55                     "BluetoothMap", IBluetoothMap.class.getName()) {
56                 @Override
57                 public IBluetoothMap getServiceInterface(IBinder service) {
58                     return IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
59                 }
60     };
61 
62     /**
63      * Create a BluetoothMap proxy object.
64      */
BluetoothMap(Context context, ServiceListener listener)65     /*package*/ BluetoothMap(Context context, ServiceListener listener) {
66         if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
67         mAdapter = BluetoothAdapter.getDefaultAdapter();
68         mProfileConnector.connect(context, listener);
69     }
70 
finalize()71     protected void finalize() throws Throwable {
72         try {
73             close();
74         } finally {
75             super.finalize();
76         }
77     }
78 
79     /**
80      * Close the connection to the backing service.
81      * Other public functions of BluetoothMap will return default error
82      * results once close() has been called. Multiple invocations of close()
83      * are ok.
84      */
close()85     public synchronized void close() {
86         mProfileConnector.disconnect();
87     }
88 
getService()89     private IBluetoothMap getService() {
90         return mProfileConnector.getService();
91     }
92 
93     /**
94      * Get the current state of the BluetoothMap service.
95      *
96      * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not
97      * connected to the Map service.
98      */
getState()99     public int getState() {
100         if (VDBG) log("getState()");
101         final IBluetoothMap service = getService();
102         if (service != null) {
103             try {
104                 return service.getState();
105             } catch (RemoteException e) {
106                 Log.e(TAG, e.toString());
107             }
108         } else {
109             Log.w(TAG, "Proxy not attached to service");
110             if (DBG) log(Log.getStackTraceString(new Throwable()));
111         }
112         return BluetoothMap.STATE_ERROR;
113     }
114 
115     /**
116      * Get the currently connected remote Bluetooth device (PCE).
117      *
118      * @return The remote Bluetooth device, or null if not in connected or connecting state, or if
119      * this proxy object is not connected to the Map service.
120      */
getClient()121     public BluetoothDevice getClient() {
122         if (VDBG) log("getClient()");
123         final IBluetoothMap service = getService();
124         if (service != null) {
125             try {
126                 return service.getClient();
127             } catch (RemoteException e) {
128                 Log.e(TAG, e.toString());
129             }
130         } else {
131             Log.w(TAG, "Proxy not attached to service");
132             if (DBG) log(Log.getStackTraceString(new Throwable()));
133         }
134         return null;
135     }
136 
137     /**
138      * Returns true if the specified Bluetooth device is connected.
139      * Returns false if not connected, or if this proxy object is not
140      * currently connected to the Map service.
141      */
isConnected(BluetoothDevice device)142     public boolean isConnected(BluetoothDevice device) {
143         if (VDBG) log("isConnected(" + device + ")");
144         final IBluetoothMap service = getService();
145         if (service != null) {
146             try {
147                 return service.isConnected(device);
148             } catch (RemoteException e) {
149                 Log.e(TAG, e.toString());
150             }
151         } else {
152             Log.w(TAG, "Proxy not attached to service");
153             if (DBG) log(Log.getStackTraceString(new Throwable()));
154         }
155         return false;
156     }
157 
158     /**
159      * Initiate connection. Initiation of outgoing connections is not
160      * supported for MAP server.
161      */
connect(BluetoothDevice device)162     public boolean connect(BluetoothDevice device) {
163         if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
164         return false;
165     }
166 
167     /**
168      * Initiate disconnect.
169      *
170      * @param device Remote Bluetooth Device
171      * @return false on error, true otherwise
172      */
173     @UnsupportedAppUsage
disconnect(BluetoothDevice device)174     public boolean disconnect(BluetoothDevice device) {
175         if (DBG) log("disconnect(" + device + ")");
176         final IBluetoothMap service = getService();
177         if (service != null && isEnabled() && isValidDevice(device)) {
178             try {
179                 return service.disconnect(device);
180             } catch (RemoteException e) {
181                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
182                 return false;
183             }
184         }
185         if (service == null) Log.w(TAG, "Proxy not attached to service");
186         return false;
187     }
188 
189     /**
190      * Check class bits for possible Map support.
191      * This is a simple heuristic that tries to guess if a device with the
192      * given class bits might support Map. It is not accurate for all
193      * devices. It tries to err on the side of false positives.
194      *
195      * @return True if this device might support Map.
196      */
doesClassMatchSink(BluetoothClass btClass)197     public static boolean doesClassMatchSink(BluetoothClass btClass) {
198         // TODO optimize the rule
199         switch (btClass.getDeviceClass()) {
200             case BluetoothClass.Device.COMPUTER_DESKTOP:
201             case BluetoothClass.Device.COMPUTER_LAPTOP:
202             case BluetoothClass.Device.COMPUTER_SERVER:
203             case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
204                 return true;
205             default:
206                 return false;
207         }
208     }
209 
210     /**
211      * Get the list of connected devices. Currently at most one.
212      *
213      * @return list of connected devices
214      */
getConnectedDevices()215     public List<BluetoothDevice> getConnectedDevices() {
216         if (DBG) log("getConnectedDevices()");
217         final IBluetoothMap service = getService();
218         if (service != null && isEnabled()) {
219             try {
220                 return service.getConnectedDevices();
221             } catch (RemoteException e) {
222                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
223                 return new ArrayList<BluetoothDevice>();
224             }
225         }
226         if (service == null) Log.w(TAG, "Proxy not attached to service");
227         return new ArrayList<BluetoothDevice>();
228     }
229 
230     /**
231      * Get the list of devices matching specified states. Currently at most one.
232      *
233      * @return list of matching devices
234      */
getDevicesMatchingConnectionStates(int[] states)235     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
236         if (DBG) log("getDevicesMatchingStates()");
237         final IBluetoothMap service = getService();
238         if (service != null && isEnabled()) {
239             try {
240                 return service.getDevicesMatchingConnectionStates(states);
241             } catch (RemoteException e) {
242                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
243                 return new ArrayList<BluetoothDevice>();
244             }
245         }
246         if (service == null) Log.w(TAG, "Proxy not attached to service");
247         return new ArrayList<BluetoothDevice>();
248     }
249 
250     /**
251      * Get connection state of device
252      *
253      * @return device connection state
254      */
getConnectionState(BluetoothDevice device)255     public int getConnectionState(BluetoothDevice device) {
256         if (DBG) log("getConnectionState(" + device + ")");
257         final IBluetoothMap service = getService();
258         if (service != null && isEnabled() && isValidDevice(device)) {
259             try {
260                 return service.getConnectionState(device);
261             } catch (RemoteException e) {
262                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
263                 return BluetoothProfile.STATE_DISCONNECTED;
264             }
265         }
266         if (service == null) Log.w(TAG, "Proxy not attached to service");
267         return BluetoothProfile.STATE_DISCONNECTED;
268     }
269 
270     /**
271      * Set priority of the profile
272      *
273      * <p> The device should already be paired.
274      * Priority can be one of {@link #PRIORITY_ON} or
275      * {@link #PRIORITY_OFF},
276      *
277      * @param device Paired bluetooth device
278      * @param priority
279      * @return true if priority is set, false on error
280      */
setPriority(BluetoothDevice device, int priority)281     public boolean setPriority(BluetoothDevice device, int priority) {
282         if (DBG) log("setPriority(" + device + ", " + priority + ")");
283         final IBluetoothMap service = getService();
284         if (service != null && isEnabled() && isValidDevice(device)) {
285             if (priority != BluetoothProfile.PRIORITY_OFF
286                     && priority != BluetoothProfile.PRIORITY_ON) {
287                 return false;
288             }
289             try {
290                 return service.setPriority(device, priority);
291             } catch (RemoteException e) {
292                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
293                 return false;
294             }
295         }
296         if (service == null) Log.w(TAG, "Proxy not attached to service");
297         return false;
298     }
299 
300     /**
301      * Get the priority of the profile.
302      *
303      * <p> The priority can be any of:
304      * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
305      * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
306      *
307      * @param device Bluetooth device
308      * @return priority of the device
309      */
getPriority(BluetoothDevice device)310     public int getPriority(BluetoothDevice device) {
311         if (VDBG) log("getPriority(" + device + ")");
312         final IBluetoothMap service = getService();
313         if (service != null && isEnabled() && isValidDevice(device)) {
314             try {
315                 return service.getPriority(device);
316             } catch (RemoteException e) {
317                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
318                 return PRIORITY_OFF;
319             }
320         }
321         if (service == null) Log.w(TAG, "Proxy not attached to service");
322         return PRIORITY_OFF;
323     }
324 
log(String msg)325     private static void log(String msg) {
326         Log.d(TAG, msg);
327     }
328 
isEnabled()329     private boolean isEnabled() {
330         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
331         if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
332         log("Bluetooth is Not enabled");
333         return false;
334     }
isValidDevice(BluetoothDevice device)335     private static boolean isValidDevice(BluetoothDevice device) {
336         return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
337     }
338 
339 }
340