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