127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon/* 227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * Copyright (C) 2013 The Android Open Source Project 327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * you may not use this file except in compliance with the License. 627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * You may obtain a copy of the License at 727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * http://www.apache.org/licenses/LICENSE-2.0 927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 1027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * Unless required by applicable law or agreed to in writing, software 1127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 1227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * See the License for the specific language governing permissions and 1427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * limitations under the License. 1527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 1627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 1727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonpackage com.android.phone; 1827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 1927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport com.google.android.collect.Lists; 2027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport com.google.common.base.Preconditions; 2127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 2227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.bluetooth.BluetoothAdapter; 2327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.bluetooth.BluetoothDevice; 2427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.bluetooth.BluetoothHeadset; 2527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.bluetooth.BluetoothProfile; 2627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.content.BroadcastReceiver; 2727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.content.Context; 2827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.content.Intent; 2927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.content.IntentFilter; 3027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.os.SystemClock; 3127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.os.SystemProperties; 3227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport android.util.Log; 3327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 3427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport com.android.internal.telephony.CallManager; 35de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Leeimport com.android.internal.telephony.Connection; 362c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordonimport com.android.services.telephony.common.Call; 3727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 3827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordonimport java.util.List; 3927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 4027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon/** 41593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon * Listens to and caches bluetooth headset state. Used By the AudioRouter for maintaining 42593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon * overall audio state for use in the UI layer. Also provides method for connecting the bluetooth 43593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon * headset to the phone call. 4427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 452c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordonpublic class BluetoothManager implements CallModeler.Listener { 46593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon private static final String LOG_TAG = BluetoothManager.class.getSimpleName(); 4727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private static final boolean DBG = 4827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 4927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2); 5027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 5127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private final BluetoothAdapter mBluetoothAdapter; 5227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private final CallManager mCallManager; 5327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private final Context mContext; 542c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon private final CallModeler mCallModeler; 5527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 5627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private BluetoothHeadset mBluetoothHeadset; 5727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private int mBluetoothHeadsetState = BluetoothProfile.STATE_DISCONNECTED; 5827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private int mBluetoothHeadsetAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 5927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private boolean mShowBluetoothIndication = false; 6027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private boolean mBluetoothConnectionPending = false; 6127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private long mBluetoothConnectionRequestTime; 6227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 6327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Broadcast receiver for various intent broadcasts (see onCreate()) 6427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private final BroadcastReceiver mReceiver = new BluetoothBroadcastReceiver(); 6527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 6627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private final List<BluetoothIndicatorListener> mListeners = Lists.newArrayList(); 6727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 682c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon public BluetoothManager(Context context, CallManager callManager, CallModeler callModeler) { 6927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mContext = context; 7027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mCallManager = callManager; 712c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon mCallModeler = callModeler; 7227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 7327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 7427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon init(mContext); 7527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 7627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 7727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ boolean isBluetoothHeadsetAudioOn() { 7827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return (mBluetoothHeadsetAudioState != BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 7927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 8027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 8127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 8227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Bluetooth helper methods. 8327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 8427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // - BluetoothAdapter is the Bluetooth system service. If 8527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // getDefaultAdapter() returns null 8627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // then the device is not BT capable. Use BluetoothDevice.isEnabled() 8727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // to see if BT is enabled on the device. 8827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 8927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // - BluetoothHeadset is the API for the control connection to a 9027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Bluetooth Headset. This lets you completely connect/disconnect a 9127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // headset (which we don't do from the Phone UI!) but also lets you 9227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // get the address of the currently active headset and see whether 9327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // it's currently connected. 9427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 9527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 9627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @return true if the Bluetooth on/off switch in the UI should be 9727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * available to the user (i.e. if the device is BT-capable 9827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * and a headset is connected.) 9927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 10027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ boolean isBluetoothAvailable() { 10127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAvailable()..."); 10227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 10327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // There's no need to ask the Bluetooth system service if BT is enabled: 10427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 10527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 10627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // if ((adapter == null) || !adapter.isEnabled()) { 10727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // if (DBG) log(" ==> FALSE (BT not enabled)"); 10827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // return false; 10927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // } 11027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // if (DBG) log(" - BT enabled! device name " + adapter.getName() 11127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // + ", address " + adapter.getAddress()); 11227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 11327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // ...since we already have a BluetoothHeadset instance. We can just 11427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // call isConnected() on that, and assume it'll be false if BT isn't 11527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // enabled at all. 11627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 11727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Check if there's a connected headset, using the BluetoothHeadset API. 11827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon boolean isConnected = false; 11927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothHeadset != null) { 12027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); 12127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 12227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (deviceList.size() > 0) { 12327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon BluetoothDevice device = deviceList.get(0); 12427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon isConnected = true; 12527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 12627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log(" - headset state = " + 12727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset.getConnectionState(device)); 12827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log(" - headset address: " + device); 12927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log(" - isConnected: " + isConnected); 13027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 13127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 13227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 13327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log(" ==> " + isConnected); 13427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return isConnected; 13527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 13627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 13727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 13827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @return true if a BT Headset is available, and its audio is currently connected. 13927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 14027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ boolean isBluetoothAudioConnected() { 14127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothHeadset == null) { 14227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAudioConnected: ==> FALSE (null mBluetoothHeadset)"); 14327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return false; 14427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 14527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); 14627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 14727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (deviceList.isEmpty()) { 14827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return false; 14927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 15027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon BluetoothDevice device = deviceList.get(0); 15127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon boolean isAudioOn = mBluetoothHeadset.isAudioConnected(device); 15227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAudioConnected: ==> isAudioOn = " + isAudioOn); 15327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return isAudioOn; 15427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 15527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 15627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 15727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * Helper method used to control the onscreen "Bluetooth" indication; 15827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * see InCallControlState.bluetoothIndicatorOn. 15927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 16027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @return true if a BT device is available and its audio is currently connected, 16127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * <b>or</b> if we issued a BluetoothHeadset.connectAudio() 16227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * call within the last 5 seconds (which presumably means 16327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * that the BT audio connection is currently being set 16427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * up, and will be connected soon.) 16527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 16627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ boolean isBluetoothAudioConnectedOrPending() { 16727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (isBluetoothAudioConnected()) { 16827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAudioConnectedOrPending: ==> TRUE (really connected)"); 16927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return true; 17027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 17127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 17227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // If we issued a connectAudio() call "recently enough", even 17327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // if BT isn't actually connected yet, let's still pretend BT is 17427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // on. This makes the onscreen indication more responsive. 17527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothConnectionPending) { 17627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon long timeSinceRequest = 17727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon SystemClock.elapsedRealtime() - mBluetoothConnectionRequestTime; 17827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (timeSinceRequest < 5000 /* 5 seconds */) { 17927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAudioConnectedOrPending: ==> TRUE (requested " 18027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon + timeSinceRequest + " msec ago)"); 18127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return true; 18227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } else { 18327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAudioConnectedOrPending: ==> FALSE (request too old: " 18427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon + timeSinceRequest + " msec ago)"); 18527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothConnectionPending = false; 18627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return false; 18727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 18827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 18927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 19027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("isBluetoothAudioConnectedOrPending: ==> FALSE"); 19127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return false; 19227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 19327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 19427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 19527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @return true if the onscreen UI should currently be showing the 19627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * special "bluetooth is active" indication in a couple of places (in 19727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * which UI elements turn blue and/or show the bluetooth logo.) 19827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 19927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * This depends on the BluetoothHeadset state *and* the current 20027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * telephony state; see shouldShowBluetoothIndication(). 20127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 20227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @see CallCard 20327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @see NotificationMgr.updateInCallNotification 20427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 20527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ boolean showBluetoothIndication() { 20627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return mShowBluetoothIndication; 20727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 20827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 20927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 21027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * Recomputes the mShowBluetoothIndication flag based on the current 21127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * bluetooth state and current telephony state. 21227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 21327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * This needs to be called any time the bluetooth headset state or the 21427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * telephony state changes. 21527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 21627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ void updateBluetoothIndication() { 21727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState, 21827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadsetAudioState, 21927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mCallManager); 22027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 22127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon notifyListeners(mShowBluetoothIndication); 22227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 22327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 2249b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon public void addBluetoothIndicatorListener(BluetoothIndicatorListener listener) { 22527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (!mListeners.contains(listener)) { 22627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mListeners.add(listener); 22727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 22827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 22927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 2309b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon public void removeBluetoothIndicatorListener(BluetoothIndicatorListener listener) { 2319b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon if (mListeners.contains(listener)) { 2329b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon mListeners.remove(listener); 2339b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon } 2349b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon } 2359b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon 23627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private void notifyListeners(boolean showBluetoothOn) { 23727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon for (int i = 0; i < mListeners.size(); i++) { 23827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mListeners.get(i).onBluetoothIndicationChange(showBluetoothOn, this); 23927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 24027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 24127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 24227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private void init(Context context) { 24327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon Preconditions.checkNotNull(context); 24427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 24527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothAdapter != null) { 24627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener, 24727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon BluetoothProfile.HEADSET); 24827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 24927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 25027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Register for misc other intent broadcasts. 25127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon IntentFilter intentFilter = 25227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 25327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 25427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon context.registerReceiver(mReceiver, intentFilter); 2552c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon 2562c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon mCallModeler.addListener(this); 25727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 25827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 25927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private void tearDown() { 26027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothHeadset != null) { 26127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); 26227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset = null; 26327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 26427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 26527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 26627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 26727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon new BluetoothProfile.ServiceListener() { 26827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon @Override 26927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon public void onServiceConnected(int profile, BluetoothProfile proxy) { 27027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset = (BluetoothHeadset) proxy; 27127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("- Got BluetoothHeadset: " + mBluetoothHeadset); 27227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 27327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 27427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon @Override 27527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon public void onServiceDisconnected(int profile) { 27627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset = null; 27727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 27827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon }; 27927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 28027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 28127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * UI policy helper function for the couple of places in the UI that 28227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * have some way of indicating that "bluetooth is in use." 28327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * 28427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @return true if the onscreen UI should indicate that "bluetooth is in use", 28527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * based on the specified bluetooth headset state, and the 28627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * current state of the phone. 28727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * @see showBluetoothIndication() 28827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 28927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private static boolean shouldShowBluetoothIndication(int bluetoothState, 29027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon int bluetoothAudioState, 29127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon CallManager cm) { 29227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // We want the UI to indicate that "bluetooth is in use" in two 29327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // slightly different cases: 29427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 29527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // (a) The obvious case: if a bluetooth headset is currently in 29627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // use for an ongoing call. 29727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // 29827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // (b) The not-so-obvious case: if an incoming call is ringing, 29927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // and we expect that audio *will* be routed to a bluetooth 30027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // headset once the call is answered. 30127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 30227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon switch (cm.getState()) { 30327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon case OFFHOOK: 30427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // This covers normal active calls, and also the case if 30527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // the foreground call is DIALING or ALERTING. In this 30627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // case, bluetooth is considered "active" if a headset 30727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // is connected *and* audio is being routed to it. 30827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED) 30927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon && (bluetoothAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED)); 31027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 31127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon case RINGING: 31227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // If an incoming call is ringing, we're *not* yet routing 31327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // audio to the headset (since there's no in-call audio 31427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // yet!) In this case, if a bluetooth headset is 31527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // connected at all, we assume that it'll become active 31627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // once the user answers the phone. 31727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return (bluetoothState == BluetoothHeadset.STATE_CONNECTED); 31827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 31927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon default: // Presumably IDLE 32027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon return false; 32127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 32227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 32327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 32427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private void dumpBluetoothState() { 32527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("============== dumpBluetoothState() ============="); 32627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= isBluetoothAvailable: " + isBluetoothAvailable()); 32727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= isBluetoothAudioConnected: " + isBluetoothAudioConnected()); 32827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= isBluetoothAudioConnectedOrPending: " + isBluetoothAudioConnectedOrPending()); 32927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= PhoneApp.showBluetoothIndication: " 33027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon + showBluetoothIndication()); 33127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("="); 33227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothAdapter != null) { 33327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothHeadset != null) { 33427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); 33527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 33627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (deviceList.size() > 0) { 33727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon BluetoothDevice device = deviceList.get(0); 33827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= BluetoothHeadset.getCurrentDevice: " + device); 33927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= BluetoothHeadset.State: " 34027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon + mBluetoothHeadset.getConnectionState(device)); 34127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= BluetoothHeadset audio connected: " + 34227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset.isAudioConnected(device)); 34327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 34427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } else { 34527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= mBluetoothHeadset is null"); 34627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 34727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } else { 34827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon log("= mBluetoothAdapter is null; device is not BT capable"); 34927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 35027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 35127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 35227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ void connectBluetoothAudio() { 35327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("connectBluetoothAudio()..."); 35427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothHeadset != null) { 35527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // TODO(BT) check return 35627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset.connectAudio(); 35727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 35827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 35927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Watch out: The bluetooth connection doesn't happen instantly; 36027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // the connectAudio() call returns instantly but does its real 36127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // work in another thread. The mBluetoothConnectionPending flag 36227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // is just a little trickery to ensure that the onscreen UI updates 36327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // instantly. (See isBluetoothAudioConnectedOrPending() above.) 36427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothConnectionPending = true; 36527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime(); 36627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 36727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 36827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ void disconnectBluetoothAudio() { 36927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) log("disconnectBluetoothAudio()..."); 37027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (mBluetoothHeadset != null) { 37127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadset.disconnectAudio(); 37227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 37327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothConnectionPending = false; 37427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 37527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 37627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /** 37727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon * Receiver for misc intent broadcasts the BluetoothManager cares about. 37827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon */ 37927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private class BluetoothBroadcastReceiver extends BroadcastReceiver { 38027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon @Override 38127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon public void onReceive(Context context, Intent intent) { 38227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon String action = intent.getAction(); 38327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 38427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 38527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 38627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon BluetoothHeadset.STATE_DISCONNECTED); 38727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); 38827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState); 38927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon // Also update any visible UI if necessary 39027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon updateBluetoothIndication(); 39127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 39227a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon mBluetoothHeadsetAudioState = 39327a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 39427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 39527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); 39627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState); 39727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon updateBluetoothIndication(); 39827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 39927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 40027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 40127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 4022c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon @Override 4032c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon public void onDisconnect(Call call) { 4042c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon updateBluetoothIndication(); 4052c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon } 4062c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon 4072c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon @Override 4086c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng public void onIncoming(Call call) { 4092c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon // An incoming call can affect bluetooth indicator, so we update it whenever there is 4102c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon // a change to any of the calls. 4112c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon updateBluetoothIndication(); 4122c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon } 4132c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon 4142c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon @Override 4156c6b27265806a053193b8ccbc57f66b1feb8e5abChiao Cheng public void onUpdate(List<Call> calls) { 4162c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon updateBluetoothIndication(); 4172c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon } 4182c2d3cf8cca6bb471fbd26770b1736af2a32d619Santos Cordon 4193f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng @Override 420de41f67985e48d9cc17d48a9299648966b9bc7e5Yorke Lee public void onPostDialAction(Connection.PostDialState state, int callId, String chars, char c) { 4213f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng // no-op 4223f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng } 4233f015c9e837c4e7a2b710d32f16e81eb684dda74Chiao Cheng 42427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon private void log(String msg) { 42527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon Log.d(LOG_TAG, msg); 42627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 42727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon 42827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon /* package */ interface BluetoothIndicatorListener { 4299b7bac7705b3afcae7b010edc2032c7c0f37f770Santos Cordon public void onBluetoothIndicationChange(boolean isConnected, BluetoothManager manager); 43027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon } 43127a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon} 432