1436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby/* 2436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Copyright (C) 2011 The Android Open Source Project 3436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 4436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Licensed under the Apache License, Version 2.0 (the "License"); 5436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * you may not use this file except in compliance with the License. 6436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * You may obtain a copy of the License at 7436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 8436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * http://www.apache.org/licenses/LICENSE-2.0 9436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 10436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Unless required by applicable law or agreed to in writing, software 11436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * distributed under the License is distributed on an "AS IS" BASIS, 12436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * See the License for the specific language governing permissions and 14436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * limitations under the License. 15436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 16436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 17436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambypackage com.android.settings.bluetooth; 18436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 19436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothA2dp; 20436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothAdapter; 21436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothClass; 22436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothDevice; 23436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothProfile; 24436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothUuid; 25436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Context; 26436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.os.ParcelUuid; 27654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredcimport android.util.Log; 28436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 29436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport com.android.settings.R; 30436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 31afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredcimport java.util.ArrayList; 32436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.List; 33436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 34436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyfinal class A2dpProfile implements LocalBluetoothProfile { 35654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc private static final String TAG = "A2dpProfile"; 36654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc private static boolean V = true; 37654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc 38436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private BluetoothA2dp mService; 39654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc private boolean mIsProfileReady; 40436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 4118c4317b93fce47109017efdab089dec4b01f790Jake Hamby private final LocalBluetoothAdapter mLocalAdapter; 4218c4317b93fce47109017efdab089dec4b01f790Jake Hamby private final CachedBluetoothDeviceManager mDeviceManager; 4318c4317b93fce47109017efdab089dec4b01f790Jake Hamby 44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby static final ParcelUuid[] SINK_UUIDS = { 45436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothUuid.AudioSink, 46436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothUuid.AdvAudioDist, 47436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby }; 48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 49436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby static final String NAME = "A2DP"; 502ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji private final LocalBluetoothProfileManager mProfileManager; 51436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 52436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Order of this profile in device profiles list 53436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static final int ORDINAL = 1; 54436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 55436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // These callbacks run on the main thread. 56436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final class A2dpServiceListener 57436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby implements BluetoothProfile.ServiceListener { 58436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 59436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onServiceConnected(int profile, BluetoothProfile proxy) { 60afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (V) Log.d(TAG,"Bluetooth service connected"); 61436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService = (BluetoothA2dp) proxy; 6218c4317b93fce47109017efdab089dec4b01f790Jake Hamby // We just bound to the service, so refresh the UI for any connected A2DP devices. 6318c4317b93fce47109017efdab089dec4b01f790Jake Hamby List<BluetoothDevice> deviceList = mService.getConnectedDevices(); 6418c4317b93fce47109017efdab089dec4b01f790Jake Hamby while (!deviceList.isEmpty()) { 6518c4317b93fce47109017efdab089dec4b01f790Jake Hamby BluetoothDevice nextDevice = deviceList.remove(0); 6618c4317b93fce47109017efdab089dec4b01f790Jake Hamby CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); 6718c4317b93fce47109017efdab089dec4b01f790Jake Hamby // we may add a new device here, but generally this should not happen 6818c4317b93fce47109017efdab089dec4b01f790Jake Hamby if (device == null) { 6918c4317b93fce47109017efdab089dec4b01f790Jake Hamby Log.w(TAG, "A2dpProfile found new device: " + nextDevice); 7018c4317b93fce47109017efdab089dec4b01f790Jake Hamby device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); 7118c4317b93fce47109017efdab089dec4b01f790Jake Hamby } 7218c4317b93fce47109017efdab089dec4b01f790Jake Hamby device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED); 7318c4317b93fce47109017efdab089dec4b01f790Jake Hamby device.refresh(); 7418c4317b93fce47109017efdab089dec4b01f790Jake Hamby } 75654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mIsProfileReady=true; 76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 77436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 78436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onServiceDisconnected(int profile) { 79654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG,"Bluetooth service disconnected"); 80654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mIsProfileReady=false; 81436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 82436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 83436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 84654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc public boolean isProfileReady() { 85654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc return mIsProfileReady; 86654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 8718c4317b93fce47109017efdab089dec4b01f790Jake Hamby 8818c4317b93fce47109017efdab089dec4b01f790Jake Hamby A2dpProfile(Context context, LocalBluetoothAdapter adapter, 8918c4317b93fce47109017efdab089dec4b01f790Jake Hamby CachedBluetoothDeviceManager deviceManager, 9018c4317b93fce47109017efdab089dec4b01f790Jake Hamby LocalBluetoothProfileManager profileManager) { 9118c4317b93fce47109017efdab089dec4b01f790Jake Hamby mLocalAdapter = adapter; 9218c4317b93fce47109017efdab089dec4b01f790Jake Hamby mDeviceManager = deviceManager; 932ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji mProfileManager = profileManager; 9418c4317b93fce47109017efdab089dec4b01f790Jake Hamby mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(), 95436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.A2DP); 96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 98436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isConnectable() { 99436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 101436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 102436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isAutoConnectable() { 103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 105436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 10600ec05985d6715daab7b15f105f0a9f3ada2ab83Swaminatha Balaji public List<BluetoothDevice> getConnectedDevices() { 107afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return new ArrayList<BluetoothDevice>(0); 108436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getDevicesMatchingConnectionStates( 109436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby new int[] {BluetoothProfile.STATE_CONNECTED, 110436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.STATE_CONNECTING, 111436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.STATE_DISCONNECTING}); 112436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 113436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 114436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean connect(BluetoothDevice device) { 115afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 116436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby List<BluetoothDevice> sinks = getConnectedDevices(); 117436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (sinks != null) { 118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothDevice sink : sinks) { 119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.disconnect(sink); 120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 122436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.connect(device); 123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean disconnect(BluetoothDevice device) { 126afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 1270654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta // Downgrade priority as user is disconnecting the headset. 1280654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ 1290654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 1302ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji } 1310654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta return mService.disconnect(device); 1322ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji } 1332ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji 134436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getConnectionStatus(BluetoothDevice device) { 135afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) { 136afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc return BluetoothProfile.STATE_DISCONNECTED; 137afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc } 138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getConnectionState(device); 139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isPreferred(BluetoothDevice device) { 142afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getPreferred(BluetoothDevice device) { 147afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return BluetoothProfile.PRIORITY_OFF; 148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getPriority(device); 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 151436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void setPreferred(BluetoothDevice device, boolean preferred) { 152afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return; 153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (preferred) { 154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 157436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else { 158436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 160436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 161436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby boolean isA2dpPlaying() { 162afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 163436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby List<BluetoothDevice> sinks = mService.getConnectedDevices(); 164436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (!sinks.isEmpty()) { 165436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mService.isA2dpPlaying(sinks.get(0))) { 166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 167436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 168436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 169436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return false; 170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public String toString() { 173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return NAME; 174436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getOrdinal() { 177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return ORDINAL; 178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 18079be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby public int getNameResource(BluetoothDevice device) { 181436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_profile_a2dp; 182436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 183436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 184436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getSummaryResourceForDevice(BluetoothDevice device) { 185afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc int state = getConnectionStatus(device); 186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby switch (state) { 187436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothProfile.STATE_DISCONNECTED: 188436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_a2dp_profile_summary_use_for; 189c78d71e16c4413180f79182c8e246d70928c2442Kausik Sinnaswamy 190436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothProfile.STATE_CONNECTED: 191436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_a2dp_profile_summary_connected; 192c78d71e16c4413180f79182c8e246d70928c2442Kausik Sinnaswamy 193436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby default: 194436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return Utils.getConnectionStateSummary(state); 195436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 196436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 197436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 198436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getDrawableResource(BluetoothClass btClass) { 199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.drawable.ic_bt_headphones_a2dp; 200436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 201654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc 202654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc protected void finalize() { 203654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG, "finalize()"); 204654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (mService != null) { 205654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc try { 206b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP, 207b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie mService); 208654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mService = null; 209654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc }catch (Throwable t) { 210654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc Log.w(TAG, "Error cleaning up A2DP proxy", t); 211654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 212654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 213654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 214436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby} 215