blob: 665b956b3416ce1f1ad9335d3abb280e08b437b1 [file] [log] [blame]
Hall Liu8502d6e2016-10-31 14:07:52 -07001/*
2 * Copyright (C) 2016 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
17package com.android.server.telecom.bluetooth;
18
19import android.bluetooth.BluetoothDevice;
20import android.bluetooth.BluetoothHeadset;
21import android.bluetooth.BluetoothProfile;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.telecom.Log;
27
28import com.android.server.telecom.BluetoothAdapterProxy;
29import com.android.server.telecom.BluetoothHeadsetProxy;
30import com.android.server.telecom.TelecomSystem;
31
Hall Liud4970c12017-02-07 15:39:51 -080032import java.util.Collection;
Hall Liu8502d6e2016-10-31 14:07:52 -070033import java.util.LinkedHashMap;
Hall Liud4970c12017-02-07 15:39:51 -080034import java.util.LinkedList;
35import java.util.List;
36import java.util.Map;
Hall Liu8502d6e2016-10-31 14:07:52 -070037import java.util.Objects;
Hall Liud4970c12017-02-07 15:39:51 -080038import java.util.stream.Collectors;
Hall Liu8502d6e2016-10-31 14:07:52 -070039
40public class BluetoothDeviceManager {
41 private final BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
42 new BluetoothProfile.ServiceListener() {
43 @Override
44 public void onServiceConnected(int profile, BluetoothProfile proxy) {
45 Log.startSession("BMSL.oSC");
46 try {
47 synchronized (mLock) {
48 if (profile == BluetoothProfile.HEADSET) {
49 mBluetoothHeadsetService =
50 new BluetoothHeadsetProxy((BluetoothHeadset) proxy);
51 Log.i(this, "- Got BluetoothHeadset: " + mBluetoothHeadsetService);
52 } else {
53 Log.w(this, "Connected to non-headset bluetooth service." +
54 " Not changing bluetooth headset.");
55 }
56 }
57 } finally {
58 Log.endSession();
59 }
60 }
61
62 @Override
63 public void onServiceDisconnected(int profile) {
64 Log.startSession("BMSL.oSD");
65 try {
66 synchronized (mLock) {
67 mBluetoothHeadsetService = null;
Hall Liud4970c12017-02-07 15:39:51 -080068 Log.i(BluetoothDeviceManager.this, "Lost BluetoothHeadset service. " +
69 "Removing all tracked devices.");
70 List<BluetoothDevice> devicesToRemove = new LinkedList<>(
71 mConnectedDevicesByAddress.values());
72 mConnectedDevicesByAddress.clear();
73 for (BluetoothDevice device : devicesToRemove) {
74 mBluetoothRouteManager.onDeviceLost(device);
75 }
Hall Liu8502d6e2016-10-31 14:07:52 -070076 }
77 } finally {
78 Log.endSession();
79 }
80 }
81 };
82
83 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
84 @Override
85 public void onReceive(Context context, Intent intent) {
86 Log.startSession("BM.oR");
87 try {
88 String action = intent.getAction();
89
90 if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
91 int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
92 BluetoothHeadset.STATE_DISCONNECTED);
93 BluetoothDevice device =
94 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
95
96 if (device == null) {
97 Log.w(BluetoothDeviceManager.this, "Got null device from broadcast. " +
98 "Ignoring.");
99 return;
100 }
101
102 Log.i(BluetoothDeviceManager.this, "Device %s changed state to %d",
103 device.getAddress(), bluetoothHeadsetState);
104
105 synchronized (mLock) {
106 if (bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED) {
107 if (!mConnectedDevicesByAddress.containsKey(device.getAddress())) {
108 mConnectedDevicesByAddress.put(device.getAddress(), device);
109 mBluetoothRouteManager.onDeviceAdded(device);
110 }
111 } else if (bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTED
112 || bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTING) {
113 if (mConnectedDevicesByAddress.containsKey(device.getAddress())) {
114 mConnectedDevicesByAddress.remove(device.getAddress());
115 mBluetoothRouteManager.onDeviceLost(device);
116 }
117 }
118 }
119 }
120 } finally {
121 Log.endSession();
122 }
123 }
124 };
125
126 private final LinkedHashMap<String, BluetoothDevice> mConnectedDevicesByAddress =
127 new LinkedHashMap<>();
128 private final TelecomSystem.SyncRoot mLock;
129
130 private BluetoothRouteManager mBluetoothRouteManager;
131 private BluetoothHeadsetProxy mBluetoothHeadsetService;
132
133 public BluetoothDeviceManager(Context context, BluetoothAdapterProxy bluetoothAdapter,
134 TelecomSystem.SyncRoot lock) {
135 mLock = lock;
136
137 if (bluetoothAdapter != null) {
138 bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
139 BluetoothProfile.HEADSET);
140 }
141 IntentFilter intentFilter =
142 new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
143 context.registerReceiver(mReceiver, intentFilter);
144 }
145
146 public void setBluetoothRouteManager(BluetoothRouteManager brm) {
147 mBluetoothRouteManager = brm;
148 }
149
150 public int getNumConnectedDevices() {
151 return mConnectedDevicesByAddress.size();
152 }
153
154 public String getMostRecentlyConnectedDevice(String excludeAddress) {
155 String result = null;
156 synchronized (mLock) {
157 for (String addr : mConnectedDevicesByAddress.keySet()) {
158 if (!Objects.equals(addr, excludeAddress)) {
159 result = addr;
160 }
161 }
162 }
163 return result;
164 }
165
166 public BluetoothHeadsetProxy getHeadsetService() {
167 return mBluetoothHeadsetService;
168 }
169
170 public void setHeadsetServiceForTesting(BluetoothHeadsetProxy bluetoothHeadset) {
171 mBluetoothHeadsetService = bluetoothHeadset;
172 }
173}