19b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh/*
2f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh * Copyright (C) 2010 The Android Open Source Project
39b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
49b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * Licensed under the Apache License, Version 2.0 (the "License");
59b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * you may not use this file except in compliance with the License.
69b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * You may obtain a copy of the License at
79b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
89b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *      http://www.apache.org/licenses/LICENSE-2.0
99b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * Unless required by applicable law or agreed to in writing, software
119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * distributed under the License is distributed on an "AS IS" BASIS,
129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * See the License for the specific language governing permissions and
149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * limitations under the License.
159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh */
169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshpackage android.bluetooth;
189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.content.BroadcastReceiver;
209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.content.Context;
219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.content.Intent;
229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.content.IntentFilter;
239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.os.Message;
24365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganeshimport android.os.PowerManager;
259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.server.BluetoothA2dpService;
269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.server.BluetoothService;
279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.util.Log;
28365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganeshimport android.util.Pair;
299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport com.android.internal.util.HierarchicalState;
319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport com.android.internal.util.HierarchicalStateMachine;
329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh/**
349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * This class is the Profile connection state machine associated with a remote
359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * device. When the device bonds an instance of this class is created.
369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * This tracks incoming and outgoing connections of all the profiles. Incoming
379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * connections are preferred over outgoing connections and HFP preferred over
389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * A2DP. When the device is unbonded, the instance is removed.
399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * States:
419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * {@link BondedDevice}: This state represents a bonded device. When in this
429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * state none of the profiles are in transition states.
439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * {@link OutgoingHandsfree}: Handsfree profile connection is in a transition
459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * state because of a outgoing Connect or Disconnect.
469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * {@link IncomingHandsfree}: Handsfree profile connection is in a transition
489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * state because of a incoming Connect or Disconnect.
499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * {@link IncomingA2dp}: A2dp profile connection is in a transition
519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * state because of a incoming Connect or Disconnect.
529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * {@link OutgoingA2dp}: A2dp profile connection is in a transition
549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * state because of a outgoing Connect or Disconnect.
559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh *
569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * Todo(): Write tests for this class, when the Android Mock support is completed.
579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh * @hide
589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh */
59f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshpublic final class BluetoothDeviceProfileState extends HierarchicalStateMachine {
60f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private static final String TAG = "BluetoothDeviceProfileState";
61bdb1d9320b49c286935b04e286ae41734b8f7237Jaikumar Ganesh    private static final boolean DBG = false;
629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int CONNECT_HFP_OUTGOING = 1;
649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int CONNECT_HFP_INCOMING = 2;
659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int CONNECT_A2DP_OUTGOING = 3;
669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int CONNECT_A2DP_INCOMING = 4;
679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int DISCONNECT_HFP_OUTGOING = 5;
699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private static final int DISCONNECT_HFP_INCOMING = 6;
709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int DISCONNECT_A2DP_OUTGOING = 7;
719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static final int DISCONNECT_A2DP_INCOMING = 8;
7259453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    public static final int DISCONNECT_PBAP_OUTGOING = 9;
739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
7459453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    public static final int UNPAIR = 100;
7559453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    public static final int AUTO_CONNECT_PROFILES = 101;
7659453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    public static final int TRANSITION_TO_STABLE = 102;
7728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh    public static final int CONNECT_OTHER_PROFILES = 103;
78365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final int CONNECTION_ACCESS_REQUEST_REPLY = 104;
79365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final int CONNECTION_ACCESS_REQUEST_EXPIRY = 105;
809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
81f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private static final int AUTO_CONNECT_DELAY = 6000; // 6 secs
8240e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh    private static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
83365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final int CONNECTION_ACCESS_REQUEST_EXPIRY_TIMEOUT = 7000; // 7 secs
84365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final int CONNECTION_ACCESS_UNDEFINED = -1;
85365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final long INIT_INCOMING_REJECT_TIMER = 1000; // 1 sec
86365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final long MAX_INCOMING_REJECT_TIMER = 3600 * 1000 * 4; // 4 hours
87365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
88365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final String PREFS_NAME = "ConnectionAccess";
899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BondedDevice mBondedDevice = new BondedDevice();
919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private OutgoingHandsfree mOutgoingHandsfree = new OutgoingHandsfree();
929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private IncomingHandsfree mIncomingHandsfree = new IncomingHandsfree();
939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private IncomingA2dp mIncomingA2dp = new IncomingA2dp();
949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private OutgoingA2dp mOutgoingA2dp = new OutgoingA2dp();
959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private Context mContext;
979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothService mService;
989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothHeadset  mHeadsetService;
10059453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    private BluetoothPbap     mPbapService;
1019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private boolean mHeadsetServiceConnected;
10259453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    private boolean mPbapServiceConnected;
103365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
1049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothDevice mDevice;
1069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private int mHeadsetState;
1079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private int mA2dpState;
108365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private long mIncomingRejectTimer;
109365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private boolean mConnectionAccessReplyReceived = false;
110365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private Pair<Integer, String> mIncomingConnections;
111365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private PowerManager.WakeLock mWakeLock;
112365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private PowerManager mPowerManager;
1139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
1169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        public void onReceive(Context context, Intent intent) {
1179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String action = intent.getAction();
1189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
1199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (!device.equals(mDevice)) return;
1209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
1229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0);
1239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                int oldState = intent.getIntExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, 0);
1249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                int initiator = intent.getIntExtra(
1259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR,
1269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    BluetoothHeadset.LOCAL_DISCONNECT);
127365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                // We trust this device now
128365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                if (newState == BluetoothHeadset.STATE_CONNECTED) {
129365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    setTrust(BluetoothDevice.CONNECTION_ACCESS_YES);
130365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                }
1319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mHeadsetState = newState;
1329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (newState == BluetoothHeadset.STATE_DISCONNECTED &&
1339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    initiator == BluetoothHeadset.REMOTE_DISCONNECT) {
1349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    sendMessage(DISCONNECT_HFP_INCOMING);
1359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
1369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (newState == BluetoothHeadset.STATE_CONNECTED ||
1379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    newState == BluetoothHeadset.STATE_DISCONNECTED) {
1389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    sendMessage(TRANSITION_TO_STABLE);
1399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
1409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
1419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
1429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0);
1439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mA2dpState = newState;
144365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                // We trust this device now
145365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                if (newState == BluetoothA2dp.STATE_CONNECTED) {
146365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    setTrust(BluetoothDevice.CONNECTION_ACCESS_YES);
147365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                }
1489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if ((oldState == BluetoothA2dp.STATE_CONNECTED ||
1499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                           oldState == BluetoothA2dp.STATE_PLAYING) &&
1509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                           newState == BluetoothA2dp.STATE_DISCONNECTED) {
1519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    sendMessage(DISCONNECT_A2DP_INCOMING);
1529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
1539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (newState == BluetoothA2dp.STATE_CONNECTED ||
1549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    newState == BluetoothA2dp.STATE_DISCONNECTED) {
1559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    sendMessage(TRANSITION_TO_STABLE);
1569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
15770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
15870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // This is technically not needed, but we can get stuck sometimes.
15970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                // For example, if incoming A2DP fails, we are not informed by Bluez
16070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                sendMessage(TRANSITION_TO_STABLE);
161365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            } else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
162365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                mWakeLock.release();
163365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                int val = intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
164365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                                             BluetoothDevice.CONNECTION_ACCESS_NO);
165365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                Message msg = obtainMessage(CONNECTION_ACCESS_REQUEST_REPLY);
166365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                msg.arg1 = val;
167365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                sendMessage(msg);
1689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
1699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh      }
1709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    };
1719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
172f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private boolean isPhoneDocked(BluetoothDevice autoConnectDevice) {
173f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh      // This works only because these broadcast intents are "sticky"
174f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh      Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
175f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh      if (i != null) {
176f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh          int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
177f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh          if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
178f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh              BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
179f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh              if (device != null && autoConnectDevice.equals(device)) {
180f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                  return true;
181f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh              }
182f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh          }
183f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh      }
184f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh      return false;
185f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh  }
186f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
187f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    public BluetoothDeviceProfileState(Context context, String address,
1889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh          BluetoothService service, BluetoothA2dpService a2dpService) {
1899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        super(address);
1909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mContext = context;
1919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mDevice = new BluetoothDevice(address);
1929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mService = service;
1939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
1949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        addState(mBondedDevice);
1969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        addState(mOutgoingHandsfree);
1979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        addState(mIncomingHandsfree);
1989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        addState(mIncomingA2dp);
1999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        addState(mOutgoingA2dp);
2009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        setInitialState(mBondedDevice);
2019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        IntentFilter filter = new IntentFilter();
2039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        // Fine-grained state broadcasts
2049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
2059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
2069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
20770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
208365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
2099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mContext.registerReceiver(mBroadcastReceiver, filter);
2119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        HeadsetServiceListener l = new HeadsetServiceListener();
21359453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        PbapServiceListener p = new PbapServiceListener();
214365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
215365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mIncomingConnections = mService.getIncomingState(address);
216365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mIncomingRejectTimer = readTimerValue();
217365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
218365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK |
219365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                                              PowerManager.ACQUIRE_CAUSES_WAKEUP |
220365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                                              PowerManager.ON_AFTER_RELEASE, TAG);
221365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mWakeLock.setReferenceCounted(false);
2229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
2239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private class HeadsetServiceListener implements BluetoothHeadset.ServiceListener {
2259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        public HeadsetServiceListener() {
2269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mHeadsetService = new BluetoothHeadset(mContext, this);
2279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
2289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        public void onServiceConnected() {
229f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            synchronized(BluetoothDeviceProfileState.this) {
2309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mHeadsetServiceConnected = true;
2319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
2329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
2339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        public void onServiceDisconnected() {
234f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            synchronized(BluetoothDeviceProfileState.this) {
2359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mHeadsetServiceConnected = false;
2369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
2379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
2389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
2399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
24059453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    private class PbapServiceListener implements BluetoothPbap.ServiceListener {
24159453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        public PbapServiceListener() {
24259453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh            mPbapService = new BluetoothPbap(mContext, this);
24359453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        }
24459453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        public void onServiceConnected() {
24559453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh            synchronized(BluetoothDeviceProfileState.this) {
24659453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                mPbapServiceConnected = true;
24759453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh            }
24859453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        }
24959453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        public void onServiceDisconnected() {
25059453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh            synchronized(BluetoothDeviceProfileState.this) {
25159453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                mPbapServiceConnected = false;
25259453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh            }
25359453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh        }
25459453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    }
25559453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh
2569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private class BondedDevice extends HierarchicalState {
2579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
2589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected void enter() {
259bdb1d9320b49c286935b04e286ae41734b8f7237Jaikumar Ganesh            Log.i(TAG, "Entering ACL Connected state with: " + getCurrentMessage().what);
2609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message m = new Message();
2619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            m.copyFrom(getCurrentMessage());
2629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            sendMessageAtFrontOfQueue(m);
2639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
2649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
2659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected boolean processMessage(Message message) {
2669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            log("ACL Connected State -> Processing Message: " + message.what);
2679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            switch(message.what) {
2689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_OUTGOING:
2699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_OUTGOING:
2709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mOutgoingHandsfree);
2719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
2729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_INCOMING:
2739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mIncomingHandsfree);
2749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
2759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_INCOMING:
2769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mIncomingHandsfree);
2779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
2789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_OUTGOING:
2799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_OUTGOING:
2809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mOutgoingA2dp);
2819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
2829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_INCOMING:
2839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_INCOMING:
2849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mIncomingA2dp);
2859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
28659453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                case DISCONNECT_PBAP_OUTGOING:
28759453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    processCommand(DISCONNECT_PBAP_OUTGOING);
28859453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    break;
2899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case UNPAIR:
2909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mHeadsetState != BluetoothHeadset.STATE_DISCONNECTED) {
2919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        sendMessage(DISCONNECT_HFP_OUTGOING);
2929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(message);
2939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        break;
2949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    } else if (mA2dpState != BluetoothA2dp.STATE_DISCONNECTED) {
2959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        sendMessage(DISCONNECT_A2DP_OUTGOING);
2969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(message);
2979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        break;
2989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
2999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    processCommand(UNPAIR);
3009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
3019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case AUTO_CONNECT_PROFILES:
302f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                    if (isPhoneDocked(mDevice)) {
303f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                        // Don't auto connect to docks.
304f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                        break;
305f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                    } else if (!mHeadsetServiceConnected) {
3069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(message);
3079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    } else {
3089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        if (mHeadsetService.getPriority(mDevice) ==
309f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                              BluetoothHeadset.PRIORITY_AUTO_CONNECT &&
310f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                              !mHeadsetService.isConnected(mDevice)) {
31128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            Log.i(TAG, "Headset:Auto Connect Profiles");
3129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                            mHeadsetService.connectHeadset(mDevice);
3139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        }
3149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        if (mA2dpService != null &&
315f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                              mA2dpService.getSinkPriority(mDevice) ==
316f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                              BluetoothA2dp.PRIORITY_AUTO_CONNECT &&
317f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh                              mA2dpService.getConnectedSinks().length == 0) {
31828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            Log.i(TAG, "A2dp:Auto Connect Profiles");
3199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                            mA2dpService.connectSink(mDevice);
3209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        }
3219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
3229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
32328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                case CONNECT_OTHER_PROFILES:
32428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    if (isPhoneDocked(mDevice)) {
32528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                       break;
32628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    }
32728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    if (message.arg1 == CONNECT_A2DP_OUTGOING) {
32828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                        if (mA2dpService != null &&
32928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            mA2dpService.getConnectedSinks().length == 0) {
33028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            Log.i(TAG, "A2dp:Connect Other Profiles");
33128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            mA2dpService.connectSink(mDevice);
33228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                        }
33328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    } else if (message.arg1 == CONNECT_HFP_OUTGOING) {
33428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                        if (!mHeadsetServiceConnected) {
33528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            deferMessage(message);
33628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                        } else {
33728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            if (!mHeadsetService.isConnected(mDevice)) {
33828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                                Log.i(TAG, "Headset:Connect Other Profiles");
33928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                                mHeadsetService.connectHeadset(mDevice);
34028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                            }
34128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                        }
34228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    }
34328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    break;
3449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case TRANSITION_TO_STABLE:
3459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // ignore.
3469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
3479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                default:
3489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return NOT_HANDLED;
3499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
3509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return HANDLED;
3519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
3529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
3539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
3549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private class OutgoingHandsfree extends HierarchicalState {
3559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private boolean mStatus = false;
3569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private int mCommand;
3579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
3589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
3599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected void enter() {
360bdb1d9320b49c286935b04e286ae41734b8f7237Jaikumar Ganesh            Log.i(TAG, "Entering OutgoingHandsfree state with: " + getCurrentMessage().what);
3619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mCommand = getCurrentMessage().what;
3629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (mCommand != CONNECT_HFP_OUTGOING &&
3639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mCommand != DISCONNECT_HFP_OUTGOING) {
3649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                Log.e(TAG, "Error: OutgoingHandsfree state with command:" + mCommand);
3659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
3669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mStatus = processCommand(mCommand);
36770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            if (!mStatus) {
36870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                sendMessage(TRANSITION_TO_STABLE);
36970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                mService.sendProfileStateMessage(BluetoothProfileState.HFP,
37070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                                                 BluetoothProfileState.TRANSITION_TO_STABLE);
37170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            }
3729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
3739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
3749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
3759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected boolean processMessage(Message message) {
3769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            log("OutgoingHandsfree State -> Processing Message: " + message.what);
3779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message deferMsg = new Message();
3789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            int command = message.what;
3799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            switch(command) {
3809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_OUTGOING:
3819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (command != mCommand) {
3829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        // Disconnect followed by a connect - defer
3839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(message);
3849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
3859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
3869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_INCOMING:
3879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mCommand == CONNECT_HFP_OUTGOING) {
3889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        // Cancel outgoing connect, accept incoming
3899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        cancelCommand(CONNECT_HFP_OUTGOING);
3909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        transitionTo(mIncomingHandsfree);
3919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    } else {
3929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        // We have done the disconnect but we are not
3939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        // sure which state we are in at this point.
3949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(message);
3959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
3969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
3979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_INCOMING:
3989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // accept incoming A2DP, retry HFP_OUTGOING
3999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mIncomingA2dp);
4009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
4019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mStatus) {
4029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMsg.what = mCommand;
4039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(deferMsg);
4049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
4059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_OUTGOING:
4079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
4089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_OUTGOING:
4109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mCommand == CONNECT_HFP_OUTGOING) {
4119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        // Cancel outgoing connect
4129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        cancelCommand(CONNECT_HFP_OUTGOING);
4139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        processCommand(DISCONNECT_HFP_OUTGOING);
4149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
4159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // else ignore
4169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_INCOMING:
4189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // When this happens the socket would be closed and the headset
4199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // state moved to DISCONNECTED, cancel the outgoing thread.
4209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // if it still is in CONNECTING state
4219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    cancelCommand(CONNECT_HFP_OUTGOING);
4229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_OUTGOING:
4249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
4259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_INCOMING:
4279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Bluez will handle the disconnect. If because of this the outgoing
4289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // handsfree connection has failed, then retry.
4299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mStatus) {
4309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                       deferMsg.what = mCommand;
4319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                       deferMessage(deferMsg);
4329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
4339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
43459453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                case DISCONNECT_PBAP_OUTGOING:
4359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case UNPAIR:
4369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case AUTO_CONNECT_PROFILES:
43728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                case CONNECT_OTHER_PROFILES:
4389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
4399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case TRANSITION_TO_STABLE:
4419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mBondedDevice);
4429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                default:
4449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return NOT_HANDLED;
4459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
4469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return HANDLED;
4479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
4489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
4499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
4509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private class IncomingHandsfree extends HierarchicalState {
4519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private boolean mStatus = false;
4529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private int mCommand;
4539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
4549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
4559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected void enter() {
456bdb1d9320b49c286935b04e286ae41734b8f7237Jaikumar Ganesh            Log.i(TAG, "Entering IncomingHandsfree state with: " + getCurrentMessage().what);
4579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mCommand = getCurrentMessage().what;
4589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (mCommand != CONNECT_HFP_INCOMING &&
4599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mCommand != DISCONNECT_HFP_INCOMING) {
4609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                Log.e(TAG, "Error: IncomingHandsfree state with command:" + mCommand);
4619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
4629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mStatus = processCommand(mCommand);
46370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            if (!mStatus) {
46470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                sendMessage(TRANSITION_TO_STABLE);
46570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                mService.sendProfileStateMessage(BluetoothProfileState.HFP,
46670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                                                 BluetoothProfileState.TRANSITION_TO_STABLE);
46770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            }
4689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
4699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
4709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
4719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected boolean processMessage(Message message) {
4729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            log("IncomingHandsfree State -> Processing Message: " + message.what);
4739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            switch(message.what) {
4749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_OUTGOING:
4759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
4769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
4779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_INCOMING:
4789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Ignore
4799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    Log.e(TAG, "Error: Incoming connection with a pending incoming connection");
4809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
481365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                case CONNECTION_ACCESS_REQUEST_REPLY:
482365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    int val = message.arg1;
483365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    mConnectionAccessReplyReceived = true;
484365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    boolean value = false;
485365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    if (val == BluetoothDevice.CONNECTION_ACCESS_YES) {
486365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        value = true;
487365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    }
488365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    setTrust(val);
489365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
490365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    handleIncomingConnection(CONNECT_HFP_INCOMING, value);
491365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    break;
492365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                case CONNECTION_ACCESS_REQUEST_EXPIRY:
493365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    if (!mConnectionAccessReplyReceived) {
494365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        handleIncomingConnection(CONNECT_HFP_INCOMING, false);
495365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        sendConnectionAccessRemovalIntent();
496365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        sendMessage(TRANSITION_TO_STABLE);
497365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    }
498365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    break;
4999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_INCOMING:
5009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Serialize the commands.
5019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
5029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_OUTGOING:
5049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
5059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_OUTGOING:
5079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // We don't know at what state we are in the incoming HFP connection state.
5089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // We can be changing from DISCONNECTED to CONNECTING, or
5099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // from CONNECTING to CONNECTED, so serializing this command is
5109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // the safest option.
5119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
5129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_INCOMING:
5149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Nothing to do here, we will already be DISCONNECTED
5159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // by this point.
5169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_OUTGOING:
5189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
5199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_INCOMING:
5219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Bluez handles incoming A2DP disconnect.
5229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // If this causes incoming HFP to fail, it is more of a headset problem
5239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // since both connections are incoming ones.
5249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
52559453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                case DISCONNECT_PBAP_OUTGOING:
5269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case UNPAIR:
5279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case AUTO_CONNECT_PROFILES:
52828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                case CONNECT_OTHER_PROFILES:
5299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
5309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case TRANSITION_TO_STABLE:
5329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mBondedDevice);
5339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                default:
5359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return NOT_HANDLED;
5369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
5379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return HANDLED;
5389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
5399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
5409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
5419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private class OutgoingA2dp extends HierarchicalState {
5429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private boolean mStatus = false;
5439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private int mCommand;
5449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
5459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
5469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected void enter() {
547bdb1d9320b49c286935b04e286ae41734b8f7237Jaikumar Ganesh            Log.i(TAG, "Entering OutgoingA2dp state with: " + getCurrentMessage().what);
5489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mCommand = getCurrentMessage().what;
5499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (mCommand != CONNECT_A2DP_OUTGOING &&
5509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mCommand != DISCONNECT_A2DP_OUTGOING) {
5519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                Log.e(TAG, "Error: OutgoingA2DP state with command:" + mCommand);
5529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
5539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mStatus = processCommand(mCommand);
55470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            if (!mStatus) {
55570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                sendMessage(TRANSITION_TO_STABLE);
55670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                mService.sendProfileStateMessage(BluetoothProfileState.A2DP,
55770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                                                 BluetoothProfileState.TRANSITION_TO_STABLE);
55870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            }
5599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
5609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
5619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
5629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected boolean processMessage(Message message) {
5639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            log("OutgoingA2dp State->Processing Message: " + message.what);
5649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message deferMsg = new Message();
5659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            switch(message.what) {
5669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_OUTGOING:
5679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    processCommand(CONNECT_HFP_OUTGOING);
5689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
5699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Don't cancel A2DP outgoing as there is no guarantee it
5709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // will get canceled.
5719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // It might already be connected but we might not have got the
5729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // A2DP_SINK_STATE_CHANGE. Hence, no point disconnecting here.
5739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // The worst case, the connection will fail, retry.
5749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // The same applies to Disconnecting an A2DP connection.
5759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mStatus) {
5769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMsg.what = mCommand;
5779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(deferMsg);
5789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
5799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_INCOMING:
5819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    processCommand(CONNECT_HFP_INCOMING);
5829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
5839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Don't cancel A2DP outgoing as there is no guarantee
5849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // it will get canceled.
5859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // The worst case, the connection will fail, retry.
5869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mStatus) {
5879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMsg.what = mCommand;
5889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(deferMsg);
5899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
5909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_INCOMING:
5929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Bluez will take care of conflicts between incoming and outgoing
5939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // connections.
5949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mIncomingA2dp);
5959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_OUTGOING:
5979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Ignore
5989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
5999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_OUTGOING:
6009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
6019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_INCOMING:
6039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // At this point, we are already disconnected
6049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // with HFP. Sometimes A2DP connection can
6059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // fail due to the disconnection of HFP. So add a retry
6069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // for the A2DP.
6079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mStatus) {
6089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMsg.what = mCommand;
6099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        deferMessage(deferMsg);
6109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
6119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_OUTGOING:
613adbda6f094bf957e2943f80ef63d4530f6fcfc5aJaikumar Ganesh                    deferMessage(message);
6149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_INCOMING:
6169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Ignore, will be handled by Bluez
6179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
61859453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                case DISCONNECT_PBAP_OUTGOING:
6199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case UNPAIR:
6209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case AUTO_CONNECT_PROFILES:
62128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                case CONNECT_OTHER_PROFILES:
6229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
6239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case TRANSITION_TO_STABLE:
6259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mBondedDevice);
6269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                default:
6289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return NOT_HANDLED;
6299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
6309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return HANDLED;
6319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
6329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
6339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
6349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private class IncomingA2dp extends HierarchicalState {
6359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private boolean mStatus = false;
6369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        private int mCommand;
6379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
6389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
6399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected void enter() {
640bdb1d9320b49c286935b04e286ae41734b8f7237Jaikumar Ganesh            Log.i(TAG, "Entering IncomingA2dp state with: " + getCurrentMessage().what);
6419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mCommand = getCurrentMessage().what;
6429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (mCommand != CONNECT_A2DP_INCOMING &&
6439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mCommand != DISCONNECT_A2DP_INCOMING) {
6449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                Log.e(TAG, "Error: IncomingA2DP state with command:" + mCommand);
6459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
6469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mStatus = processCommand(mCommand);
64770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            if (!mStatus) {
64870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                sendMessage(TRANSITION_TO_STABLE);
64970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                mService.sendProfileStateMessage(BluetoothProfileState.A2DP,
65070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh                                                 BluetoothProfileState.TRANSITION_TO_STABLE);
65170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            }
6529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
6539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
6549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        @Override
6559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        protected boolean processMessage(Message message) {
6569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            log("IncomingA2dp State->Processing Message: " + message.what);
6579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message deferMsg = new Message();
6589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            switch(message.what) {
6599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_OUTGOING:
6609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
6619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_HFP_INCOMING:
6639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Shouldn't happen, but serialize the commands.
6649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
6659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_INCOMING:
6679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // ignore
6689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
669365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                case CONNECTION_ACCESS_REQUEST_REPLY:
670365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    int val = message.arg1;
671365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    mConnectionAccessReplyReceived = true;
672365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    boolean value = false;
673365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    if (val == BluetoothDevice.CONNECTION_ACCESS_YES) {
674365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        value = true;
675365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    }
676365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    setTrust(val);
677365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    handleIncomingConnection(CONNECT_A2DP_INCOMING, value);
678365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    break;
679365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                case CONNECTION_ACCESS_REQUEST_EXPIRY:
680365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    // The check protects the race condition between REQUEST_REPLY
681365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    // and the timer expiry.
682365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    if (!mConnectionAccessReplyReceived) {
683365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        handleIncomingConnection(CONNECT_A2DP_INCOMING, false);
684365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        sendConnectionAccessRemovalIntent();
685365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        sendMessage(TRANSITION_TO_STABLE);
686365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    }
687365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    break;
6889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case CONNECT_A2DP_OUTGOING:
6899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Defer message and retry
6909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
6919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_OUTGOING:
6939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
6949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
6959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_HFP_INCOMING:
6969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Shouldn't happen but if does, we can handle it.
6979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Depends if the headset can handle it.
6989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Incoming A2DP will be handled by Bluez, Disconnect HFP
6999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // the socket would have already been closed.
7009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // ignore
7019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
7029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_OUTGOING:
7039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
7049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
7059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case DISCONNECT_A2DP_INCOMING:
7069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    // Ignore, will be handled by Bluez
7079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
70859453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                case DISCONNECT_PBAP_OUTGOING:
7099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case UNPAIR:
7109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case AUTO_CONNECT_PROFILES:
71128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                case CONNECT_OTHER_PROFILES:
7129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    deferMessage(message);
7139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
7149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                case TRANSITION_TO_STABLE:
7159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    transitionTo(mBondedDevice);
7169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    break;
7179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                default:
7189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return NOT_HANDLED;
7199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
7209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return HANDLED;
7219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
7229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
7239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
7249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
7259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
7269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    synchronized void cancelCommand(int command) {
7279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (command == CONNECT_HFP_OUTGOING ) {
7289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // Cancel the outgoing thread.
7299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (mHeadsetServiceConnected) {
7309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                mHeadsetService.cancelConnectThread();
7319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
7329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // HeadsetService is down. Phone process most likely crashed.
7339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // The thread would have got killed.
7349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
7359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
7369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
73759453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh    synchronized void deferProfileServiceMessage(int command) {
7389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        Message msg = new Message();
7399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        msg.what = command;
7409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        deferMessage(msg);
7419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
7429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
743365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private void updateIncomingAllowedTimer() {
744365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        // Not doing a perfect exponential backoff because
745365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        // we want two different rates. For all practical
746365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        // purposes, this is good enough.
747365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (mIncomingRejectTimer == 0) mIncomingRejectTimer = INIT_INCOMING_REJECT_TIMER;
748365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
749365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mIncomingRejectTimer *= 5;
750365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (mIncomingRejectTimer > MAX_INCOMING_REJECT_TIMER) {
751365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            mIncomingRejectTimer = MAX_INCOMING_REJECT_TIMER;
752365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        }
753365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        writeTimerValue(mIncomingRejectTimer);
754365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
755365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
756365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private boolean handleIncomingConnection(int command, boolean accept) {
757365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        boolean ret = false;
758365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        Log.i(TAG, "handleIncomingConnection:" + command + ":" + accept);
759365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        switch (command) {
760365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            case CONNECT_HFP_INCOMING:
761365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                if (!accept) {
762365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    ret = mHeadsetService.rejectIncomingConnect(mDevice);
763365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    sendMessage(TRANSITION_TO_STABLE);
764365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    updateIncomingAllowedTimer();
765365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                } else if (mHeadsetState == BluetoothHeadset.STATE_CONNECTING) {
766365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    writeTimerValue(0);
767365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    ret =  mHeadsetService.acceptIncomingConnect(mDevice);
768365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                } else if (mHeadsetState == BluetoothHeadset.STATE_DISCONNECTED) {
769365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    writeTimerValue(0);
770365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    handleConnectionOfOtherProfiles(command);
771365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    ret = mHeadsetService.createIncomingConnect(mDevice);
772365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                }
773365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                break;
774365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            case CONNECT_A2DP_INCOMING:
775365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                if (!accept) {
776365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    ret = mA2dpService.allowIncomingConnect(mDevice, false);
777365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    sendMessage(TRANSITION_TO_STABLE);
778365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    updateIncomingAllowedTimer();
779365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                } else {
780365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    writeTimerValue(0);
781365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    ret = mA2dpService.allowIncomingConnect(mDevice, true);
782365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    handleConnectionOfOtherProfiles(command);
783365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                }
784365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                break;
785365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            default:
786365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                Log.e(TAG, "Waiting for incoming connection but state changed to:" + command);
787365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                break;
788365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh       }
789365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh       return ret;
790365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
791365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
792365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private void sendConnectionAccessIntent() {
793365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mConnectionAccessReplyReceived = false;
794365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
795365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (!mPowerManager.isScreenOn()) mWakeLock.acquire();
796365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
797365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
798365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
799365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
800365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
801365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
802365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private void sendConnectionAccessRemovalIntent() {
803365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mWakeLock.release();
804365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL);
805365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
806365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
807365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
808365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
809365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private int getTrust() {
810365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        String address = mDevice.getAddress();
811365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (mIncomingConnections != null) return mIncomingConnections.first;
812365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        return CONNECTION_ACCESS_UNDEFINED;
813365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
814365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
815365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
816365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private String getStringValue(long value) {
817365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        StringBuilder sbr = new StringBuilder();
818365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        sbr.append(Long.toString(System.currentTimeMillis()));
819365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        sbr.append("-");
820365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        sbr.append(Long.toString(value));
821365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        return sbr.toString();
822365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
823365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
824365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private void setTrust(int value) {
825365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        String second;
826365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (mIncomingConnections == null) {
827365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            second = getStringValue(INIT_INCOMING_REJECT_TIMER);
828365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        } else {
829365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            second = mIncomingConnections.second;
830365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        }
831365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
832365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mIncomingConnections = new Pair(value, second);
833365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mService.writeIncomingConnectionState(mDevice.getAddress(), mIncomingConnections);
834365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
835365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
836365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private void writeTimerValue(long value) {
837365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        Integer first;
838365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (mIncomingConnections == null) {
839365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            first = CONNECTION_ACCESS_UNDEFINED;
840365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        } else {
841365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            first = mIncomingConnections.first;
842365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        }
843365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mIncomingConnections = new Pair(first, getStringValue(value));
844365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        mService.writeIncomingConnectionState(mDevice.getAddress(), mIncomingConnections);
845365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
846365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
847365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private long readTimerValue() {
848365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (mIncomingConnections == null)
849365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            return 0;
850365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        String value = mIncomingConnections.second;
851365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        String[] splits = value.split("-");
852365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (splits != null && splits.length == 2) {
853365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            return Long.parseLong(splits[1]);
854365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        }
855365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        return 0;
856365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
857365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
858365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    private boolean readIncomingAllowedValue() {
859365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (readTimerValue() == 0) return true;
860365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        String value = mIncomingConnections.second;
861365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        String[] splits = value.split("-");
862365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        if (splits != null && splits.length == 2) {
863365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            long val1 = Long.parseLong(splits[0]);
864365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            long val2 = Long.parseLong(splits[1]);
865365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            if (val1 + val2 <= System.currentTimeMillis()) {
866365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                return true;
867365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh            }
868365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        }
869365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        return false;
870365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh    }
871365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh
8729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    synchronized boolean processCommand(int command) {
873365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        Log.e(TAG, "Processing command:" + command);
874365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh        Message msg;
8759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        switch(command) {
8769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case  CONNECT_HFP_OUTGOING:
8779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (mHeadsetService != null) {
8789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return mHeadsetService.connectHeadsetInternal(mDevice);
8799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
8809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                break;
8819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case CONNECT_HFP_INCOMING:
8829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (!mHeadsetServiceConnected) {
88359453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    deferProfileServiceMessage(command);
884365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                } else {
885365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    // Check if device is already trusted
886365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    int access = getTrust();
887365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    if (access == BluetoothDevice.CONNECTION_ACCESS_YES) {
888365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        handleIncomingConnection(command, true);
889365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    } else if (access == BluetoothDevice.CONNECTION_ACCESS_NO &&
890365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                               !readIncomingAllowedValue()) {
891365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        handleIncomingConnection(command, false);
892365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    } else {
893365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        sendConnectionAccessIntent();
894365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        msg = obtainMessage(CONNECTION_ACCESS_REQUEST_EXPIRY);
895365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                        sendMessageDelayed(msg,
896365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                                CONNECTION_ACCESS_REQUEST_EXPIRY_TIMEOUT);
897365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    }
898365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    return true;
8999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
9009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                break;
9019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case CONNECT_A2DP_OUTGOING:
9029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (mA2dpService != null) {
9039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return mA2dpService.connectSinkInternal(mDevice);
9049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
9059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                break;
9069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case CONNECT_A2DP_INCOMING:
907365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                // Check if device is already trusted
908365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                int access = getTrust();
909365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                if (access == BluetoothDevice.CONNECTION_ACCESS_YES) {
910365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    handleIncomingConnection(command, true);
911365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                } else if (access == BluetoothDevice.CONNECTION_ACCESS_NO &&
912365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                           !readIncomingAllowedValue()) {
913365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    handleIncomingConnection(command, false);
914365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                } else {
915365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    sendConnectionAccessIntent();
916365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    msg = obtainMessage(CONNECTION_ACCESS_REQUEST_EXPIRY);
917365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                    sendMessageDelayed(msg,
918365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                            CONNECTION_ACCESS_REQUEST_EXPIRY_TIMEOUT);
919365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                }
9209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                return true;
9219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case DISCONNECT_HFP_OUTGOING:
9229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (!mHeadsetServiceConnected) {
92359453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    deferProfileServiceMessage(command);
9249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                } else {
92559453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    // Disconnect PBAP
92659453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    // TODO(): Add PBAP to the state machine.
92759453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    Message m = new Message();
92859453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    m.what = DISCONNECT_PBAP_OUTGOING;
92959453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    deferMessage(m);
9309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mHeadsetService.getPriority(mDevice) ==
9319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        BluetoothHeadset.PRIORITY_AUTO_CONNECT) {
9329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        mHeadsetService.setPriority(mDevice, BluetoothHeadset.PRIORITY_ON);
9339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
9349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return mHeadsetService.disconnectHeadsetInternal(mDevice);
9359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
9369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                break;
9379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case DISCONNECT_HFP_INCOMING:
9389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                // ignore
9399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                return true;
9409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case DISCONNECT_A2DP_INCOMING:
9419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                // ignore
9429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                return true;
9439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case DISCONNECT_A2DP_OUTGOING:
9449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                if (mA2dpService != null) {
9459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    if (mA2dpService.getSinkPriority(mDevice) ==
9469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        BluetoothA2dp.PRIORITY_AUTO_CONNECT) {
9479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                        mA2dpService.setSinkPriority(mDevice, BluetoothHeadset.PRIORITY_ON);
9489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    }
9499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                    return mA2dpService.disconnectSinkInternal(mDevice);
9509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                }
9519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                break;
95259453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh            case DISCONNECT_PBAP_OUTGOING:
95359453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                if (!mPbapServiceConnected) {
95459453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    deferProfileServiceMessage(command);
95559453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                } else {
95659453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                    return mPbapService.disconnect();
95759453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                }
95859453c947a2d4d64e2f4a4216a479cd33728439cJaikumar Ganesh                break;
9599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            case UNPAIR:
960365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                writeTimerValue(INIT_INCOMING_REJECT_TIMER);
961365522a828f529593aa87e4d5a22f0cf2460c45aJaikumar Ganesh                setTrust(CONNECTION_ACCESS_UNDEFINED);
9629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                return mService.removeBondInternal(mDevice.getAddress());
9639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            default:
9649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                Log.e(TAG, "Error: Unknown Command");
9659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
9669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
9679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
9689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
96928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh    private void handleConnectionOfOtherProfiles(int command) {
97028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // The white paper recommendations mentions that when there is a
97128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // link loss, it is the responsibility of the remote device to connect.
97228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // Many connect only 1 profile - and they connect the second profile on
97328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // some user action (like play being pressed) and so we need this code.
97428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // Auto Connect code only connects to the last connected device - which
97528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // is useful in cases like when the phone reboots. But consider the
97628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // following case:
97728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // User is connected to the car's phone and  A2DP profile.
97828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // User comes to the desk  and places the phone in the dock
97928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // (or any speaker or music system or even another headset) and thus
98028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // gets connected to the A2DP profile.  User goes back to the car.
98128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // Ideally the car's system is supposed to send incoming connections
98228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // from both Handsfree and A2DP profile. But they don't. The Auto
98328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // connect code, will not work here because we only auto connect to the
98428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // last connected device for that profile which in this case is the dock.
98528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // Now suppose a user is using 2 headsets simultaneously, one for the
98628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // phone profile one for the A2DP profile. If this is the use case, we
98728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // expect the user to use the preference to turn off the A2DP profile in
98828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // the Settings screen for the first headset. Else, after link loss,
98928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // there can be an incoming connection from the first headset which
99028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // might result in the connection of the A2DP profile (if the second
99128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // headset is slower) and thus the A2DP profile on the second headset
99228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // will never get connected.
99328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        //
99428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        // TODO(): Handle other profiles here.
99528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        switch (command) {
99628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh            case CONNECT_HFP_INCOMING:
99728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                // Connect A2DP if there is no incoming connection
99828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                // If the priority is OFF - don't auto connect.
99940e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                if (mA2dpService.getSinkPriority(mDevice) == BluetoothA2dp.PRIORITY_ON ||
100040e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                        mA2dpService.getSinkPriority(mDevice) ==
100140e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                            BluetoothA2dp.PRIORITY_AUTO_CONNECT) {
100228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    Message msg = new Message();
100328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    msg.what = CONNECT_OTHER_PROFILES;
100428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    msg.arg1 = CONNECT_A2DP_OUTGOING;
100540e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                    sendMessageDelayed(msg, CONNECT_OTHER_PROFILES_DELAY);
100628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                }
100728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                break;
100828967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh            case CONNECT_A2DP_INCOMING:
100928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                // This is again against spec. HFP incoming connections should be made
101028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                // before A2DP, so we should not hit this case. But many devices
101128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                // don't follow this.
101240e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                if (mHeadsetService.getPriority(mDevice) == BluetoothHeadset.PRIORITY_ON
101340e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                        || mHeadsetService.getPriority(mDevice) ==
101440e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                            BluetoothHeadset.PRIORITY_AUTO_CONNECT) {
101528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    Message msg = new Message();
101628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    msg.what = CONNECT_OTHER_PROFILES;
101728967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                    msg.arg1 = CONNECT_HFP_OUTGOING;
101840e6c210f88bfde3f5bc0faa93de0910f1a8181bJaikumar Ganesh                    sendMessageDelayed(msg, CONNECT_OTHER_PROFILES_DELAY);
101928967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                }
102028967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                break;
102128967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh            default:
102228967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh                break;
102328967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh        }
102428967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh
102528967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh    }
102628967499d7433f2cc498e7432707e2d5991a408aJaikumar Ganesh
1027f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    /*package*/ BluetoothDevice getDevice() {
1028f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        return mDevice;
1029f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    }
1030f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
10319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void log(String message) {
10329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (DBG) {
10339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Log.i(TAG, "Device:" + mDevice + " Message:" + message);
10349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
10359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
10369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh}
1037