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 41436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby static final ParcelUuid[] SINK_UUIDS = { 42436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothUuid.AudioSink, 43436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothUuid.AdvAudioDist, 44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby }; 45436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 46436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby static final String NAME = "A2DP"; 472ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji private final LocalBluetoothProfileManager mProfileManager; 48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 49436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Order of this profile in device profiles list 50436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static final int ORDINAL = 1; 51436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 52436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // These callbacks run on the main thread. 53436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final class A2dpServiceListener 54436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby implements BluetoothProfile.ServiceListener { 55436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 56436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onServiceConnected(int profile, BluetoothProfile proxy) { 57afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (V) Log.d(TAG,"Bluetooth service connected"); 58436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService = (BluetoothA2dp) proxy; 59654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mIsProfileReady=true; 60436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 61436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 62436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onServiceDisconnected(int profile) { 63654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG,"Bluetooth service disconnected"); 64654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mIsProfileReady=false; 65436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 66436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 67436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 68654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc public boolean isProfileReady() { 69654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc return mIsProfileReady; 70654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 712ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji A2dpProfile(Context context, LocalBluetoothProfileManager profileManager) { 722ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji mProfileManager = profileManager; 73436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 74436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby adapter.getProfileProxy(context, new A2dpServiceListener(), 75436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.A2DP); 76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 77436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 78436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isConnectable() { 79436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 80436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 81436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 82436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isAutoConnectable() { 83436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 84436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 85436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 8600ec05985d6715daab7b15f105f0a9f3ada2ab83Swaminatha Balaji public List<BluetoothDevice> getConnectedDevices() { 87afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return new ArrayList<BluetoothDevice>(0); 88436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getDevicesMatchingConnectionStates( 89436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby new int[] {BluetoothProfile.STATE_CONNECTED, 90436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.STATE_CONNECTING, 91436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothProfile.STATE_DISCONNECTING}); 92436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 93436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 94436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean connect(BluetoothDevice device) { 95afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby List<BluetoothDevice> sinks = getConnectedDevices(); 97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (sinks != null) { 98436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothDevice sink : sinks) { 99436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.disconnect(sink); 100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 101436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 102436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.connect(device); 103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 105436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean disconnect(BluetoothDevice device) { 106afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 1070654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta // Downgrade priority as user is disconnecting the headset. 1080654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ 1090654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 1102ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji } 1110654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta return mService.disconnect(device); 1122ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji } 1132ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji 114436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getConnectionStatus(BluetoothDevice device) { 115afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) { 116afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc return BluetoothProfile.STATE_DISCONNECTED; 117afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc } 118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getConnectionState(device); 119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public boolean isPreferred(BluetoothDevice device) { 122afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; 124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getPreferred(BluetoothDevice device) { 127afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return BluetoothProfile.PRIORITY_OFF; 128436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mService.getPriority(device); 129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void setPreferred(BluetoothDevice device, boolean preferred) { 132afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return; 133436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (preferred) { 134436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { 135436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.setPriority(device, BluetoothProfile.PRIORITY_ON); 136436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 137436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else { 138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); 139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby boolean isA2dpPlaying() { 142afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc if (mService == null) return false; 143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby List<BluetoothDevice> sinks = mService.getConnectedDevices(); 144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (!sinks.isEmpty()) { 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mService.isA2dpPlaying(sinks.get(0))) { 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return true; 147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return false; 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 151436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 152436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public String toString() { 153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return NAME; 154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getOrdinal() { 157436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return ORDINAL; 158436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 16079be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby public int getNameResource(BluetoothDevice device) { 161436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_profile_a2dp; 162436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 163436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 164436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getSummaryResourceForDevice(BluetoothDevice device) { 165afedeacd575d51edc4f741bd2c8f75dd4928f2b6fredc int state = getConnectionStatus(device); 166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby switch (state) { 167436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothProfile.STATE_DISCONNECTED: 168436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_a2dp_profile_summary_use_for; 169c78d71e16c4413180f79182c8e246d70928c2442Kausik Sinnaswamy 170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothProfile.STATE_CONNECTED: 171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.string.bluetooth_a2dp_profile_summary_connected; 172c78d71e16c4413180f79182c8e246d70928c2442Kausik Sinnaswamy 173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby default: 174436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return Utils.getConnectionStateSummary(state); 175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public int getDrawableResource(BluetoothClass btClass) { 179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return R.drawable.ic_bt_headphones_a2dp; 180436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 181654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc 182654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc protected void finalize() { 183654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (V) Log.d(TAG, "finalize()"); 184654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc if (mService != null) { 185654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc try { 186b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP, 187b5f144af8ecc1c2f2e45f8a7d936f4ab368fdd97Matthew Xie mService); 188654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc mService = null; 189654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc }catch (Throwable t) { 190654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc Log.w(TAG, "Error cleaning up A2DP proxy", t); 191654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 192654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 193654a3ab77dac5acaf6e100c518ba322cc1edb3c0fredc } 194436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby} 195