• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server.telecom.bluetooth;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.bluetooth.BluetoothHeadset;
21 import android.bluetooth.BluetoothProfile;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.telecom.Log;
27 
28 import com.android.server.telecom.BluetoothAdapterProxy;
29 import com.android.server.telecom.BluetoothHeadsetProxy;
30 import com.android.server.telecom.TelecomSystem;
31 
32 import java.util.Collection;
33 import java.util.LinkedHashMap;
34 import java.util.LinkedList;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Objects;
38 import java.util.stream.Collectors;
39 
40 public 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;
68                             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                             }
76                         }
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 
BluetoothDeviceManager(Context context, BluetoothAdapterProxy bluetoothAdapter, TelecomSystem.SyncRoot lock)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 
setBluetoothRouteManager(BluetoothRouteManager brm)146     public void setBluetoothRouteManager(BluetoothRouteManager brm) {
147         mBluetoothRouteManager = brm;
148     }
149 
getNumConnectedDevices()150     public int getNumConnectedDevices() {
151         return mConnectedDevicesByAddress.size();
152     }
153 
getMostRecentlyConnectedDevice(String excludeAddress)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 
getHeadsetService()166     public BluetoothHeadsetProxy getHeadsetService() {
167         return mBluetoothHeadsetService;
168     }
169 
setHeadsetServiceForTesting(BluetoothHeadsetProxy bluetoothHeadset)170     public void setHeadsetServiceForTesting(BluetoothHeadsetProxy bluetoothHeadset) {
171         mBluetoothHeadsetService = bluetoothHeadset;
172     }
173 }
174