diff options
| author | 2016-03-04 13:02:54 -0800 | |
|---|---|---|
| committer | 2016-03-14 17:02:16 -0700 | |
| commit | cfa8a6469463ace9c3336e3686d950792a2c7ad4 (patch) | |
| tree | b68b50ae2b47d28c5b52d9886ee49b76f4e3e6fb | |
| parent | 329484bb7e31e3b0574cd25186a9d6a840f39781 (diff) | |
Add BluetoothProfile for PBAP PCE role.
Create a new Bluetooth profile for Pbap Client.
Bug: 27490041
Change-Id: I77d2c7eeeb8e955ea61386d784b02b14f415b318
| -rw-r--r-- | Android.mk | 1 | ||||
| -rw-r--r-- | core/java/android/bluetooth/BluetoothAdapter.java | 9 | ||||
| -rw-r--r-- | core/java/android/bluetooth/BluetoothPbapClient.java | 331 | ||||
| -rw-r--r-- | core/java/android/bluetooth/BluetoothProfile.java | 6 | ||||
| -rw-r--r-- | core/java/android/bluetooth/IBluetoothPbapClient.aidl | 32 |
5 files changed, 378 insertions, 1 deletions
diff --git a/Android.mk b/Android.mk index 3ac5889f61c3..dfa9f58d2d18 100644 --- a/Android.mk +++ b/Android.mk @@ -117,6 +117,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothManager.aidl \ core/java/android/bluetooth/IBluetoothManagerCallback.aidl \ core/java/android/bluetooth/IBluetoothPbap.aidl \ + core/java/android/bluetooth/IBluetoothPbapClient.aidl \ core/java/android/bluetooth/IBluetoothMap.aidl \ core/java/android/bluetooth/IBluetoothSap.aidl \ core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \ diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index eb4cb919ce1b..d762a1727272 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Android Open Source Project + * Copyright (C) 2009-2016 The Android Open Source Project * Copyright (C) 2015 Samsung LSI * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -1837,6 +1837,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.SAP) { BluetoothSap sap = new BluetoothSap(context, listener); return true; + } else if (profile == BluetoothProfile.PBAP_CLIENT) { + BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener); + return true; } else { return false; } @@ -1905,6 +1908,10 @@ public final class BluetoothAdapter { BluetoothSap sap = (BluetoothSap)proxy; sap.close(); break; + case BluetoothProfile.PBAP_CLIENT: + BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy; + pbapClient.close(); + break; } } diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java new file mode 100644 index 000000000000..736e55d17d8a --- /dev/null +++ b/core/java/android/bluetooth/BluetoothPbapClient.java @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import java.util.List; +import java.util.ArrayList; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.RemoteException; +import android.os.IBinder; +import android.util.Log; + +/** + * This class provides the APIs to control the Bluetooth PBAP Client Profile. + *@hide + */ +public final class BluetoothPbapClient implements BluetoothProfile { + + private static final String TAG = "BluetoothPbapClient"; + private static final boolean DBG = false; + private static final boolean VDBG = false; + + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED"; + + private IBluetoothPbapClient mService; + private BluetoothDevice mDevice; + private final Context mContext; + private ServiceListener mServiceListener; + private BluetoothAdapter mAdapter; + + /** There was an error trying to obtain the state */ + public static final int STATE_ERROR = -1; + + public static final int RESULT_FAILURE = 0; + public static final int RESULT_SUCCESS = 1; + /** Connection canceled before completion. */ + public static final int RESULT_CANCELED = 2; + + final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + public void onBluetoothStateChange(boolean up) { + if (DBG) { + Log.d(TAG, "onBluetoothStateChange: PBAP CLIENT up=" + up); + } + if (!up) { + if (VDBG) { + Log.d(TAG,"Unbinding service..."); + } + synchronized (mConnection) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (VDBG) { + Log.d(TAG,"Binding service..."); + } + doBind(); + } + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + }; + + /** + * Create a BluetoothPbapClient proxy object. + */ + BluetoothPbapClient(Context context, ServiceListener l) { + if (DBG) { + Log.d(TAG, "Create BluetoothPbapClient proxy object"); + } + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + doBind(); + } + + private boolean doBind() { + Intent intent = new Intent(IBluetoothPbapClient.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth PBAP Client Service with " + intent); + return false; + } + return true; + } + + protected void finalize() throws Throwable { + try { + close(); + } finally { + super.finalize(); + } + } + + /** + * Close the connection to the backing service. + * Other public functions of BluetoothPbapClient will return default error + * results once close() has been called. Multiple invocations of close() + * are ok. + */ + public synchronized void close() { + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (Exception e) { + Log.e(TAG,"",e); + } + } + + synchronized (mConnection) { + if (mService != null) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + mServiceListener = null; + } + + /** + * Initiate connection. + * Upon successful connection to remote PBAP server the Client will + * attempt to automatically download the users phonebook and call log. + * + * @param device a remote device we want connect to + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + */ + public boolean connect(BluetoothDevice device) { + if (DBG) { + log("connect(" + device + ") for PBAP Client."); + } + if (mService != null && isEnabled() && isValidDevice(device)) { + try { + mDevice = device; + return mService.connect(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return false; + } + + /** + * Initiate disconnect. + * + * @param device Remote Bluetooth Device + * @return false on error, + * true otherwise + */ + public boolean disconnect() { + if (DBG) { + log("disconnect(" + mDevice + ")"); + } + if (mService != null && isEnabled() && isValidDevice(mDevice)) { + try { + mService.disconnect(mDevice); + return true; + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return false; + } + + /** + * Get the list of connected devices. + * Currently at most one. + * + * @return list of connected devices + */ + @Override + public List<BluetoothDevice> getConnectedDevices() { + if (DBG) { + log("getConnectedDevices()"); + } + if (mService != null && isEnabled()) { + try { + return mService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return new ArrayList<BluetoothDevice>(); + } + + /** + * Get the list of devices matching specified states. Currently at most one. + * + * @return list of matching devices + */ + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (DBG) { + log("getDevicesMatchingStates()"); + } + if (mService != null && isEnabled()) { + try { + return mService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return new ArrayList<BluetoothDevice>(); + } + + /** + * Get connection state of device + * + * @return device connection state + */ + @Override + public int getConnectionState(BluetoothDevice device) { + if (DBG) { + log("getConnectionState(" + device + ")"); + } + if (mService != null && isEnabled() && isValidDevice(device)) { + try { + return mService.getConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return BluetoothProfile.STATE_DISCONNECTED; + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) { + log("Proxy object connected"); + } + mService = IBluetoothPbapClient.Stub.asInterface(service); + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient.this); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) { + log("Proxy object disconnected"); + } + mService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP_CLIENT); + } + } + }; + + private static void log(String msg) { + Log.d(TAG, msg); + } + + private boolean isEnabled() { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) { + return true; + } + log("Bluetooth is Not enabled"); + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) { + return false; + } + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + return true; + } + return false; + } +} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index cbce22cdea60..eee66d193fe4 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -131,6 +131,12 @@ public interface BluetoothProfile { public static final int HEADSET_CLIENT = 16; /** + * PBAP Client + * @hide + */ + public static final int PBAP_CLIENT = 17; + + /** * Default priority for devices that we try to auto-connect to and * and allow incoming connections for the profile * @hide diff --git a/core/java/android/bluetooth/IBluetoothPbapClient.aidl b/core/java/android/bluetooth/IBluetoothPbapClient.aidl new file mode 100644 index 000000000000..b26ea2957142 --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothPbapClient.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import android.bluetooth.BluetoothDevice; + +/** + * API for Bluetooth Phone Book Access Provile Client Side + * + * {@hide} + */ +interface IBluetoothPbapClient { + boolean connect(in BluetoothDevice device); + boolean disconnect(in BluetoothDevice device); + List<BluetoothDevice> getConnectedDevices(); + List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); + int getConnectionState(in BluetoothDevice device); +} |