1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.telecom.bluetooth; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.bluetooth.BluetoothHeadset; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.telecom.Log; 26 import android.telecom.Logging.Session; 27 28 import com.android.internal.os.SomeArgs; 29 30 import static com.android.server.telecom.bluetooth.BluetoothRouteManager.HFP_IS_ON; 31 import static com.android.server.telecom.bluetooth.BluetoothRouteManager.HFP_LOST; 32 33 34 public class BluetoothStateReceiver extends BroadcastReceiver { 35 private static final String LOG_TAG = BluetoothStateReceiver.class.getSimpleName(); 36 public static final IntentFilter INTENT_FILTER; 37 static { 38 INTENT_FILTER = new IntentFilter(); 39 INTENT_FILTER.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 40 INTENT_FILTER.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 41 INTENT_FILTER.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED); 42 } 43 44 // If not in a call, BSR won't listen to the Bluetooth stack's HFP on/off messages, since 45 // other apps could be turning it on and off. We don't want to interfere. 46 private boolean mIsInCall = false; 47 private final BluetoothRouteManager mBluetoothRouteManager; 48 private final BluetoothDeviceManager mBluetoothDeviceManager; 49 50 public void onReceive(Context context, Intent intent) { 51 Log.startSession("BSR.oR"); 52 try { 53 String action = intent.getAction(); 54 switch (action) { 55 case BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED: 56 handleAudioStateChanged(intent); 57 break; 58 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: 59 handleConnectionStateChanged(intent); 60 break; 61 case BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED: 62 handleActiveDeviceChanged(intent); 63 break; 64 } 65 } finally { 66 Log.endSession(); 67 } 68 } 69 70 private void handleAudioStateChanged(Intent intent) { 71 if (!mIsInCall) { 72 Log.i(LOG_TAG, "Ignoring BT audio state change since we're not in a call"); 73 return; 74 } 75 int bluetoothHeadsetAudioState = 76 intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 77 BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 78 BluetoothDevice device = 79 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 80 if (device == null) { 81 Log.w(LOG_TAG, "Got null device from broadcast. " + 82 "Ignoring."); 83 return; 84 } 85 86 Log.i(LOG_TAG, "Device %s transitioned to audio state %d", 87 device.getAddress(), bluetoothHeadsetAudioState); 88 Session session = Log.createSubsession(); 89 SomeArgs args = SomeArgs.obtain(); 90 args.arg1 = session; 91 args.arg2 = device.getAddress(); 92 switch (bluetoothHeadsetAudioState) { 93 case BluetoothHeadset.STATE_AUDIO_CONNECTED: 94 mBluetoothRouteManager.sendMessage(HFP_IS_ON, args); 95 break; 96 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 97 mBluetoothRouteManager.sendMessage(HFP_LOST, args); 98 break; 99 } 100 } 101 102 private void handleConnectionStateChanged(Intent intent) { 103 int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 104 BluetoothHeadset.STATE_DISCONNECTED); 105 BluetoothDevice device = 106 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 107 108 if (device == null) { 109 Log.w(LOG_TAG, "Got null device from broadcast. " + 110 "Ignoring."); 111 return; 112 } 113 114 Log.i(LOG_TAG, "Device %s changed state to %d", 115 device.getAddress(), bluetoothHeadsetState); 116 117 if (bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED) { 118 mBluetoothDeviceManager.onDeviceConnected(device); 119 } else if (bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTED 120 || bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTING) { 121 mBluetoothDeviceManager.onDeviceDisconnected(device); 122 } 123 } 124 125 private void handleActiveDeviceChanged(Intent intent) { 126 BluetoothDevice device = 127 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 128 Log.i(LOG_TAG, "Device %s is now the preferred HFP device", device); 129 mBluetoothRouteManager.onActiveDeviceChanged(device); 130 } 131 132 public BluetoothStateReceiver(BluetoothDeviceManager deviceManager, 133 BluetoothRouteManager routeManager) { 134 mBluetoothDeviceManager = deviceManager; 135 mBluetoothRouteManager = routeManager; 136 } 137 138 public void setIsInCall(boolean isInCall) { 139 mIsInCall = isInCall; 140 } 141 } 142