1c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood/* 2c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Copyright (C) 2014 The Android Open Source Project 3c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * 4c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 5c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * you may not use this file except in compliance with the License. 6c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * You may obtain a copy of the License at 7c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * 8c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 9c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * 10c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Unless required by applicable law or agreed to in writing, software 11c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 12c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * See the License for the specific language governing permissions and 14c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * limitations under the License. 15c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood */ 16c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 17c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood/** 18c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Bluetooth A2dp StateMachine 19c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * (Disconnected) 20c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * | ^ 21c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * CONNECT | | DISCONNECTED 22c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * V | 23c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * (Pending) 24c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * | ^ 25c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * CONNECTED | | CONNECT 26c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * V | 27c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * (Connected) 28c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood */ 29c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodpackage com.android.bluetooth.a2dp; 30c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 31c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.BluetoothA2dpSink; 32c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.BluetoothAdapter; 33c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.BluetoothAudioConfig; 34c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.BluetoothDevice; 35c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.BluetoothProfile; 36c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.BluetoothUuid; 37c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.bluetooth.IBluetooth; 38c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.content.Context; 39c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.media.AudioFormat; 40c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.media.AudioManager; 41c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.Handler; 42c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.Message; 43c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.ParcelUuid; 44c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.PowerManager; 45c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.PowerManager.WakeLock; 46c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.content.Intent; 47c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.Message; 48c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.RemoteException; 49c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.ServiceManager; 50c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.os.ParcelUuid; 51c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport android.util.Log; 52c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport com.android.bluetooth.Utils; 53c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport com.android.bluetooth.btservice.AdapterService; 54c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport com.android.bluetooth.btservice.ProfileService; 55c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport com.android.internal.util.IState; 56c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport com.android.internal.util.State; 57c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport com.android.internal.util.StateMachine; 58c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport java.util.ArrayList; 59c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport java.util.List; 60c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport java.util.HashMap; 61c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodimport java.util.Set; 62c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 63c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodfinal class A2dpSinkStateMachine extends StateMachine { 64c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private static final boolean DBG = false; 65c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 66c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood static final int CONNECT = 1; 67c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood static final int DISCONNECT = 2; 68c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private static final int STACK_EVENT = 101; 69c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private static final int CONNECT_TIMEOUT = 201; 70c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 71c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private Disconnected mDisconnected; 72c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private Pending mPending; 73c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private Connected mConnected; 74c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 75c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private A2dpSinkService mService; 76c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private Context mContext; 77c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private BluetoothAdapter mAdapter; 78c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private final AudioManager mAudioManager; 79c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private IntentBroadcastHandler mIntentBroadcastHandler; 80c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private final WakeLock mWakeLock; 81c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 82c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private static final int MSG_CONNECTION_STATE_CHANGED = 0; 83c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 84c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mCurrentDevice is the device connected before the state changes 85c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mTargetDevice is the device to be connected 86c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mIncomingDevice is the device connecting to us, valid only in Pending state 87c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // when mIncomingDevice is not null, both mCurrentDevice 88c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // and mTargetDevice are null 89c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // when either mCurrentDevice or mTargetDevice is not null, 90c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mIncomingDevice is null 91c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Stable states 92c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // No connection, Disconnected state 93c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // both mCurrentDevice and mTargetDevice are null 94c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Connected, Connected state 95c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mCurrentDevice is not null, mTargetDevice is null 96c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Interim states 97c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Connecting to a device, Pending 98c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mCurrentDevice is null, mTargetDevice is not null 99c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Disconnecting device, Connecting to new device 100c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Pending 101c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Both mCurrentDevice and mTargetDevice are not null 102c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Disconnecting device Pending 103c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // mCurrentDevice is not null, mTargetDevice is null 104c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Incoming connections Pending 105c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Both mCurrentDevice and mTargetDevice are null 106c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private BluetoothDevice mCurrentDevice = null; 107c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private BluetoothDevice mTargetDevice = null; 108c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private BluetoothDevice mIncomingDevice = null; 109c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 110c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private final HashMap<BluetoothDevice,BluetoothAudioConfig> mAudioConfigs 111c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood = new HashMap<BluetoothDevice,BluetoothAudioConfig>(); 112c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 113c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood static { 114c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood classInitNative(); 115c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 116c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 117c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private A2dpSinkStateMachine(A2dpSinkService svc, Context context) { 118c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood super("A2dpSinkStateMachine"); 119c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mService = svc; 120c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mContext = context; 121c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mAdapter = BluetoothAdapter.getDefaultAdapter(); 122c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 123c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood initNative(); 124c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 125c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mDisconnected = new Disconnected(); 126c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mPending = new Pending(); 127c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mConnected = new Connected(); 128c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 129c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood addState(mDisconnected); 130c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood addState(mPending); 131c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood addState(mConnected); 132c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 133c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood setInitialState(mDisconnected); 134c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 135c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 136c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BluetoothA2dpSinkService"); 137c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 138c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIntentBroadcastHandler = new IntentBroadcastHandler(); 139c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 140c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 141c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 142c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 143c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood static A2dpSinkStateMachine make(A2dpSinkService svc, Context context) { 144c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood Log.d("A2dpSinkStateMachine", "make"); 145c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood A2dpSinkStateMachine a2dpSm = new A2dpSinkStateMachine(svc, context); 146c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood a2dpSm.start(); 147c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return a2dpSm; 148c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 149c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 150c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void doQuit() { 151c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood quitNow(); 152c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 153c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 154c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void cleanup() { 155c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood cleanupNative(); 156c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mAudioConfigs.clear(); 157c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 158c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 159c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private class Disconnected extends State { 160c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 161c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void enter() { 162c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Enter Disconnected: " + getCurrentMessage().what); 163c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 164c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 165c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 166c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public boolean processMessage(Message message) { 167c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Disconnected process message: " + message.what); 168c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null) { 169c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("ERROR: current, target, or mIncomingDevice not null in Disconnected"); 170c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return NOT_HANDLED; 171c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 172c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 173c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood boolean retValue = HANDLED; 174c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch(message.what) { 175c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECT: 176c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothDevice device = (BluetoothDevice) message.obj; 177c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 178c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED); 179c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 180c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!connectA2dpNative(getByteAddress(device)) ) { 181c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 182c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 183c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 184c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 185c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 186c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 187c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = device; 188c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mPending); 189c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 190c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // TODO(BT) remove CONNECT_TIMEOUT when the stack 191c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // sends back events consistently 192c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood sendMessageDelayed(CONNECT_TIMEOUT, 30000); 193c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 194c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case DISCONNECT: 195c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // ignore 196c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 197c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case STACK_EVENT: 198c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood StackEvent event = (StackEvent) message.obj; 199c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (event.type) { 200c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_CONNECTION_STATE_CHANGED: 201c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processConnectionEvent(event.valueInt, event.device); 202c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 203c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_AUDIO_CONFIG_CHANGED: 204c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processAudioConfigEvent(event.audioConfig, event.device); 205c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 206c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 207c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Unexpected stack event: " + event.type); 208c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 209c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 210c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 211c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 212c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return NOT_HANDLED; 213c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 214c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return retValue; 215c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 216c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 217c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 218c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void exit() { 219c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Exit Disconnected: " + getCurrentMessage().what); 220c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 221c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 222c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // in Disconnected state 223c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void processConnectionEvent(int state, BluetoothDevice device) { 224c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (state) { 225c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_DISCONNECTED: 226c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logw("Ignore HF DISCONNECTED event, device: " + device); 227c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 228c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_CONNECTING: 229c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (okToConnect(device)){ 230c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logi("Incoming A2DP accepted"); 231c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 232c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED); 233c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 234c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIncomingDevice = device; 235c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mPending); 236c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 237c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 238c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood //reject the connection and stay in Disconnected state itself 239c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logi("Incoming A2DP rejected"); 240c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood disconnectA2dpNative(getByteAddress(device)); 241c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // the other profile connection should be initiated 242c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood AdapterService adapterService = AdapterService.getAdapterService(); 243c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (adapterService != null) { 244c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood adapterService.connectOtherProfile(device, 245c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood AdapterService.PROFILE_CONN_REJECTED); 246c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 247c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 248c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 249c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_CONNECTED: 250c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logw("A2DP Connected from Disconnected state"); 251c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (okToConnect(device)){ 252c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logi("Incoming A2DP accepted"); 253c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 254c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED); 255c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 256c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice = device; 257c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mConnected); 258c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 259c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 260c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood //reject the connection and stay in Disconnected state itself 261c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logi("Incoming A2DP rejected"); 262c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood disconnectA2dpNative(getByteAddress(device)); 263c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // the other profile connection should be initiated 264c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood AdapterService adapterService = AdapterService.getAdapterService(); 265c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (adapterService != null) { 266c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood adapterService.connectOtherProfile(device, 267c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood AdapterService.PROFILE_CONN_REJECTED); 268c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 269c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 270c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 271c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_DISCONNECTING: 272c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood logw("Ignore HF DISCONNECTING event, device: " + device); 273c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 274c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 275c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Incorrect state: " + state); 276c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 277c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 278c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 279c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 280c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 281c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private class Pending extends State { 282c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 283c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void enter() { 284c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Enter Pending: " + getCurrentMessage().what); 285c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 286c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 287c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 288c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public boolean processMessage(Message message) { 289c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Pending process message: " + message.what); 290c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 291c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood boolean retValue = HANDLED; 292c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch(message.what) { 293c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECT: 294c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood deferMessage(message); 295c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 296c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECT_TIMEOUT: 297c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED, 298c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood getByteAddress(mTargetDevice)); 299c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 300c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case DISCONNECT: 301c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothDevice device = (BluetoothDevice) message.obj; 302c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mCurrentDevice != null && mTargetDevice != null && 303c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice.equals(device) ) { 304c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // cancel connection to the mTargetDevice 305c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 306c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 307c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 308c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = null; 309c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 310c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 311c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood deferMessage(message); 312c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 313c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 314c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case STACK_EVENT: 315c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood StackEvent event = (StackEvent) message.obj; 316c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (event.type) { 317c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_CONNECTION_STATE_CHANGED: 318c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood removeMessages(CONNECT_TIMEOUT); 319c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processConnectionEvent(event.valueInt, event.device); 320c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 321c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_AUDIO_CONFIG_CHANGED: 322c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processAudioConfigEvent(event.audioConfig, event.device); 323c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 324c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 325c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Unexpected stack event: " + event.type); 326c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 327c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 328c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 329c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 330c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return NOT_HANDLED; 331c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 332c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return retValue; 333c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 334c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 335c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // in Pending state 336c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void processConnectionEvent(int state, BluetoothDevice device) { 337c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (state) { 338c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_DISCONNECTED: 339c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mAudioConfigs.remove(device); 340c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 341c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mCurrentDevice, 342c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED, 343c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTING); 344c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 345c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice = null; 346c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 347c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 348c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mTargetDevice != null) { 349c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!connectA2dpNative(getByteAddress(mTargetDevice))) { 350c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mTargetDevice, 351c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED, 352c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 353c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 354c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = null; 355c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mDisconnected); 356c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 357c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 358c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 359c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 360c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIncomingDevice = null; 361c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mDisconnected); 362c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 363c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 364c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 365c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // outgoing connection failed 366c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED, 367c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 368c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 369c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = null; 370c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mDisconnected); 371c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 372c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 373c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mIncomingDevice, 374c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED, 375c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 376c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 377c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIncomingDevice = null; 378c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mDisconnected); 379c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 380c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 381c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Unknown device Disconnected: " + device); 382c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 383c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 384c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_CONNECTED: 385c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 386c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // disconnection failed 387c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, 388c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTING); 389c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mTargetDevice != null) { 390c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED, 391c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 392c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 393c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 394c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = null; 395c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mConnected); 396c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 397c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 398c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_CONNECTED, 399c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 400c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 401c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice = mTargetDevice; 402c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = null; 403c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mConnected); 404c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 405c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 406c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mIncomingDevice, BluetoothProfile.STATE_CONNECTED, 407c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 408c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 409c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice = mIncomingDevice; 410c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIncomingDevice = null; 411c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mConnected); 412c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 413c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 414c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Unknown device Connected: " + device); 415c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // something is wrong here, but sync our state with stack 416c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 417c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED); 418c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 419c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice = device; 420c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = null; 421c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIncomingDevice = null; 422c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mConnected); 423c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 424c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 425c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 426c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_CONNECTING: 427c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 428c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("current device tries to connect back"); 429c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // TODO(BT) ignore or reject 430c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 431c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // The stack is connecting to target device or 432c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // there is an incoming connection from the target device at the same time 433c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // we already broadcasted the intent, doing nothing here 434c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Stack and target device are connecting"); 435c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 436c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 437c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Another connecting event on the incoming device"); 438c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 439c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // We get an incoming connecting request while Pending 440c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // TODO(BT) is stack handing this case? let's ignore it for now 441c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Incoming connection while pending, ignore"); 442c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 443c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 444c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_DISCONNECTING: 445c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 446c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // we already broadcasted the intent, doing nothing here 447c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (DBG) { 448c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("stack is disconnecting mCurrentDevice"); 449c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 450c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 451c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("TargetDevice is getting disconnected"); 452c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 453c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("IncomingDevice is getting disconnected"); 454c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 455c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Disconnecting unknown device: " + device); 456c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 457c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 458c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 459c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Incorrect state: " + state); 460c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 461c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 462c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 463c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 464c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 465c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 466c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private class Connected extends State { 467c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 468c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void enter() { 469c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Enter Connected: " + getCurrentMessage().what); 470c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Upon connected, the audio starts out as stopped 471c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastAudioState(mCurrentDevice, BluetoothA2dpSink.STATE_NOT_PLAYING, 472c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothA2dpSink.STATE_PLAYING); 473c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 474c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 475c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 476c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public boolean processMessage(Message message) { 477c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Connected process message: " + message.what); 478c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mCurrentDevice == null) { 479c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("ERROR: mCurrentDevice is null in Connected"); 480c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return NOT_HANDLED; 481c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 482c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 483c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood boolean retValue = HANDLED; 484c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch(message.what) { 485c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECT: 486c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood { 487c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothDevice device = (BluetoothDevice) message.obj; 488c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mCurrentDevice.equals(device)) { 489c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 490c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 491c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 492c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 493c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED); 494c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!disconnectA2dpNative(getByteAddress(mCurrentDevice))) { 495c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 496c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTING); 497c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 498c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 499c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 500c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 501c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mTargetDevice = device; 502c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mPending); 503c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 504c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 505c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 506c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case DISCONNECT: 507c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood { 508c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothDevice device = (BluetoothDevice) message.obj; 509c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!mCurrentDevice.equals(device)) { 510c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 511c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 512c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING, 513c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTED); 514c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!disconnectA2dpNative(getByteAddress(device))) { 515c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 516c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_DISCONNECTED); 517c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 518c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 519c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mPending); 520c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 521c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 522c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case STACK_EVENT: 523c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood StackEvent event = (StackEvent) message.obj; 524c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (event.type) { 525c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_CONNECTION_STATE_CHANGED: 526c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processConnectionEvent(event.valueInt, event.device); 527c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 528c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_AUDIO_STATE_CHANGED: 529c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processAudioStateEvent(event.valueInt, event.device); 530c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 531c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case EVENT_TYPE_AUDIO_CONFIG_CHANGED: 532c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood processAudioConfigEvent(event.audioConfig, event.device); 533c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 534c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 535c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Unexpected stack event: " + event.type); 536c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 537c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 538c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 539c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 540c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return NOT_HANDLED; 541c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 542c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return retValue; 543c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 544c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 545c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // in Connected state 546c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void processConnectionEvent(int state, BluetoothDevice device) { 547c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (state) { 548c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case CONNECTION_STATE_DISCONNECTED: 549c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mAudioConfigs.remove(device); 550c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mCurrentDevice.equals(device)) { 551c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_DISCONNECTED, 552c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.STATE_CONNECTED); 553c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (A2dpSinkStateMachine.this) { 554c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice = null; 555c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood transitionTo(mDisconnected); 556c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 557c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 558c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Disconnected from unknown device: " + device); 559c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 560c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 561c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 562c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Connection State Device: " + device + " bad state: " + state); 563c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 564c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 565c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 566c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void processAudioStateEvent(int state, BluetoothDevice device) { 567c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!mCurrentDevice.equals(device)) { 568c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Audio State Device:" + device + "is different from ConnectedDevice:" + 569c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mCurrentDevice); 570c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return; 571c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 572c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (state) { 573c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case AUDIO_STATE_STARTED: 574c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastAudioState(device, BluetoothA2dpSink.STATE_PLAYING, 575c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothA2dpSink.STATE_NOT_PLAYING); 576c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 577c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case AUDIO_STATE_REMOTE_SUSPEND: 578c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case AUDIO_STATE_STOPPED: 579c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastAudioState(device, BluetoothA2dpSink.STATE_NOT_PLAYING, 580c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothA2dpSink.STATE_PLAYING); 581c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 582c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood default: 583c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Audio State Device: " + device + " bad state: " + state); 584c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 585c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 586c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 587c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 588c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 589c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void processAudioConfigEvent(BluetoothAudioConfig audioConfig, BluetoothDevice device) { 590c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mAudioConfigs.put(device, audioConfig); 591c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood broadcastAudioConfig(device, audioConfig); 592c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 593c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 594c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood int getConnectionState(BluetoothDevice device) { 595c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (getCurrentState() == mDisconnected) { 596c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_DISCONNECTED; 597c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 598c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 599c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized (this) { 600c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood IState currentState = getCurrentState(); 601c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (currentState == mPending) { 602c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mTargetDevice != null) && mTargetDevice.equals(device)) { 603c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_CONNECTING; 604c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 605c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 606c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_DISCONNECTING; 607c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 608c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if ((mIncomingDevice != null) && mIncomingDevice.equals(device)) { 609c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_CONNECTING; // incoming connection 610c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 611c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_DISCONNECTED; 612c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 613c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 614c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (currentState == mConnected) { 615c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (mCurrentDevice.equals(device)) { 616c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_CONNECTED; 617c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 618c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_DISCONNECTED; 619c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } else { 620c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood loge("Bad currentState: " + currentState); 621c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return BluetoothProfile.STATE_DISCONNECTED; 622c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 623c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 624c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 625c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 626c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { 627c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return mAudioConfigs.get(device); 628c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 629c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 630c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood List<BluetoothDevice> getConnectedDevices() { 631c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 632c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized(this) { 633c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (getCurrentState() == mConnected) { 634c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood devices.add(mCurrentDevice); 635c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 636c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 637c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return devices; 638c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 639c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 640c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood boolean okToConnect(BluetoothDevice device) { 641c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood AdapterService adapterService = AdapterService.getAdapterService(); 642c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood boolean ret = true; 643c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood //check if this is an incoming connection in Quiet mode. 644c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if((adapterService == null) || 645c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood ((adapterService.isQuietModeEnabled() == true) && 646c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood (mTargetDevice == null))){ 647c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood ret = false; 648c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 649c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return ret; 650c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 651c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 652c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 653c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 654c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 655c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood int connectionState; 656c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 657c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood for (BluetoothDevice device : bondedDevices) { 658c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood ParcelUuid[] featureUuids = device.getUuids(); 659c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (!BluetoothUuid.isUuidPresent(featureUuids, BluetoothUuid.AudioSource)) { 660c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood continue; 661c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 662c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood connectionState = getConnectionState(device); 663c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood for(int i = 0; i < states.length; i++) { 664c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood if (connectionState == states[i]) { 665c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood deviceList.add(device); 666c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 667c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 668c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 669c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return deviceList; 670c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 671c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 672c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 673c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // This method does not check for error conditon (newState == prevState) 674c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void broadcastConnectionState(BluetoothDevice device, int newState, int prevState) { 675c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 676c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood int delay = mAudioManager.setBluetoothA2dpDeviceConnectionState(device, newState, 677c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothProfile.A2DP_SINK); 678c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 679c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mWakeLock.acquire(); 680c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mIntentBroadcastHandler.sendMessageDelayed(mIntentBroadcastHandler.obtainMessage( 681c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood MSG_CONNECTION_STATE_CHANGED, 682c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood prevState, 683c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood newState, 684c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood device), 685c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood delay); 686c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 687c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 688c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void broadcastAudioState(BluetoothDevice device, int state, int prevState) { 689c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood Intent intent = new Intent(BluetoothA2dpSink.ACTION_PLAYING_STATE_CHANGED); 690c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 691c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 692c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothProfile.EXTRA_STATE, state); 693c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood//FIXME intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 694c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mContext.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 695c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 696c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("A2DP Playing state : device: " + device + " State:" + prevState + "->" + state); 697c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 698c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 699c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void broadcastAudioConfig(BluetoothDevice device, BluetoothAudioConfig audioConfig) { 700c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood Intent intent = new Intent(BluetoothA2dpSink.ACTION_AUDIO_CONFIG_CHANGED); 701c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 702c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothA2dpSink.EXTRA_AUDIO_CONFIG, audioConfig); 703c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood//FIXME intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 704c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mContext.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 705c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 706c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("A2DP Audio Config : device: " + device + " config: " + audioConfig); 707c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 708c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 709c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private byte[] getByteAddress(BluetoothDevice device) { 710c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return Utils.getBytesFromAddress(device.getAddress()); 711c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 712c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 713c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void onConnectionStateChanged(int state, byte[] address) { 714c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED); 715c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood event.valueInt = state; 716c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood event.device = getDevice(address); 717c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood sendMessage(STACK_EVENT, event); 718c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 719c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 720c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void onAudioStateChanged(int state, byte[] address) { 721c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood StackEvent event = new StackEvent(EVENT_TYPE_AUDIO_STATE_CHANGED); 722c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood event.valueInt = state; 723c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood event.device = getDevice(address); 724c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood sendMessage(STACK_EVENT, event); 725c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 726c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 727c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void onAudioConfigChanged(byte[] address, int sampleRate, int channelCount) { 728c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood StackEvent event = new StackEvent(EVENT_TYPE_AUDIO_CONFIG_CHANGED); 729c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood int channelConfig = (channelCount == 1 ? AudioFormat.CHANNEL_IN_MONO 730c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood : AudioFormat.CHANNEL_IN_STEREO); 731c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood event.audioConfig = new BluetoothAudioConfig(sampleRate, channelConfig, 732c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood AudioFormat.ENCODING_PCM_16BIT); 733c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood event.device = getDevice(address); 734c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood sendMessage(STACK_EVENT, event); 735c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 736c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 737c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private BluetoothDevice getDevice(byte[] address) { 738c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 739c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 740c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 741c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private class StackEvent { 742c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood int type = EVENT_TYPE_NONE; 743c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood int valueInt = 0; 744c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothDevice device = null; 745c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood BluetoothAudioConfig audioConfig = null; 746c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 747c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private StackEvent(int type) { 748c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood this.type = type; 749c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 750c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 751c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood /** Handles A2DP connection state change intent broadcasts. */ 752c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private class IntentBroadcastHandler extends Handler { 753c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 754c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private void onConnectionStateChanged(BluetoothDevice device, int prevState, int state) { 755c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood Intent intent = new Intent(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); 756c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 757c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothProfile.EXTRA_STATE, state); 758c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 759c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood//FIXME intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 760c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mContext.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 761c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood log("Connection state " + device + ": " + prevState + "->" + state); 762c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mService.notifyProfileConnectionStateChanged(device, BluetoothProfile.A2DP_SINK, 763c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood state, prevState); 764c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 765c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 766c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood @Override 767c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood public void handleMessage(Message msg) { 768c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood switch (msg.what) { 769c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood case MSG_CONNECTION_STATE_CHANGED: 770c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood onConnectionStateChanged((BluetoothDevice) msg.obj, msg.arg1, msg.arg2); 771c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood mWakeLock.release(); 772c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood break; 773c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 774c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 775c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood } 776c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 777c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 778c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Event types for STACK_EVENT message 779c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final private static int EVENT_TYPE_NONE = 0; 780c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final private static int EVENT_TYPE_CONNECTION_STATE_CHANGED = 1; 781c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final private static int EVENT_TYPE_AUDIO_STATE_CHANGED = 2; 782c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final private static int EVENT_TYPE_AUDIO_CONFIG_CHANGED = 3; 783c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 784c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // Do not modify without updating the HAL bt_av.h files. 785c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 786c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // match up with btav_connection_state_t enum of bt_av.h 787c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int CONNECTION_STATE_DISCONNECTED = 0; 788c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int CONNECTION_STATE_CONNECTING = 1; 789c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int CONNECTION_STATE_CONNECTED = 2; 790c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int CONNECTION_STATE_DISCONNECTING = 3; 791c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 792c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood // match up with btav_audio_state_t enum of bt_av.h 793c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int AUDIO_STATE_REMOTE_SUSPEND = 0; 794c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int AUDIO_STATE_STOPPED = 1; 795c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood final static int AUDIO_STATE_STARTED = 2; 796c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood 797c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private native static void classInitNative(); 798c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private native void initNative(); 799c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private native void cleanupNative(); 800c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private native boolean connectA2dpNative(byte[] address); 801c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood private native boolean disconnectA2dpNative(byte[] address); 802c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood} 803