BluetoothA2dpSink.java revision 2263dd1ddd1a8ac828c25d34000c85165cad21ef
12263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood/* 22263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Copyright (C) 2014 The Android Open Source Project 32263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 42263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 52263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * you may not use this file except in compliance with the License. 62263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * You may obtain a copy of the License at 72263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 82263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 92263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 102263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Unless required by applicable law or agreed to in writing, software 112263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 122263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * See the License for the specific language governing permissions and 142263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * limitations under the License. 152263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 162263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 172263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodpackage android.bluetooth; 182263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 192263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.content.ComponentName; 202263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.content.Context; 212263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.content.Intent; 222263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.content.ServiceConnection; 232263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.os.IBinder; 242263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.os.RemoteException; 252263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport android.util.Log; 262263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 272263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport java.util.ArrayList; 282263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodimport java.util.List; 292263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 302263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood/** 312263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * This class provides the public APIs to control the Bluetooth A2DP Sink 322263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * profile. 332263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 342263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood *<p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink 352263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get 362263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * the BluetoothA2dpSink proxy object. 372263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 382263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @hide 392263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 402263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwoodpublic final class BluetoothA2dpSink implements BluetoothProfile { 412263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private static final String TAG = "BluetoothA2dpSink"; 422263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private static final boolean DBG = true; 432263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private static final boolean VDBG = false; 442263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 452263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 462263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Intent used to broadcast the change in connection state of the A2DP Sink 472263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * profile. 482263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 492263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>This intent will have 3 extras: 502263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <ul> 512263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> 522263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> 532263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> 542263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * </ul> 552263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 562263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of 572263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, 582263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. 592263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 602263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to 612263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * receive. 622263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 632263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static final String ACTION_CONNECTION_STATE_CHANGED = 642263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED"; 652263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 662263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 672263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Intent used to broadcast the change in the Playing state of the A2DP Sink 682263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * profile. 692263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 702263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>This intent will have 3 extras: 712263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <ul> 722263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> 732263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li> 742263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> 752263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * </ul> 762263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 772263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of 782263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING}, 792263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 802263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to 812263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * receive. 822263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 832263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static final String ACTION_PLAYING_STATE_CHANGED = 842263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED"; 852263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 862263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 872263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * A2DP sink device is streaming music. This state can be one of 882263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of 892263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #ACTION_PLAYING_STATE_CHANGED} intent. 902263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 912263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static final int STATE_PLAYING = 10; 922263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 932263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 942263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * A2DP sink device is NOT streaming music. This state can be one of 952263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of 962263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #ACTION_PLAYING_STATE_CHANGED} intent. 972263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 982263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static final int STATE_NOT_PLAYING = 11; 992263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1002263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 1012263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Intent used to broadcast the change in the Playing state of the A2DP Sink 1022263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * profile. 1032263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 1042263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>This intent will have 3 extras: 1052263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <ul> 1062263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li> 1072263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> 1082263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * </ul> 1092263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 1102263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to 1112263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * receive. 1122263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 1132263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static final String ACTION_AUDIO_CONFIG_CHANGED = 1142263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED"; 1152263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1162263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 1172263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent. 1182263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 1192263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * This extra represents the current audio configuration of the A2DP source device. 1202263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@see BluetoothAudioConfig} 1212263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 1222263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static final String EXTRA_AUDIO_CONFIG 1232263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood = "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG"; 1242263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1252263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private Context mContext; 1262263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private ServiceListener mServiceListener; 1272263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private IBluetoothA2dpSink mService; 1282263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private BluetoothAdapter mAdapter; 1292263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1302263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = 1312263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood new IBluetoothStateChangeCallback.Stub() { 1322263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public void onBluetoothStateChange(boolean up) { 1332263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); 1342263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (!up) { 1352263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (VDBG) Log.d(TAG,"Unbinding service..."); 1362263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood synchronized (mConnection) { 1372263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 1382263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mService = null; 1392263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mContext.unbindService(mConnection); 1402263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (Exception re) { 1412263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG,"",re); 1422263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1432263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1442263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } else { 1452263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood synchronized (mConnection) { 1462263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 1472263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) { 1482263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (VDBG) Log.d(TAG,"Binding service..."); 1492263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood doBind(); 1502263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1512263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (Exception re) { 1522263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG,"",re); 1532263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1542263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1552263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1562263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1572263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood }; 1582263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 1592263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Create a BluetoothA2dp proxy object for interacting with the local 1602263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Bluetooth A2DP service. 1612263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 1622263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 1632263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /*package*/ BluetoothA2dpSink(Context context, ServiceListener l) { 1642263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mContext = context; 1652263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mServiceListener = l; 1662263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mAdapter = BluetoothAdapter.getDefaultAdapter(); 1672263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood IBluetoothManager mgr = mAdapter.getBluetoothManager(); 1682263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mgr != null) { 1692263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 1702263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); 1712263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 1722263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG,"",e); 1732263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1742263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1752263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1762263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood doBind(); 1772263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1782263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1792263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood boolean doBind() { 1802263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Intent intent = new Intent(IBluetoothA2dpSink.class.getName()); 1812263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 1822263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood intent.setComponent(comp); 1832263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, 1842263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood android.os.Process.myUserHandle())) { 1852263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent); 1862263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 1872263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1882263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return true; 1892263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 1902263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 1912263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /*package*/ void close() { 1922263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mServiceListener = null; 1932263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood IBluetoothManager mgr = mAdapter.getBluetoothManager(); 1942263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mgr != null) { 1952263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 1962263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); 1972263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (Exception e) { 1982263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG,"",e); 1992263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2002263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2012263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 2022263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood synchronized (mConnection) { 2032263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null) { 2042263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 2052263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mService = null; 2062263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mContext.unbindService(mConnection); 2072263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (Exception re) { 2082263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG,"",re); 2092263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2102263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2112263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2122263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2132263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 2142263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public void finalize() { 2152263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood close(); 2162263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2172263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 2182263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Initiate connection to a profile of the remote bluetooth device. 2192263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2202263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p> Currently, the system supports only 1 connection to the 2212263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * A2DP profile. The API will automatically disconnect connected 2222263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * devices before connecting. 2232263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2242263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p> This API returns false in scenarios like the profile on the 2252263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * device is already connected or Bluetooth is not turned on. 2262263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * When this API returns true, it is guaranteed that 2272263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * connection state intent for the profile will be broadcasted with 2282263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * the state. Users can get the connection state of the profile 2292263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * from this intent. 2302263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2312263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 2322263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * permission. 2332263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2342263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @param device Remote Bluetooth Device 2352263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @return false on immediate error, 2362263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * true otherwise 2372263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @hide 2382263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 2392263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public boolean connect(BluetoothDevice device) { 2402263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (DBG) log("connect(" + device + ")"); 2412263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null && isEnabled() && 2422263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood isValidDevice(device)) { 2432263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 2442263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return mService.connect(device); 2452263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 2462263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 2472263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 2482263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2492263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2502263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) Log.w(TAG, "Proxy not attached to service"); 2512263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 2522263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2532263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 2542263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 2552263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Initiate disconnection from a profile 2562263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2572263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p> This API will return false in scenarios like the profile on the 2582263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Bluetooth device is not in connected state etc. When this API returns, 2592263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * true, it is guaranteed that the connection state change 2602263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * intent will be broadcasted with the state. Users can get the 2612263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * disconnection state of the profile from this intent. 2622263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2632263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p> If the disconnection is initiated by a remote device, the state 2642263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * will transition from {@link #STATE_CONNECTED} to 2652263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the 2662263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * host (local) device the state will transition from 2672263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to 2682263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * state {@link #STATE_DISCONNECTED}. The transition to 2692263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@link #STATE_DISCONNECTING} can be used to distinguish between the 2702263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * two scenarios. 2712263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2722263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 2732263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * permission. 2742263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 2752263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @param device Remote Bluetooth Device 2762263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @return false on immediate error, 2772263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * true otherwise 2782263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @hide 2792263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 2802263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public boolean disconnect(BluetoothDevice device) { 2812263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (DBG) log("disconnect(" + device + ")"); 2822263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null && isEnabled() && 2832263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood isValidDevice(device)) { 2842263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 2852263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return mService.disconnect(device); 2862263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 2872263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 2882263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 2892263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2902263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2912263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) Log.w(TAG, "Proxy not attached to service"); 2922263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 2932263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 2942263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 2952263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 2962263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@inheritDoc} 2972263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 2982263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public List<BluetoothDevice> getConnectedDevices() { 2992263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (VDBG) log("getConnectedDevices()"); 3002263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null && isEnabled()) { 3012263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 3022263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return mService.getConnectedDevices(); 3032263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 3042263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 3052263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return new ArrayList<BluetoothDevice>(); 3062263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3072263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3082263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) Log.w(TAG, "Proxy not attached to service"); 3092263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return new ArrayList<BluetoothDevice>(); 3102263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3112263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 3122263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 3132263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@inheritDoc} 3142263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 3152263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 3162263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (VDBG) log("getDevicesMatchingStates()"); 3172263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null && isEnabled()) { 3182263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 3192263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return mService.getDevicesMatchingConnectionStates(states); 3202263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 3212263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 3222263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return new ArrayList<BluetoothDevice>(); 3232263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3242263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3252263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) Log.w(TAG, "Proxy not attached to service"); 3262263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return new ArrayList<BluetoothDevice>(); 3272263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3282263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 3292263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 3302263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@inheritDoc} 3312263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 3322263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public int getConnectionState(BluetoothDevice device) { 3332263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (VDBG) log("getState(" + device + ")"); 3342263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null && isEnabled() 3352263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood && isValidDevice(device)) { 3362263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 3372263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return mService.getConnectionState(device); 3382263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 3392263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 3402263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return BluetoothProfile.STATE_DISCONNECTED; 3412263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3422263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3432263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) Log.w(TAG, "Proxy not attached to service"); 3442263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return BluetoothProfile.STATE_DISCONNECTED; 3452263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3462263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 3472263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 3482263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Get the current audio configuration for the A2DP source device, 3492263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * or null if the device has no audio configuration 3502263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 3512263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 3522263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 3532263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @param device Remote bluetooth device. 3542263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @return audio configuration for the device, or null 3552263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 3562263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * {@see BluetoothAudioConfig} 3572263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 3582263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { 3592263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (VDBG) log("getAudioConfig(" + device + ")"); 3602263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService != null && isEnabled() 3612263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood && isValidDevice(device)) { 3622263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood try { 3632263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return mService.getAudioConfig(device); 3642263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } catch (RemoteException e) { 3652263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 3662263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return null; 3672263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3682263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3692263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mService == null) Log.w(TAG, "Proxy not attached to service"); 3702263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return null; 3712263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3722263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 3732263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood /** 3742263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * Helper for converting a state to a string. 3752263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * 3762263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * For debug use only - strings are not internationalized. 3772263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood * @hide 3782263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood */ 3792263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public static String stateToString(int state) { 3802263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood switch (state) { 3812263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood case STATE_DISCONNECTED: 3822263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "disconnected"; 3832263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood case STATE_CONNECTING: 3842263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "connecting"; 3852263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood case STATE_CONNECTED: 3862263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "connected"; 3872263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood case STATE_DISCONNECTING: 3882263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "disconnecting"; 3892263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood case STATE_PLAYING: 3902263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "playing"; 3912263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood case STATE_NOT_PLAYING: 3922263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "not playing"; 3932263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood default: 3942263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return "<unknown state " + state + ">"; 3952263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3962263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 3972263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 3982263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private final ServiceConnection mConnection = new ServiceConnection() { 3992263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public void onServiceConnected(ComponentName className, IBinder service) { 4002263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (DBG) Log.d(TAG, "Proxy object connected"); 4012263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mService = IBluetoothA2dpSink.Stub.asInterface(service); 4022263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 4032263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mServiceListener != null) { 4042263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK, 4052263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood BluetoothA2dpSink.this); 4062263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4072263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4082263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood public void onServiceDisconnected(ComponentName className) { 4092263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (DBG) Log.d(TAG, "Proxy object disconnected"); 4102263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mService = null; 4112263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mServiceListener != null) { 4122263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK); 4132263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4142263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4152263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood }; 4162263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 4172263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private boolean isEnabled() { 4182263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; 4192263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 4202263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4212263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 4222263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private boolean isValidDevice(BluetoothDevice device) { 4232263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (device == null) return false; 4242263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 4252263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; 4262263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood return false; 4272263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4282263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood 4292263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood private static void log(String msg) { 4302263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood Log.d(TAG, msg); 4312263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood } 4322263dd1ddd1a8ac828c25d34000c85165cad21efMike Lockwood} 433