diff options
author | AnubhavGupta <anubhavg@codeaurora.org> | 2015-06-30 12:40:39 +0530 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2015-10-06 03:26:43 -0600 |
commit | a63a2505e74e6955d54629c488699c7f9c52cf18 (patch) | |
tree | 8bc30213e23f99a4596531c73cacc7f3968d2d38 /packages/SettingsLib | |
parent | 05d1af456aed6220adce73e9781c08c74e176b3e (diff) | |
download | frameworks_base-a63a2505e74e6955d54629c488699c7f9c52cf18.zip frameworks_base-a63a2505e74e6955d54629c488699c7f9c52cf18.tar.gz frameworks_base-a63a2505e74e6955d54629c488699c7f9c52cf18.tar.bz2 |
Bluetooth: A2DP Sink support for Settings App
- add support for A2DP Sink in Settings App. This will enable connection
initiation and updation on Settings App
- add framework Apis to support A2DP Sink. Any third party Apps can access
A2DP Sink priority of device and playing state of device
- add support for key to set priority. This manages priority of device for
A2DP Sink profile
Change-Id: I9920957e0f20583e1e2d57ca76c2c0bd9dfa0bcf
Diffstat (limited to 'packages/SettingsLib')
5 files changed, 265 insertions, 3 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java new file mode 100755 index 0000000..fd76d81 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2011 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.BluetoothA2dpSink; +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.List; + +final class A2dpSinkProfile implements LocalBluetoothProfile { + private static final String TAG = "A2dpSinkProfile"; + private static boolean V = true; + + private BluetoothA2dpSink mService; + private boolean mIsProfileReady; + + private final LocalBluetoothAdapter mLocalAdapter; + private final CachedBluetoothDeviceManager mDeviceManager; + + static final ParcelUuid[] SRC_UUIDS = { + BluetoothUuid.AudioSource, + BluetoothUuid.AdvAudioDist, + }; + + static final String NAME = "A2DPSink"; + private final LocalBluetoothProfileManager mProfileManager; + + // Order of this profile in device profiles list + private static final int ORDINAL = 5; + + // These callbacks run on the main thread. + private final class A2dpSinkServiceListener + implements BluetoothProfile.ServiceListener { + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (V) Log.d(TAG,"Bluetooth service connected"); + mService = (BluetoothA2dpSink) proxy; + // We just bound to the service, so refresh the UI for any connected A2DP 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, "A2dpSinkProfile found new device: " + nextDevice); + device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); + } + device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED); + device.refresh(); + } + mIsProfileReady=true; + } + + public void onServiceDisconnected(int profile) { + if (V) Log.d(TAG,"Bluetooth service disconnected"); + mIsProfileReady=false; + } + } + + public boolean isProfileReady() { + return mIsProfileReady; + } + + A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter, + CachedBluetoothDeviceManager deviceManager, + LocalBluetoothProfileManager profileManager) { + mLocalAdapter = adapter; + mDeviceManager = deviceManager; + mProfileManager = profileManager; + mLocalAdapter.getProfileProxy(context, new A2dpSinkServiceListener(), + BluetoothProfile.A2DP_SINK); + } + + 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 (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; + } + } + for (BluetoothDevice src : srcs) { + mService.disconnect(src); + } + } + return mService.connect(device); + } + + public boolean disconnect(BluetoothDevice device) { + if (mService == null) return false; + // Downgrade priority as user is disconnecting the headset. + if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + 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); + } + } + + boolean isA2dpPlaying() { + if (mService == null) return false; + List<BluetoothDevice> srcs = mService.getConnectedDevices(); + if (!srcs.isEmpty()) { + if (mService.isA2dpPlaying(srcs.get(0))) { + return true; + } + } + return false; + } + + public String toString() { + return NAME; + } + + public int getOrdinal() { + return ORDINAL; + } + + public int getNameResource(BluetoothDevice device) { + // we need to have same string in UI for even SINK Media Audio. + return R.string.bluetooth_profile_a2dp; + } + + public int getSummaryResourceForDevice(BluetoothDevice device) { + int state = getConnectionStatus(device); + switch (state) { + case BluetoothProfile.STATE_DISCONNECTED: + return R.string.bluetooth_a2dp_profile_summary_use_for; + + case BluetoothProfile.STATE_CONNECTED: + return R.string.bluetooth_a2dp_profile_summary_connected; + + default: + return Utils.getConnectionStateSummary(state); + } + } + + public int getDrawableResource(BluetoothClass btClass) { + return R.drawable.ic_bt_headphones_a2dp; + } + + protected void finalize() { + if (V) Log.d(TAG, "finalize()"); + if (mService != null) { + try { + BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK, + mService); + mService = null; + }catch (Throwable t) { + Log.w(TAG, "Error cleaning up A2DP proxy", t); + } + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java index 8dec86a..0bd8dbd 100644..100755 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java @@ -112,11 +112,15 @@ public final class BluetoothDeviceFilter { if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) { return true; } + if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS)) { + return true; + } if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) { return true; } } else if (btClass != null) { if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) || + btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP_SINK) || btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { return true; } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index b0429ef..ac5a4ab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -846,7 +846,8 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe case BluetoothProfile.STATE_DISCONNECTED: if (profile.isProfileReady()) { - if (profile instanceof A2dpProfile) { + if ((profile instanceof A2dpProfile)|| + (profile instanceof A2dpSinkProfile)){ a2dpNotConnected = true; } else if (profile instanceof HeadsetProfile) { headsetNotConnected = true; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java index 0380e21..8300e0e 100644..100755 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java @@ -157,6 +157,10 @@ public final class LocalBluetoothAdapter { if (a2dp != null && a2dp.isA2dpPlaying()) { return; } + A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile(); + if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){ + return; + } } if (mAdapter.startDiscovery()) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index f018b24..6a7890f 100644..100755 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -17,6 +17,7 @@ package com.android.settingslib.bluetooth; import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothMap; @@ -75,6 +76,7 @@ public final class LocalBluetoothProfileManager { private final BluetoothEventManager mEventManager; private A2dpProfile mA2dpProfile; + private A2dpSinkProfile mA2dpSinkProfile; private HeadsetProfile mHeadsetProfile; private MapProfile mMapProfile; private final HidProfile mHidProfile; @@ -145,10 +147,10 @@ public final class LocalBluetoothProfileManager { * @param uuids */ void updateLocalProfiles(ParcelUuid[] uuids) { - // A2DP + // A2DP SRC if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) { if (mA2dpProfile == null) { - if(DEBUG) Log.d(TAG, "Adding local A2DP profile"); + if(DEBUG) Log.d(TAG, "Adding local A2DP SRC profile"); mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this); addProfile(mA2dpProfile, A2dpProfile.NAME, BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); @@ -157,6 +159,17 @@ public final class LocalBluetoothProfileManager { Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing."); } + if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) { + if (mA2dpSinkProfile == null) { + if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile"); + mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this); + addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME, + BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); + } + } else if (mA2dpSinkProfile != null) { + Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing."); + } + // Headset / Handsfree if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) { @@ -297,6 +310,10 @@ public final class LocalBluetoothProfileManager { if (profile != null) { return profile.isProfileReady(); } + profile = mA2dpSinkProfile; + if (profile != null) { + return profile.isProfileReady(); + } return false; } @@ -304,6 +321,13 @@ public final class LocalBluetoothProfileManager { return mA2dpProfile; } + A2dpSinkProfile getA2dpSinkProfile() { + if ((mA2dpSinkProfile != null)&&(mA2dpSinkProfile.isProfileReady())) + return mA2dpSinkProfile; + else + return null; + } + public HeadsetProfile getHeadsetProfile() { return mHeadsetProfile; } @@ -354,6 +378,12 @@ public final class LocalBluetoothProfileManager { removedProfiles.remove(mA2dpProfile); } + if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) && + mA2dpSinkProfile != null) { + profiles.add(mA2dpSinkProfile); + removedProfiles.remove(mA2dpSinkProfile); + } + if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) && mOppProfile != null) { profiles.add(mOppProfile); |