• 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 java.util.ArrayList;
20 import java.util.List;
21 
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.os.RemoteException;
27 import android.os.Binder;
28 import android.os.IBinder;
29 import android.os.ServiceManager;
30 import android.util.Log;
31 
32 /**
33  * This class provides the APIs to control the Bluetooth SIM
34  * Access Profile (SAP).
35  *
36  * <p>BluetoothSap is a proxy object for controlling the Bluetooth
37  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
38  * the BluetoothSap proxy object.
39  *
40  * <p>Each method is protected with its appropriate permission.
41  * @hide
42  */
43 public final class BluetoothSap implements BluetoothProfile {
44 
45     private static final String TAG = "BluetoothSap";
46     private static final boolean DBG = true;
47     private static final boolean VDBG = false;
48 
49     /**
50      * Intent used to broadcast the change in connection state of the profile.
51      *
52      * <p>This intent will have 4 extras:
53      * <ul>
54      *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
55      *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
56      *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
57      * </ul>
58      *
59      * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
60      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
61      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
62      *
63      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
64      * receive.
65      * @hide
66      */
67     public static final String ACTION_CONNECTION_STATE_CHANGED =
68         "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
69 
70     private IBluetoothSap mService;
71     private final Context mContext;
72     private ServiceListener mServiceListener;
73     private BluetoothAdapter mAdapter;
74 
75     /**
76      * There was an error trying to obtain the state.
77      * @hide
78      */
79     public static final int STATE_ERROR = -1;
80 
81     /**
82      * Connection state change succceeded.
83      * @hide
84      */
85     public static final int RESULT_SUCCESS = 1;
86 
87     /**
88      * Connection canceled before completion.
89      * @hide
90      */
91     public static final int RESULT_CANCELED = 2;
92 
93     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
94             new IBluetoothStateChangeCallback.Stub() {
95                 public void onBluetoothStateChange(boolean up) {
96                     if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
97                     if (!up) {
98                         if (VDBG) Log.d(TAG,"Unbinding service...");
99                         synchronized (mConnection) {
100                             try {
101                                 mService = null;
102                                 mContext.unbindService(mConnection);
103                             } catch (Exception re) {
104                                 Log.e(TAG,"",re);
105                             }
106                         }
107                     } else {
108                         synchronized (mConnection) {
109                             try {
110                                 if (mService == null) {
111                                     if (VDBG) Log.d(TAG,"Binding service...");
112                                     doBind();
113                                 }
114                             } catch (Exception re) {
115                                 Log.e(TAG,"",re);
116                             }
117                         }
118                     }
119                 }
120         };
121 
122     /**
123      * Create a BluetoothSap proxy object.
124      */
BluetoothSap(Context context, ServiceListener l)125     /*package*/ BluetoothSap(Context context, ServiceListener l) {
126         if (DBG) Log.d(TAG, "Create BluetoothSap proxy object");
127         mContext = context;
128         mServiceListener = l;
129         mAdapter = BluetoothAdapter.getDefaultAdapter();
130         IBluetoothManager mgr = mAdapter.getBluetoothManager();
131         if (mgr != null) {
132             try {
133                 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
134             } catch (RemoteException e) {
135                 Log.e(TAG,"",e);
136             }
137         }
138         doBind();
139     }
140 
doBind()141     boolean doBind() {
142         Intent intent = new Intent(IBluetoothSap.class.getName());
143         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
144         intent.setComponent(comp);
145         if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
146                 android.os.Process.myUserHandle())) {
147             Log.e(TAG, "Could not bind to Bluetooth SAP Service with " + intent);
148             return false;
149         }
150         return true;
151     }
152 
finalize()153     protected void finalize() throws Throwable {
154         try {
155             close();
156         } finally {
157             super.finalize();
158         }
159     }
160 
161     /**
162      * Close the connection to the backing service.
163      * Other public functions of BluetoothSap will return default error
164      * results once close() has been called. Multiple invocations of close()
165      * are ok.
166      * @hide
167      */
close()168     public synchronized void close() {
169         IBluetoothManager mgr = mAdapter.getBluetoothManager();
170         if (mgr != null) {
171             try {
172                 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
173             } catch (Exception e) {
174                 Log.e(TAG,"",e);
175             }
176         }
177 
178         synchronized (mConnection) {
179             if (mService != null) {
180                 try {
181                     mService = null;
182                     mContext.unbindService(mConnection);
183                 } catch (Exception re) {
184                     Log.e(TAG,"",re);
185                 }
186             }
187         }
188         mServiceListener = null;
189     }
190 
191     /**
192      * Get the current state of the BluetoothSap service.
193      * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
194      *         object is currently not connected to the Sap service.
195      * @hide
196      */
getState()197     public int getState() {
198         if (VDBG) log("getState()");
199         if (mService != null) {
200             try {
201                 return mService.getState();
202             } catch (RemoteException e) {Log.e(TAG, e.toString());}
203         } else {
204             Log.w(TAG, "Proxy not attached to service");
205             if (DBG) log(Log.getStackTraceString(new Throwable()));
206         }
207         return BluetoothSap.STATE_ERROR;
208     }
209 
210     /**
211      * Get the currently connected remote Bluetooth device (PCE).
212      * @return The remote Bluetooth device, or null if not in connected or
213      *         connecting state, or if this proxy object is not connected to
214      *         the Sap service.
215      * @hide
216      */
getClient()217     public BluetoothDevice getClient() {
218         if (VDBG) log("getClient()");
219         if (mService != null) {
220             try {
221                 return mService.getClient();
222             } catch (RemoteException e) {Log.e(TAG, e.toString());}
223         } else {
224             Log.w(TAG, "Proxy not attached to service");
225             if (DBG) log(Log.getStackTraceString(new Throwable()));
226         }
227         return null;
228     }
229 
230     /**
231      * Returns true if the specified Bluetooth device is connected.
232      * Returns false if not connected, or if this proxy object is not
233      * currently connected to the Sap service.
234      * @hide
235      */
isConnected(BluetoothDevice device)236     public boolean isConnected(BluetoothDevice device) {
237         if (VDBG) log("isConnected(" + device + ")");
238         if (mService != null) {
239             try {
240                 return mService.isConnected(device);
241             } catch (RemoteException e) {Log.e(TAG, e.toString());}
242         } else {
243             Log.w(TAG, "Proxy not attached to service");
244             if (DBG) log(Log.getStackTraceString(new Throwable()));
245         }
246         return false;
247     }
248 
249     /**
250      * Initiate connection. Initiation of outgoing connections is not
251      * supported for SAP server.
252      * @hide
253      */
connect(BluetoothDevice device)254     public boolean connect(BluetoothDevice device) {
255         if (DBG) log("connect(" + device + ")" + "not supported for SAPS");
256         return false;
257     }
258 
259     /**
260      * Initiate disconnect.
261      *
262      * @param device Remote Bluetooth Device
263      * @return false on error,
264      *               true otherwise
265      * @hide
266      */
disconnect(BluetoothDevice device)267     public boolean disconnect(BluetoothDevice device) {
268         if (DBG) log("disconnect(" + device + ")");
269         if (mService != null && isEnabled() &&
270             isValidDevice(device)) {
271             try {
272                 return mService.disconnect(device);
273             } catch (RemoteException e) {
274               Log.e(TAG, Log.getStackTraceString(new Throwable()));
275               return false;
276             }
277         }
278         if (mService == null) Log.w(TAG, "Proxy not attached to service");
279         return false;
280     }
281 
282     /**
283      * Get the list of connected devices. Currently at most one.
284      *
285      * @return list of connected devices
286      * @hide
287      */
getConnectedDevices()288     public List<BluetoothDevice> getConnectedDevices() {
289         if (DBG) log("getConnectedDevices()");
290         if (mService != null && isEnabled()) {
291             try {
292                 return mService.getConnectedDevices();
293             } catch (RemoteException e) {
294                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
295                 return new ArrayList<BluetoothDevice>();
296             }
297         }
298         if (mService == null) Log.w(TAG, "Proxy not attached to service");
299         return new ArrayList<BluetoothDevice>();
300     }
301 
302     /**
303      * Get the list of devices matching specified states. Currently at most one.
304      *
305      * @return list of matching devices
306      * @hide
307      */
getDevicesMatchingConnectionStates(int[] states)308     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
309         if (DBG) log("getDevicesMatchingStates()");
310         if (mService != null && isEnabled()) {
311             try {
312                 return mService.getDevicesMatchingConnectionStates(states);
313             } catch (RemoteException e) {
314                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
315                 return new ArrayList<BluetoothDevice>();
316             }
317         }
318         if (mService == null) Log.w(TAG, "Proxy not attached to service");
319         return new ArrayList<BluetoothDevice>();
320     }
321 
322     /**
323      * Get connection state of device
324      *
325      * @return device connection state
326      * @hide
327      */
getConnectionState(BluetoothDevice device)328     public int getConnectionState(BluetoothDevice device) {
329         if (DBG) log("getConnectionState(" + device + ")");
330         if (mService != null && isEnabled() &&
331             isValidDevice(device)) {
332             try {
333                 return mService.getConnectionState(device);
334             } catch (RemoteException e) {
335                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
336                 return BluetoothProfile.STATE_DISCONNECTED;
337             }
338         }
339         if (mService == null) Log.w(TAG, "Proxy not attached to service");
340         return BluetoothProfile.STATE_DISCONNECTED;
341     }
342 
343     /**
344      * Set priority of the profile
345      *
346      * <p> The device should already be paired.
347      *
348      * @param device Paired bluetooth device
349      * @param priority
350      * @return true if priority is set, false on error
351      * @hide
352      */
setPriority(BluetoothDevice device, int priority)353     public boolean setPriority(BluetoothDevice device, int priority) {
354         if (DBG) log("setPriority(" + device + ", " + priority + ")");
355         if (mService != null && isEnabled() &&
356             isValidDevice(device)) {
357             if (priority != BluetoothProfile.PRIORITY_OFF &&
358                 priority != BluetoothProfile.PRIORITY_ON) {
359               return false;
360             }
361             try {
362                 return mService.setPriority(device, priority);
363             } catch (RemoteException e) {
364                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
365                 return false;
366             }
367         }
368         if (mService == null) Log.w(TAG, "Proxy not attached to service");
369         return false;
370     }
371 
372     /**
373      * Get the priority of the profile.
374      *
375      * @param device Bluetooth device
376      * @return priority of the device
377      * @hide
378      */
getPriority(BluetoothDevice device)379     public int getPriority(BluetoothDevice device) {
380         if (VDBG) log("getPriority(" + device + ")");
381         if (mService != null && isEnabled() &&
382             isValidDevice(device)) {
383             try {
384                 return mService.getPriority(device);
385             } catch (RemoteException e) {
386                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
387                 return PRIORITY_OFF;
388             }
389         }
390         if (mService == null) Log.w(TAG, "Proxy not attached to service");
391         return PRIORITY_OFF;
392     }
393 
394     private ServiceConnection mConnection = new ServiceConnection() {
395         public void onServiceConnected(ComponentName className, IBinder service) {
396             if (DBG) log("Proxy object connected");
397             mService = IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service));
398             if (mServiceListener != null) {
399                 mServiceListener.onServiceConnected(BluetoothProfile.SAP, BluetoothSap.this);
400             }
401         }
402         public void onServiceDisconnected(ComponentName className) {
403             if (DBG) log("Proxy object disconnected");
404             mService = null;
405             if (mServiceListener != null) {
406                 mServiceListener.onServiceDisconnected(BluetoothProfile.SAP);
407             }
408         }
409     };
410 
log(String msg)411     private static void log(String msg) {
412         Log.d(TAG, msg);
413     }
414 
isEnabled()415     private boolean isEnabled() {
416         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
417 
418         if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON)
419             return true;
420         log("Bluetooth is Not enabled");
421         return false;
422     }
423 
isValidDevice(BluetoothDevice device)424     private boolean isValidDevice(BluetoothDevice device) {
425        if (device == null)
426            return false;
427 
428        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress()))
429            return true;
430        return false;
431     }
432 
433 }
434