19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: Move this to services.jar 199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * and make the constructor package private again. 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothA2dp; 26bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice; 2896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile; 29d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport android.bluetooth.BluetoothUuid; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.IBluetoothA2dp; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.AudioManager; 36b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurentimport android.os.Handler; 37b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurentimport android.os.Message; 389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.os.ParcelUuid; 39b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurentimport android.os.PowerManager; 40b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurentimport android.os.PowerManager.WakeLock; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter; 4696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport java.util.ArrayList; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 4803cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganeshimport java.util.List; 4996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class BluetoothA2dpService extends IBluetoothA2dp.Stub { 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "BluetoothA2dpService"; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DBG = true; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String BLUETOOTH_A2DP_SERVICE = "bluetooth_a2dp"; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_ENABLED = "bluetooth_enabled"; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 62d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private static final String PROPERTY_STATE = "State"; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 64d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private final Context mContext; 65d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private final IntentFilter mIntentFilter; 66bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private HashMap<BluetoothDevice, Integer> mAudioDevices; 67d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private final AudioManager mAudioManager; 68bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private final BluetoothService mBluetoothService; 69bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private final BluetoothAdapter mAdapter; 70a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent private int mTargetA2dpState; 7196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh private BluetoothDevice mPlayingA2dpDevice; 72b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private IntentBroadcastHandler mIntentBroadcastHandler; 73b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private final WakeLock mWakeLock; 74b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 75b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private static final int MSG_CONNECTION_STATE_CHANGED = 0; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String action = intent.getAction(); 81bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly BluetoothDevice device = 82005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 83de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 84de893f550301a60274e87aa8168225e7a7a42184Nick Pelly int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 85b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly BluetoothAdapter.ERROR); 86105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (state) { 87de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 88105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project onBluetoothEnable(); 89105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 90de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_OFF: 91105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project onBluetoothDisable(); 92105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 93105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 944c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { 954c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh synchronized (this) { 964c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh if (mAudioDevices.containsKey(device)) { 974c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh int state = mAudioDevices.get(device); 984c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED); 994c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh } 1004c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh } 1014f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 1024f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1034f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh if (streamType == AudioManager.STREAM_MUSIC) { 10403cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh List<BluetoothDevice> sinks = getConnectedDevices(); 10596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 10603cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh if (sinks.size() != 0 && isPhoneDocked(sinks.get(0))) { 10703cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh String address = sinks.get(0).getAddress(); 1084f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh int newVolLevel = 1094f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 1104f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh int oldVolLevel = 1114f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh intent.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 1124f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh String path = mBluetoothService.getObjectPathFromAddress(address); 1134f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh if (newVolLevel > oldVolLevel) { 1144f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh avrcpVolumeUpNative(path); 1154f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } else if (newVolLevel < oldVolLevel) { 1164f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh avrcpVolumeDownNative(path); 1174f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1184f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1194f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1244f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh private boolean isPhoneDocked(BluetoothDevice device) { 1254f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh // This works only because these broadcast intents are "sticky" 1264f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); 1274f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh if (i != null) { 1284f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); 1294f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { 1304f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh BluetoothDevice dockDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1314f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh if (dockDevice != null && device.equals(dockDevice)) { 1324f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh return true; 1334f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1344f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1354f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1364f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh return false; 1374f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh } 1384f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh 139bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothA2dpService(Context context, BluetoothService bluetoothService) { 140d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext = context; 141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 142b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 143b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BluetoothA2dpService"); 144b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 145b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mIntentBroadcastHandler = new IntentBroadcastHandler(); 146b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 147d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 148d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 149d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mBluetoothService = bluetoothService; 150d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (mBluetoothService == null) { 151d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh throw new RuntimeException("Platform does not support Bluetooth"); 152d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 153d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 154d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!initNative()) { 155d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh throw new RuntimeException("Could not init BluetoothA2dpService"); 156d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 157d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 158f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly mAdapter = BluetoothAdapter.getDefaultAdapter(); 159bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 160de893f550301a60274e87aa8168225e7a7a42184Nick Pelly mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 161005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); 1624c9a29efdbf58034c1d90eb001dc7299f1f012eaJaikumar Ganesh mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); 1634f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh mIntentFilter.addAction(AudioManager.VOLUME_CHANGED_ACTION); 164d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.registerReceiver(mReceiver, mIntentFilter); 165d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 166bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAudioDevices = new HashMap<BluetoothDevice, Integer>(); 167d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 168d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (mBluetoothService.isEnabled()) 169d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh onBluetoothEnable(); 170a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mTargetA2dpState = -1; 1719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh mBluetoothService.setA2dpService(this); 172d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 173d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 174d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh @Override 175d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh protected void finalize() throws Throwable { 176d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh try { 177d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh cleanupNative(); 178d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } finally { 179d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh super.finalize(); 180d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 181d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 182d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby private int convertBluezSinkStringToState(String value) { 184d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value.equalsIgnoreCase("disconnected")) 185d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothA2dp.STATE_DISCONNECTED; 186d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value.equalsIgnoreCase("connecting")) 187d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothA2dp.STATE_CONNECTING; 188d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value.equalsIgnoreCase("connected")) 189d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothA2dp.STATE_CONNECTED; 190d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value.equalsIgnoreCase("playing")) 191d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothA2dp.STATE_PLAYING; 192d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return -1; 193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 194d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 195bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private boolean isSinkDevice(BluetoothDevice device) { 196dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh ParcelUuid[] uuids = mBluetoothService.getRemoteUuids(device.getAddress()); 197dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (uuids != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) { 198dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh return true; 1997f74d534f39c4d1e1db8604faa117dcf127cc8b9Jaikumar Ganesh } 2007f74d534f39c4d1e1db8604faa117dcf127cc8b9Jaikumar Ganesh return false; 2017f74d534f39c4d1e1db8604faa117dcf127cc8b9Jaikumar Ganesh } 2027f74d534f39c4d1e1db8604faa117dcf127cc8b9Jaikumar Ganesh 2038594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie private synchronized void addAudioSink(BluetoothDevice device) { 2048594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie if (mAudioDevices.get(device) == null) { 2058594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie mAudioDevices.put(device, BluetoothA2dp.STATE_DISCONNECTED); 206d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 207d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 208d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private synchronized void onBluetoothEnable() { 210a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh String devices = mBluetoothService.getProperty("Devices", true); 211d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (devices != null) { 212d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String [] paths = devices.split(","); 213d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh for (String path: paths) { 214d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String address = mBluetoothService.getAddressFromObjectPath(path); 215bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly BluetoothDevice device = mAdapter.getRemoteDevice(address); 216dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh ParcelUuid[] remoteUuids = mBluetoothService.getRemoteUuids(address); 217dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (remoteUuids != null) 218dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (BluetoothUuid.containsAnyUuid(remoteUuids, 219dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh new ParcelUuid[] {BluetoothUuid.AudioSink, 220dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh BluetoothUuid.AdvAudioDist})) { 221dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh addAudioSink(device); 222d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 223dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh } 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 225a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true"); 22680a6a229b33b0868944fe011af2d778e23c83322Eric Laurent mAudioManager.setParameters("A2dpSuspended=false"); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private synchronized void onBluetoothDisable() { 230d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!mAudioDevices.isEmpty()) { 231bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly BluetoothDevice[] devices = new BluetoothDevice[mAudioDevices.size()]; 232bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly devices = mAudioDevices.keySet().toArray(devices); 233bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly for (BluetoothDevice device : devices) { 23496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh int state = getConnectionState(device); 235d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh switch (state) { 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_CONNECTING: 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_CONNECTED: 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_PLAYING: 239bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly disconnectSinkNative(mBluetoothService.getObjectPathFromAddress( 240bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly device.getAddress())); 241bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED); 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_DISCONNECTING: 244bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTING, 245bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly BluetoothA2dp.STATE_DISCONNECTED); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 249d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mAudioDevices.clear(); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 251a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 252bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAudioManager.setParameters(BLUETOOTH_ENABLED + "=false"); 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private synchronized boolean isConnectSinkFeasible(BluetoothDevice device) { 2569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (!mBluetoothService.isEnabled() || !isSinkDevice(device) || 25796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh getPriority(device) == BluetoothA2dp.PRIORITY_OFF) { 2589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby return false; 2599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby } 2609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2618594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie addAudioSink(device); 2629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 2649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby if (path == null) { 2659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby return false; 2669a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby } 2679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby return true; 2689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 2699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 27096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public synchronized boolean isA2dpPlaying(BluetoothDevice device) { 27196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 27296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 27396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (DBG) log("isA2dpPlaying(" + device + ")"); 27496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (device.equals(mPlayingA2dpDevice)) return true; 27596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh return false; 27696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 27796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 27896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public synchronized boolean connect(BluetoothDevice device) { 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 281bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (DBG) log("connectSink(" + device + ")"); 2829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (!isConnectSinkFeasible(device)) return false; 283d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 28496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh for (BluetoothDevice sinkDevice : mAudioDevices.keySet()) { 28596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getConnectionState(sinkDevice) != BluetoothProfile.STATE_DISCONNECTED) { 28696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh disconnect(sinkDevice); 28796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 28896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 28996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 2909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return mBluetoothService.connectSink(device.getAddress()); 2919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 2929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public synchronized boolean connectSinkInternal(BluetoothDevice device) { 2944aae54cf29c562a6c59ee47732745a224fa2882dJaikumar Ganesh if (!mBluetoothService.isEnabled()) return false; 2954aae54cf29c562a6c59ee47732745a224fa2882dJaikumar Ganesh 2969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh int state = mAudioDevices.get(device); 2979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 298c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // ignore if there are any active sinks 29996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getDevicesMatchingConnectionStates(new int[] { 300c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BluetoothA2dp.STATE_CONNECTING, 301c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project BluetoothA2dp.STATE_CONNECTED, 30203cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh BluetoothA2dp.STATE_DISCONNECTING}).size() != 0) { 303b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return false; 304c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 305c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (state) { 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_CONNECTED: 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_DISCONNECTING: 309b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return false; 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_CONNECTING: 311b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return true; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 314bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 315d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 316bcf5cf47ed03f1a685fd1de8ed9dc4a6abf7b1e3Jaikumar Ganesh // State is DISCONNECTED and we are connecting. 317aa4b235dd720d1f2861681cdfabf3b5fabc61fb0Jaikumar Ganesh if (getPriority(device) < BluetoothA2dp.PRIORITY_AUTO_CONNECT) { 318aa4b235dd720d1f2861681cdfabf3b5fabc61fb0Jaikumar Ganesh setPriority(device, BluetoothA2dp.PRIORITY_AUTO_CONNECT); 319bcf5cf47ed03f1a685fd1de8ed9dc4a6abf7b1e3Jaikumar Ganesh } 320c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh handleSinkStateChange(device, state, BluetoothA2dp.STATE_CONNECTING); 321c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!connectSinkNative(path)) { 323c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh // Restore previous state 324c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh handleSinkStateChange(device, mAudioDevices.get(device), state); 325b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return false; 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 327b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return true; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private synchronized boolean isDisconnectSinkFeasible(BluetoothDevice device) { 331bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path == null) { 333b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return false; 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 335d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 33696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh int state = getConnectionState(device); 337c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh switch (state) { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_DISCONNECTED: 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothA2dp.STATE_DISCONNECTING: 34096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh return false; 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 3439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 3449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 34596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public synchronized boolean disconnect(BluetoothDevice device) { 3469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 3479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 3489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (DBG) log("disconnectSink(" + device + ")"); 3499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (!isDisconnectSinkFeasible(device)) return false; 3509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return mBluetoothService.disconnectSink(device.getAddress()); 3519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 3529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 3539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public synchronized boolean disconnectSinkInternal(BluetoothDevice device) { 35496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh int state = getConnectionState(device); 3559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3575844f1d35731b619969805957d7c3cce54431785Jaikumar Ganesh switch (state) { 3585844f1d35731b619969805957d7c3cce54431785Jaikumar Ganesh case BluetoothA2dp.STATE_DISCONNECTED: 3595844f1d35731b619969805957d7c3cce54431785Jaikumar Ganesh case BluetoothA2dp.STATE_DISCONNECTING: 3605844f1d35731b619969805957d7c3cce54431785Jaikumar Ganesh return false; 3615844f1d35731b619969805957d7c3cce54431785Jaikumar Ganesh } 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // State is CONNECTING or CONNECTED or PLAYING 363c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTING); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!disconnectSinkNative(path)) { 365c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh // Restore previous state 366c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh handleSinkStateChange(device, mAudioDevices.get(device), state); 367b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return false; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 369c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh return true; 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 372f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan public synchronized boolean suspendSink(BluetoothDevice device) { 373f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 374f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan "Need BLUETOOTH_ADMIN permission"); 375a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent if (DBG) log("suspendSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); 376f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan if (device == null || mAudioDevices == null) { 377f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan return false; 378f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan } 379f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 38062895a67d2c34fc2a4b8943e330c4269275b1c20Nick Pelly Integer state = mAudioDevices.get(device); 38162895a67d2c34fc2a4b8943e330c4269275b1c20Nick Pelly if (path == null || state == null) { 382f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan return false; 383f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan } 384a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent 385a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mTargetA2dpState = BluetoothA2dp.STATE_CONNECTED; 386a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent return checkSinkSuspendState(state.intValue()); 387f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan } 388f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan 389f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan public synchronized boolean resumeSink(BluetoothDevice device) { 390f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 391f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan "Need BLUETOOTH_ADMIN permission"); 392a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent if (DBG) log("resumeSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState); 393f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan if (device == null || mAudioDevices == null) { 394f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan return false; 395f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan } 396f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); 39762895a67d2c34fc2a4b8943e330c4269275b1c20Nick Pelly Integer state = mAudioDevices.get(device); 39862895a67d2c34fc2a4b8943e330c4269275b1c20Nick Pelly if (path == null || state == null) { 399f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan return false; 400f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan } 401a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mTargetA2dpState = BluetoothA2dp.STATE_PLAYING; 402a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent return checkSinkSuspendState(state.intValue()); 403f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan } 404f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan 40596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public synchronized int getConnectionState(BluetoothDevice device) { 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 40796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh Integer state = mAudioDevices.get(device); 40896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (state == null) 40996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh return BluetoothA2dp.STATE_DISCONNECTED; 41096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh return state; 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 41303cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh public synchronized List<BluetoothDevice> getConnectedDevices() { 414b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 41503cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh List<BluetoothDevice> sinks = getDevicesMatchingConnectionStates( 41696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh new int[] {BluetoothA2dp.STATE_CONNECTED}); 41796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh return sinks; 418b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh } 419b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3Jaikumar Ganesh 42003cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh public synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 42203cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh ArrayList<BluetoothDevice> sinks = new ArrayList<BluetoothDevice>(); 42396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh for (BluetoothDevice device: mAudioDevices.keySet()) { 42496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh int sinkState = getConnectionState(device); 42596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh for (int state : states) { 42696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (state == sinkState) { 42796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh sinks.add(device); 42896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh break; 42996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 43096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 43196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 43203cd78cf5e51c3adb78d2e3d314838dcf3e36b26Jaikumar Ganesh return sinks; 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 43596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public synchronized int getPriority(BluetoothDevice device) { 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Settings.Secure.getInt(mContext.getContentResolver(), 438bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), 439ccaebfc9428aa7c167caf469f7393e1fb375307eJaikumar Ganesh BluetoothA2dp.PRIORITY_UNDEFINED); 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 44296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public synchronized boolean setPriority(BluetoothDevice device, int priority) { 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Settings.Secure.putInt(mContext.getContentResolver(), 446b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 449a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie public synchronized boolean allowIncomingConnect(BluetoothDevice device, boolean value) { 450a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 451a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie "Need BLUETOOTH_ADMIN permission"); 452a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie String address = device.getAddress(); 453a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie if (!BluetoothAdapter.checkBluetoothAddress(address)) { 454a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie return false; 455a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie } 456a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie Integer data = mBluetoothService.getAuthorizationAgentRequestData(address); 457a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie if (data == null) { 458a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie Log.w(TAG, "allowIncomingConnect(" + device + ") called but no native data available"); 459a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie return false; 460a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie } 461a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie log("allowIncomingConnect: A2DP: " + device + ":" + value); 462a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie return mBluetoothService.setAuthorizationNative(address, value, data.intValue()); 463a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie } 464a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie 4659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby /** 4669a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * Called by native code on a PropertyChanged signal from 4679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * org.bluez.AudioSink. 4689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * 4699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * @param path the object path for the changed device 4709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * @param propValues a string array containing the key and one or more 4719a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * values. 4729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby */ 4739a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby private synchronized void onSinkPropertyChanged(String path, String[] propValues) { 4749488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh if (!mBluetoothService.isEnabled()) { 4759488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh return; 4769488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 4779488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 478d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String name = propValues[0]; 479d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String address = mBluetoothService.getAddressFromObjectPath(path); 480d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (address == null) { 481d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "onSinkPropertyChanged: Address of the remote device in null"); 482d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 485bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly BluetoothDevice device = mAdapter.getRemoteDevice(address); 486bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 487d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (name.equals(PROPERTY_STATE)) { 4889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby int state = convertBluezSinkStringToState(propValues[1]); 4898febf8861857b284721ffe6caaedbd495a87e73fJaikumar Ganesh log("A2DP: onSinkPropertyChanged newState is: " + state + "mPlayingA2dpDevice: " + mPlayingA2dpDevice); 4908febf8861857b284721ffe6caaedbd495a87e73fJaikumar Ganesh 491bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (mAudioDevices.get(device) == null) { 4929488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh // This is for an incoming connection for a device not known to us. 4939488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh // We have authorized it and bluez state has changed. 494bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly addAudioSink(device); 4958594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state); 4969488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } else { 49796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (state == BluetoothA2dp.STATE_PLAYING && mPlayingA2dpDevice == null) { 49896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mPlayingA2dpDevice = device; 49996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh handleSinkPlayingStateChange(device, state, BluetoothA2dp.STATE_NOT_PLAYING); 50096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } else if (state == BluetoothA2dp.STATE_CONNECTED && mPlayingA2dpDevice != null) { 50196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mPlayingA2dpDevice = null; 50296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh handleSinkPlayingStateChange(device, BluetoothA2dp.STATE_NOT_PLAYING, 50396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh BluetoothA2dp.STATE_PLAYING); 50496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } else { 505b2ec4fa8d7ee957ddb2c85ce2ed74fdaafe144e9Jaikumar Ganesh mPlayingA2dpDevice = null; 50696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh int prevState = mAudioDevices.get(device); 50796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh handleSinkStateChange(device, prevState, state); 50896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 5099488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 510a0de355ce04eb29356ba6f171dcf093a271f221cMike Lockwood } 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 513bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) { 514d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (state != prevState) { 515bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAudioDevices.put(device, state); 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 517a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent checkSinkSuspendState(state); 518a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mTargetA2dpState = -1; 519a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent 52096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getPriority(device) > BluetoothA2dp.PRIORITY_OFF && 521721361f1a74b876c42cc0533c9c19320e8c09927Jaikumar Ganesh state == BluetoothA2dp.STATE_CONNECTED) { 522721361f1a74b876c42cc0533c9c19320e8c09927Jaikumar Ganesh // We have connected or attempting to connect. 523721361f1a74b876c42cc0533c9c19320e8c09927Jaikumar Ganesh // Bump priority 52496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh setPriority(device, BluetoothA2dp.PRIORITY_AUTO_CONNECT); 5259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh // We will only have 1 device with AUTO_CONNECT priority 5269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh // To be backward compatible set everyone else to have PRIORITY_ON 5279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh adjustOtherSinkPriorities(device); 5289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 5299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 530b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = mAudioManager.setBluetoothA2dpDeviceConnectionState(device, state); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 532b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mWakeLock.acquire(); 533b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mIntentBroadcastHandler.sendMessageDelayed(mIntentBroadcastHandler.obtainMessage( 534b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_CONNECTION_STATE_CHANGED, 535b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent prevState, 536b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 537b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent device), 538b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 54296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh private void handleSinkPlayingStateChange(BluetoothDevice device, int state, int prevState) { 54396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED); 54496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 54596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 54696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh intent.putExtra(BluetoothProfile.EXTRA_STATE, state); 54724ca01d262f0e8563b09b3c7b4574a2bb8036f12Jake Hamby intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 54896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mContext.sendBroadcast(intent, BLUETOOTH_PERM); 54996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 55096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (DBG) log("A2DP Playing state : device: " + device + " State:" + prevState + "->" + state); 55196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 55296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 5539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private void adjustOtherSinkPriorities(BluetoothDevice connectedDevice) { 554bcf5cf47ed03f1a685fd1de8ed9dc4a6abf7b1e3Jaikumar Ganesh for (BluetoothDevice device : mAdapter.getBondedDevices()) { 555aa4b235dd720d1f2861681cdfabf3b5fabc61fb0Jaikumar Ganesh if (getPriority(device) >= BluetoothA2dp.PRIORITY_AUTO_CONNECT && 556bcf5cf47ed03f1a685fd1de8ed9dc4a6abf7b1e3Jaikumar Ganesh !device.equals(connectedDevice)) { 557aa4b235dd720d1f2861681cdfabf3b5fabc61fb0Jaikumar Ganesh setPriority(device, BluetoothA2dp.PRIORITY_ON); 5589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 5599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 5609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 5619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 562a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent private boolean checkSinkSuspendState(int state) { 563a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent boolean result = true; 564a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent 565a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent if (state != mTargetA2dpState) { 566a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent if (state == BluetoothA2dp.STATE_PLAYING && 567a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mTargetA2dpState == BluetoothA2dp.STATE_CONNECTED) { 568a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mAudioManager.setParameters("A2dpSuspended=true"); 569a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent } else if (state == BluetoothA2dp.STATE_CONNECTED && 570a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mTargetA2dpState == BluetoothA2dp.STATE_PLAYING) { 571a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent mAudioManager.setParameters("A2dpSuspended=false"); 572a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent } else { 573a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent result = false; 574a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent } 575a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent } 576a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent return result; 577a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent } 578a47d153647d8750b667942ad80e7b905ea98c68bEric Laurent 5799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby /** 5809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * Called by native code for the async response to a Connect 5819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * method call to org.bluez.AudioSink. 5829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * 5839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * @param deviceObjectPath the object path for the connecting device 5849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby * @param result true on success; false on error 5859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby */ 586c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh private void onConnectSinkResult(String deviceObjectPath, boolean result) { 587c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh // If the call was a success, ignore we will update the state 588c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh // when we a Sink Property Change 589c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh if (!result) { 590c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh if (deviceObjectPath != null) { 591c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); 592c0cec6245429ef1c9617a710fe08b2999b329d08Jaikumar Ganesh if (address == null) return; 593c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh BluetoothDevice device = mAdapter.getRemoteDevice(address); 59496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh int state = getConnectionState(device); 595c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED); 596c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh } 597c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh } 598c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh } 599c0e32f12439e5373dca5879e4eb7e819be7fb417Jaikumar Ganesh 600b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent /** Handles A2DP connection state change intent broadcasts. */ 601b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private class IntentBroadcastHandler extends Handler { 602b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 603b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void onConnectionStateChanged(BluetoothDevice device, int prevState, int state) { 604b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 605b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 606b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 607b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra(BluetoothProfile.EXTRA_STATE, state); 608b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 609b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mContext.sendBroadcast(intent, BLUETOOTH_PERM); 610b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 611b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state); 612b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 613b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.A2DP, state, 614b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent prevState); 615b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 616b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 617b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent @Override 618b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent public void handleMessage(Message msg) { 619b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent switch (msg.what) { 620b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent case MSG_CONNECTION_STATE_CHANGED: 621b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent onConnectionStateChanged((BluetoothDevice) msg.obj, msg.arg1, msg.arg2); 622b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mWakeLock.release(); 623b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent break; 624b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 625b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 626b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 627b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 630eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 631eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey 632d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (mAudioDevices.isEmpty()) return; 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pw.println("Cached audio devices:"); 634bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly for (BluetoothDevice device : mAudioDevices.keySet()) { 635bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly int state = mAudioDevices.get(device); 636bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly pw.println(device + " " + BluetoothA2dp.stateToString(state)); 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void log(String msg) { 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native boolean initNative(); 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void cleanupNative(); 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private synchronized native boolean connectSinkNative(String path); 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private synchronized native boolean disconnectSinkNative(String path); 648f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan private synchronized native boolean suspendSinkNative(String path); 649f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57Zhu Lan private synchronized native boolean resumeSinkNative(String path); 650d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private synchronized native Object []getSinkPropertiesNative(String path); 6514f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh private synchronized native boolean avrcpVolumeUpNative(String path); 6524f773a13043ec22ccd2f9d33ee86a305738c5b23Jaikumar Ganesh private synchronized native boolean avrcpVolumeDownNative(String path); 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 654