blob: 9618ba01572e94eddfb708ab3e83f94c9f105c2d [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
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080019import android.Manifest;
20import android.annotation.RequiresPermission;
21import android.annotation.SystemApi;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080022import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060023import android.os.Binder;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080024import android.os.IBinder;
Jack Hea355e5e2017-08-22 16:06:54 -070025import android.os.RemoteException;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080026import android.util.Log;
27
Jack Hea355e5e2017-08-22 16:06:54 -070028import java.util.ArrayList;
29import java.util.List;
30
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080031/**
32 * This class provides the APIs to control the Bluetooth PBAP Client Profile.
Jack Hea355e5e2017-08-22 16:06:54 -070033 *
34 * @hide
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080035 */
36public final class BluetoothPbapClient implements BluetoothProfile {
37
38 private static final String TAG = "BluetoothPbapClient";
39 private static final boolean DBG = false;
40 private static final boolean VDBG = false;
41
42 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack He37ab8152017-10-02 19:08:30 -070043 "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080044
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080045 /** There was an error trying to obtain the state */
Jack Hea355e5e2017-08-22 16:06:54 -070046 public static final int STATE_ERROR = -1;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080047
48 public static final int RESULT_FAILURE = 0;
49 public static final int RESULT_SUCCESS = 1;
50 /** Connection canceled before completion. */
51 public static final int RESULT_CANCELED = 2;
52
Ugo Yud0115462019-03-26 21:38:08 +080053 private BluetoothAdapter mAdapter;
54 private final BluetoothProfileConnector<IBluetoothPbapClient> mProfileConnector =
55 new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT,
56 "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) {
57 @Override
58 public IBluetoothPbapClient getServiceInterface(IBinder service) {
59 return IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080060 }
Ugo Yud0115462019-03-26 21:38:08 +080061 };
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080062
63 /**
64 * Create a BluetoothPbapClient proxy object.
65 */
Ugo Yud0115462019-03-26 21:38:08 +080066 BluetoothPbapClient(Context context, ServiceListener listener) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080067 if (DBG) {
68 Log.d(TAG, "Create BluetoothPbapClient proxy object");
69 }
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080070 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +080071 mProfileConnector.connect(context, listener);
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080072 }
73
74 protected void finalize() throws Throwable {
75 try {
76 close();
77 } finally {
78 super.finalize();
79 }
80 }
81
82 /**
83 * Close the connection to the backing service.
84 * Other public functions of BluetoothPbapClient will return default error
85 * results once close() has been called. Multiple invocations of close()
86 * are ok.
87 */
88 public synchronized void close() {
Ugo Yud0115462019-03-26 21:38:08 +080089 mProfileConnector.disconnect();
90 }
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080091
Ugo Yud0115462019-03-26 21:38:08 +080092 private IBluetoothPbapClient getService() {
93 return mProfileConnector.getService();
Joseph Pirozzocfa8a642016-03-04 13:02:54 -080094 }
95
96 /**
97 * Initiate connection.
98 * Upon successful connection to remote PBAP server the Client will
99 * attempt to automatically download the users phonebook and call log.
100 *
Jack Hea355e5e2017-08-22 16:06:54 -0700101 * @param device a remote device we want connect to
102 * @return <code>true</code> if command has been issued successfully; <code>false</code>
103 * otherwise;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800104 */
105 public boolean connect(BluetoothDevice device) {
106 if (DBG) {
107 log("connect(" + device + ") for PBAP Client.");
108 }
Ugo Yud0115462019-03-26 21:38:08 +0800109 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700110 if (service != null && isEnabled() && isValidDevice(device)) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800111 try {
Jack He16eeac32017-08-17 12:11:18 -0700112 return service.connect(device);
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800113 } catch (RemoteException e) {
114 Log.e(TAG, Log.getStackTraceString(new Throwable()));
115 return false;
116 }
117 }
Jack He16eeac32017-08-17 12:11:18 -0700118 if (service == null) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800119 Log.w(TAG, "Proxy not attached to service");
120 }
121 return false;
122 }
123
124 /**
125 * Initiate disconnect.
126 *
127 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700128 * @return false on error, true otherwise
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800129 */
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700130 public boolean disconnect(BluetoothDevice device) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800131 if (DBG) {
Jack Hea355e5e2017-08-22 16:06:54 -0700132 log("disconnect(" + device + ")" + new Exception());
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800133 }
Ugo Yud0115462019-03-26 21:38:08 +0800134 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700135 if (service != null && isEnabled() && isValidDevice(device)) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800136 try {
Jack He16eeac32017-08-17 12:11:18 -0700137 service.disconnect(device);
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800138 return true;
139 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700140 Log.e(TAG, Log.getStackTraceString(new Throwable()));
141 return false;
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800142 }
143 }
Jack He16eeac32017-08-17 12:11:18 -0700144 if (service == null) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800145 Log.w(TAG, "Proxy not attached to service");
146 }
147 return false;
148 }
149
150 /**
151 * Get the list of connected devices.
152 * Currently at most one.
153 *
154 * @return list of connected devices
155 */
156 @Override
157 public List<BluetoothDevice> getConnectedDevices() {
158 if (DBG) {
159 log("getConnectedDevices()");
160 }
Ugo Yud0115462019-03-26 21:38:08 +0800161 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700162 if (service != null && isEnabled()) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800163 try {
Jack He16eeac32017-08-17 12:11:18 -0700164 return service.getConnectedDevices();
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800165 } catch (RemoteException e) {
166 Log.e(TAG, Log.getStackTraceString(new Throwable()));
167 return new ArrayList<BluetoothDevice>();
168 }
169 }
Jack He16eeac32017-08-17 12:11:18 -0700170 if (service == null) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800171 Log.w(TAG, "Proxy not attached to service");
172 }
173 return new ArrayList<BluetoothDevice>();
174 }
175
176 /**
177 * Get the list of devices matching specified states. Currently at most one.
178 *
179 * @return list of matching devices
180 */
181 @Override
182 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
183 if (DBG) {
184 log("getDevicesMatchingStates()");
185 }
Ugo Yud0115462019-03-26 21:38:08 +0800186 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700187 if (service != null && isEnabled()) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800188 try {
Jack He16eeac32017-08-17 12:11:18 -0700189 return service.getDevicesMatchingConnectionStates(states);
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800190 } catch (RemoteException e) {
191 Log.e(TAG, Log.getStackTraceString(new Throwable()));
192 return new ArrayList<BluetoothDevice>();
193 }
194 }
Jack He16eeac32017-08-17 12:11:18 -0700195 if (service == null) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800196 Log.w(TAG, "Proxy not attached to service");
197 }
198 return new ArrayList<BluetoothDevice>();
199 }
200
201 /**
202 * Get connection state of device
203 *
204 * @return device connection state
205 */
206 @Override
207 public int getConnectionState(BluetoothDevice device) {
208 if (DBG) {
209 log("getConnectionState(" + device + ")");
210 }
Ugo Yud0115462019-03-26 21:38:08 +0800211 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700212 if (service != null && isEnabled() && isValidDevice(device)) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800213 try {
Jack He16eeac32017-08-17 12:11:18 -0700214 return service.getConnectionState(device);
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800215 } catch (RemoteException e) {
216 Log.e(TAG, Log.getStackTraceString(new Throwable()));
217 return BluetoothProfile.STATE_DISCONNECTED;
218 }
219 }
Jack He16eeac32017-08-17 12:11:18 -0700220 if (service == null) {
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800221 Log.w(TAG, "Proxy not attached to service");
222 }
223 return BluetoothProfile.STATE_DISCONNECTED;
224 }
225
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800226 private static void log(String msg) {
227 Log.d(TAG, msg);
228 }
229
230 private boolean isEnabled() {
231 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
232 if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
233 return true;
234 }
235 log("Bluetooth is Not enabled");
236 return false;
237 }
238
Jack He16eeac32017-08-17 12:11:18 -0700239 private static boolean isValidDevice(BluetoothDevice device) {
240 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800241 }
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700242
243 /**
244 * Set priority of the profile
245 *
246 * <p> The device should already be paired.
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800247 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700248 *
249 * @param device Paired bluetooth device
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800250 * @param priority
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700251 * @return true if priority is set, false on error
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800252 * @hide
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700253 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800254 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700255 public boolean setPriority(BluetoothDevice device, int priority) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800256 if (DBG) log("setPriority(" + device + ", " + priority + ")");
257 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
258 }
259
260 /**
261 * Set connection policy of the profile
262 *
263 * <p> The device should already be paired.
264 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
265 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
266 *
267 * @param device Paired bluetooth device
268 * @param connectionPolicy is the connection policy to set to for this profile
269 * @return true if connectionPolicy is set, false on error
270 * @hide
271 */
272 @SystemApi
273 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
274 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700275 if (DBG) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800276 log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700277 }
Ugo Yud0115462019-03-26 21:38:08 +0800278 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700279 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800280 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
281 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Jack Hea355e5e2017-08-22 16:06:54 -0700282 return false;
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700283 }
284 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800285 return service.setConnectionPolicy(device, connectionPolicy);
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700286 } catch (RemoteException e) {
287 Log.e(TAG, Log.getStackTraceString(new Throwable()));
288 return false;
289 }
290 }
Jack He16eeac32017-08-17 12:11:18 -0700291 if (service == null) {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700292 Log.w(TAG, "Proxy not attached to service");
293 }
294 return false;
295 }
296
297 /**
298 * Get the priority of the profile.
299 *
300 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800301 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700302 *
303 * @param device Bluetooth device
304 * @return priority of the device
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800305 * @hide
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700306 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800307 @RequiresPermission(Manifest.permission.BLUETOOTH)
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700308 public int getPriority(BluetoothDevice device) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800309 if (VDBG) log("getPriority(" + device + ")");
310 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
311 }
312
313 /**
314 * Get the connection policy of the profile.
315 *
316 * <p> The connection policy can be any of:
317 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
318 * {@link #CONNECTION_POLICY_UNKNOWN}
319 *
320 * @param device Bluetooth device
321 * @return connection policy of the device
322 * @hide
323 */
324 @SystemApi
325 @RequiresPermission(Manifest.permission.BLUETOOTH)
326 public int getConnectionPolicy(BluetoothDevice device) {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700327 if (VDBG) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800328 log("getConnectionPolicy(" + device + ")");
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700329 }
Ugo Yud0115462019-03-26 21:38:08 +0800330 final IBluetoothPbapClient service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700331 if (service != null && isEnabled() && isValidDevice(device)) {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700332 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800333 return service.getConnectionPolicy(device);
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700334 } catch (RemoteException e) {
335 Log.e(TAG, Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800336 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700337 }
338 }
Jack He16eeac32017-08-17 12:11:18 -0700339 if (service == null) {
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700340 Log.w(TAG, "Proxy not attached to service");
341 }
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800342 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700343 }
Joseph Pirozzocfa8a642016-03-04 13:02:54 -0800344}