blob: eab4c6f5130c6f2a7aa42f057bdbf75353c3149b [file] [log] [blame]
Joseph Pirozzocfa8a642016-03-04 13:02:54 -08001/*
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
17package android.bluetooth;
18
19import java.util.List;
20import java.util.ArrayList;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.os.RemoteException;
26import android.os.IBinder;
27import android.util.Log;
28
29/**
30 * This class provides the APIs to control the Bluetooth PBAP Client Profile.
31 *@hide
32 */
33public 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;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080043 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 */
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
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
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 */
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 */
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 {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800175 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 */
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700194 public boolean disconnect(BluetoothDevice device) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800195 if (DBG) {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700196 log("disconnect(" + device + ")" + new Exception() );
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800197 }
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700198 if (mService != null && isEnabled() && isValidDevice(device)) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800199 try {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700200 mService.disconnect(device);
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800201 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
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
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
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
307 private static void log(String msg) {
308 Log.d(TAG, msg);
309 }
310
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
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 }
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700329
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 */
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 */
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 }
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800391}