diff options
| author | 2016-03-30 21:00:52 +0000 | |
|---|---|---|
| committer | 2016-03-30 21:00:54 +0000 | |
| commit | 43b5d980d89f4badfe89008febf5fcd6e1ae9d49 (patch) | |
| tree | a899a3d60b98b57d3d7bcbe1b57bdef840452773 | |
| parent | 0ade7ff3c0100d14ca2ae0319830b5210e66ed27 (diff) | |
| parent | 563c700f7025d2f792a52b7483725b3d58eaa7a6 (diff) | |
Merge "PBAP client Settings profile." into nyc-dev
6 files changed, 366 insertions, 8 deletions
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java index 736e55d17d8a..eab4c6f5130c 100644 --- a/core/java/android/bluetooth/BluetoothPbapClient.java +++ b/core/java/android/bluetooth/BluetoothPbapClient.java @@ -40,7 +40,6 @@ public final class BluetoothPbapClient implements BluetoothProfile { "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED"; private IBluetoothPbapClient mService; - private BluetoothDevice mDevice; private final Context mContext; private ServiceListener mServiceListener; private BluetoothAdapter mAdapter; @@ -173,7 +172,6 @@ public final class BluetoothPbapClient implements BluetoothProfile { } if (mService != null && isEnabled() && isValidDevice(device)) { try { - mDevice = device; return mService.connect(device); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -193,13 +191,13 @@ public final class BluetoothPbapClient implements BluetoothProfile { * @return false on error, * true otherwise */ - public boolean disconnect() { + public boolean disconnect(BluetoothDevice device) { if (DBG) { - log("disconnect(" + mDevice + ")"); + log("disconnect(" + device + ")" + new Exception() ); } - if (mService != null && isEnabled() && isValidDevice(mDevice)) { + if (mService != null && isEnabled() && isValidDevice(device)) { try { - mService.disconnect(mDevice); + mService.disconnect(device); return true; } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -328,4 +326,66 @@ public final class BluetoothPbapClient implements BluetoothProfile { } return false; } + + /** + * Set priority of the profile + * + * <p> The device should already be paired. + * Priority can be one of {@link #PRIORITY_ON} or + * {@link #PRIORITY_OFF}, + * + * @param device Paired bluetooth device + * @param priority + * @return true if priority is set, false on error + */ + public boolean setPriority(BluetoothDevice device, int priority) { + if (DBG) { + log("setPriority(" + device + ", " + priority + ")"); + } + if (mService != null && isEnabled() && + isValidDevice(device)) { + if (priority != BluetoothProfile.PRIORITY_OFF && + priority != BluetoothProfile.PRIORITY_ON) { + return false; + } + try { + return mService.setPriority(device, priority); + } 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 priority of the profile. + * + * <p> The priority can be any of: + * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF}, + * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} + * + * @param device Bluetooth device + * @return priority of the device + */ + public int getPriority(BluetoothDevice device) { + if (VDBG) { + log("getPriority(" + device + ")"); + } + if (mService != null && isEnabled() && isValidDevice(device)) { + try { + return mService.getPriority(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return PRIORITY_OFF; + } + } + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return PRIORITY_OFF; + } } diff --git a/core/java/android/bluetooth/IBluetoothPbapClient.aidl b/core/java/android/bluetooth/IBluetoothPbapClient.aidl index b26ea2957142..6d4c5a6f90b6 100644 --- a/core/java/android/bluetooth/IBluetoothPbapClient.aidl +++ b/core/java/android/bluetooth/IBluetoothPbapClient.aidl @@ -29,4 +29,6 @@ interface IBluetoothPbapClient { List<BluetoothDevice> getConnectedDevices(); List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); int getConnectionState(in BluetoothDevice device); + boolean setPriority(in BluetoothDevice device, int priority); + int getPriority(in BluetoothDevice device); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a78f4687df2f..ebecfdb714dd 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7679,6 +7679,9 @@ public final class Settings { BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_"; /** {@hide} */ public static final String + BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_"; + /** {@hide} */ + public static final String BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_"; /** @@ -7834,6 +7837,14 @@ public final class Settings { } /** + * Get the key that retrieves a bluetooth pbap client priority. + * @hide + */ + public static final String getBluetoothPbapClientPriorityKey(String address) { + return BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT); + } + + /** * Get the key that retrieves a bluetooth map priority. * @hide */ diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml new file mode 100755 index 000000000000..299a5b74689c --- /dev/null +++ b/packages/SettingsLib/res/values/config.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +*/ +--> +<resources> + <!-- Configuration for automotive --> + <bool name="enable_pbap_pce_profile">false</bool> +</resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 6226b23c0ab2..6052ccd4ff8e 100755 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -24,12 +24,14 @@ import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothMap; import android.bluetooth.BluetoothInputDevice; import android.bluetooth.BluetoothPan; +import android.bluetooth.BluetoothPbapClient; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; import android.content.Intent; import android.os.ParcelUuid; import android.util.Log; +import com.android.settingslib.R; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -82,7 +84,9 @@ public final class LocalBluetoothProfileManager { private final HidProfile mHidProfile; private OppProfile mOppProfile; private final PanProfile mPanProfile; + private PbapClientProfile mPbapClientProfile; private final PbapServerProfile mPbapProfile; + private final boolean mUsePbapPce; /** * Mapping from profile name, e.g. "HEADSET" to profile object. @@ -99,6 +103,7 @@ public final class LocalBluetoothProfileManager { mLocalAdapter = adapter; mDeviceManager = deviceManager; mEventManager = eventManager; + mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile); // pass this reference to adapter and event manager (circular dependency) mLocalAdapter.setProfileManager(this); mEventManager.setProfileManager(this); @@ -205,9 +210,24 @@ public final class LocalBluetoothProfileManager { } else if (mOppProfile != null) { Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing."); } + + //PBAP Client + if (mUsePbapPce) { + if (mPbapClientProfile == null) { + if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile"); + mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager, + this); + addProfile(mPbapClientProfile, PbapClientProfile.NAME, + BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED); + } + } else if (mPbapClientProfile != null) { + Log.w(TAG, + "Warning: PBAP Client profile was previously added but the UUID is now missing."); + } + mEventManager.registerProfileIntentReceiver(); - // There is no local SDP record for HID and Settings app doesn't control PBAP + // There is no local SDP record for HID and Settings app doesn't control PBAP Server. } private final Collection<ServiceListener> mServiceListeners = @@ -351,6 +371,10 @@ public final class LocalBluetoothProfileManager { } } + public PbapClientProfile getPbapClientProfile() { + return mPbapClientProfile; + } + public PbapServerProfile getPbapProfile(){ return mPbapProfile; } @@ -430,6 +454,12 @@ public final class LocalBluetoothProfileManager { removedProfiles.remove(mMapProfile); mMapProfile.setPreferred(device, true); } - } + if (mUsePbapPce) { + profiles.add(mPbapClientProfile); + removedProfiles.remove(mPbapClientProfile); + profiles.remove(mPbapProfile); + removedProfiles.add(mPbapProfile); + } + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java new file mode 100755 index 000000000000..aa95be27ea52 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java @@ -0,0 +1,233 @@ +/* + * 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 com.android.settingslib.bluetooth; + +import android.bluetooth.BluetoothPbapClient; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothUuid; +import android.content.Context; +import android.os.ParcelUuid; +import android.util.Log; + +import com.android.settingslib.R; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +final class PbapClientProfile implements LocalBluetoothProfile { + private static final String TAG = "PbapClientProfile"; + private static boolean V = false; + + private BluetoothPbapClient mService; + private boolean mIsProfileReady; + + private final LocalBluetoothAdapter mLocalAdapter; + private final CachedBluetoothDeviceManager mDeviceManager; + + static final ParcelUuid[] SRC_UUIDS = { + BluetoothUuid.PBAP_PSE, + }; + + static final String NAME = "PbapClient"; + private final LocalBluetoothProfileManager mProfileManager; + + // Order of this profile in device profiles list + private static final int ORDINAL = 6; + + // These callbacks run on the main thread. + private final class PbapClientServiceListener + implements BluetoothProfile.ServiceListener { + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (V) { + Log.d(TAG,"Bluetooth service connected"); + } + mService = (BluetoothPbapClient) proxy; + // We just bound to the service, so refresh the UI for any connected PBAP devices. + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + while (!deviceList.isEmpty()) { + BluetoothDevice nextDevice = deviceList.remove(0); + CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); + // we may add a new device here, but generally this should not happen + if (device == null) { + Log.w(TAG, "PbapClientProfile found new device: " + nextDevice); + device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); + } + device.onProfileStateChanged(PbapClientProfile.this, BluetoothProfile.STATE_CONNECTED); + device.refresh(); + } + mIsProfileReady = true; + } + + public void onServiceDisconnected(int profile) { + if (V) { + Log.d(TAG,"Bluetooth service disconnected"); + } + mIsProfileReady = false; + } + } + + private void refreshProfiles() { + Collection<CachedBluetoothDevice> cachedDevices = mDeviceManager.getCachedDevicesCopy(); + for (CachedBluetoothDevice device : cachedDevices) { + device.onUuidChanged(); + } + } + + public boolean pbapClientExists() { + return (mService != null); + } + + public boolean isProfileReady() { + return mIsProfileReady; + } + + PbapClientProfile(Context context, LocalBluetoothAdapter adapter, + CachedBluetoothDeviceManager deviceManager, + LocalBluetoothProfileManager profileManager) { + mLocalAdapter = adapter; + mDeviceManager = deviceManager; + mProfileManager = profileManager; + mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(), + BluetoothProfile.PBAP_CLIENT); + } + + public boolean isConnectable() { + return true; + } + + public boolean isAutoConnectable() { + return true; + } + + public List<BluetoothDevice> getConnectedDevices() { + if (mService == null) { + return new ArrayList<BluetoothDevice>(0); + } + return mService.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.STATE_CONNECTING, + BluetoothProfile.STATE_DISCONNECTING}); + } + + public boolean connect(BluetoothDevice device) { + if (V) { + Log.d(TAG,"PBAPClientProfile got connect request"); + } + if (mService == null) { + return false; + } + List<BluetoothDevice> srcs = getConnectedDevices(); + if (srcs != null) { + for (BluetoothDevice src : srcs) { + if (src.equals(device)) { + // Connect to same device, Ignore it + Log.d(TAG,"Ignoring Connect"); + return true; + } + } + mService.disconnect(device); + } + Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress()); + + return mService.connect(device); + } + + public boolean disconnect(BluetoothDevice device) { + if (V) { + Log.d(TAG,"PBAPClientProfile got disconnect request"); + } + if (mService == null) { + return false; + } + return mService.disconnect(device); + } + + public int getConnectionStatus(BluetoothDevice device) { + if (mService == null) { + return BluetoothProfile.STATE_DISCONNECTED; + } + return mService.getConnectionState(device); + } + + public boolean isPreferred(BluetoothDevice device) { + if (mService == null) { + return false; + } + return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + } + + public int getPreferred(BluetoothDevice device) { + if (mService == null) { + return BluetoothProfile.PRIORITY_OFF; + } + return mService.getPriority(device); + } + + public void setPreferred(BluetoothDevice device, boolean preferred) { + if (mService == null) { + return; + } + if (preferred) { + if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + } else { + mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + } + } + + public String toString() { + return NAME; + } + + public int getOrdinal() { + return ORDINAL; + } + + public int getNameResource(BluetoothDevice device) { + // we need to have same string in UI as the server side. + return R.string.bluetooth_profile_pbap; + } + + public int getSummaryResourceForDevice(BluetoothDevice device) { + return R.string.bluetooth_profile_pbap_summary; + } + + public int getDrawableResource(BluetoothClass btClass) { + return R.drawable.ic_bt_cellphone; + } + + protected void finalize() { + if (V) { + Log.d(TAG, "finalize()"); + } + if (mService != null) { + try { + BluetoothAdapter.getDefaultAdapter().closeProfileProxy( + BluetoothProfile.PBAP_CLIENT,mService); + mService = null; + } catch (Throwable t) { + Log.w(TAG, "Error cleaning up PBAP Client proxy", t); + } + } + } +} |