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