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