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