1 /*
2  * Copyright (C) 2008 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.settings.bluetooth;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothDevice;
21 import android.content.Context;
22 import android.util.Log;
23 
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.List;
27 
28 /**
29  * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
30  */
31 final class CachedBluetoothDeviceManager {
32     private static final String TAG = "CachedBluetoothDeviceManager";
33     private static final boolean DEBUG = Utils.D;
34 
35     private Context mContext;
36     private final List<CachedBluetoothDevice> mCachedDevices =
37             new ArrayList<CachedBluetoothDevice>();
38 
CachedBluetoothDeviceManager(Context context)39     CachedBluetoothDeviceManager(Context context) {
40         mContext = context;
41     }
42 
getCachedDevicesCopy()43     public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
44         return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
45     }
46 
onDeviceDisappeared(CachedBluetoothDevice cachedDevice)47     public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
48         cachedDevice.setVisible(false);
49         return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
50     }
51 
onDeviceNameUpdated(BluetoothDevice device)52     public void onDeviceNameUpdated(BluetoothDevice device) {
53         CachedBluetoothDevice cachedDevice = findDevice(device);
54         if (cachedDevice != null) {
55             cachedDevice.refreshName();
56         }
57     }
58 
59     /**
60      * Search for existing {@link CachedBluetoothDevice} or return null
61      * if this device isn't in the cache. Use {@link #addDevice}
62      * to create and return a new {@link CachedBluetoothDevice} for
63      * a newly discovered {@link BluetoothDevice}.
64      *
65      * @param device the address of the Bluetooth device
66      * @return the cached device object for this device, or null if it has
67      *   not been previously seen
68      */
findDevice(BluetoothDevice device)69     CachedBluetoothDevice findDevice(BluetoothDevice device) {
70         for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
71             if (cachedDevice.getDevice().equals(device)) {
72                 return cachedDevice;
73             }
74         }
75         return null;
76     }
77 
78     /**
79      * Create and return a new {@link CachedBluetoothDevice}. This assumes
80      * that {@link #findDevice} has already been called and returned null.
81      * @param device the address of the new Bluetooth device
82      * @return the newly created CachedBluetoothDevice object
83      */
addDevice(LocalBluetoothAdapter adapter, LocalBluetoothProfileManager profileManager, BluetoothDevice device)84     CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter,
85             LocalBluetoothProfileManager profileManager,
86             BluetoothDevice device) {
87         CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter,
88             profileManager, device);
89         synchronized (mCachedDevices) {
90             mCachedDevices.add(newDevice);
91         }
92         return newDevice;
93     }
94 
95     /**
96      * Attempts to get the name of a remote device, otherwise returns the address.
97      *
98      * @param device The remote device.
99      * @return The name, or if unavailable, the address.
100      */
getName(BluetoothDevice device)101     public String getName(BluetoothDevice device) {
102         CachedBluetoothDevice cachedDevice = findDevice(device);
103         if (cachedDevice != null) {
104             return cachedDevice.getName();
105         }
106 
107         String name = device.getAliasName();
108         if (name != null) {
109             return name;
110         }
111 
112         return device.getAddress();
113     }
114 
clearNonBondedDevices()115     public synchronized void clearNonBondedDevices() {
116         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
117             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
118             if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
119                 mCachedDevices.remove(i);
120             }
121         }
122     }
123 
onScanningStateChanged(boolean started)124     public synchronized void onScanningStateChanged(boolean started) {
125         if (!started) return;
126 
127         // If starting a new scan, clear old visibility
128         // Iterate in reverse order since devices may be removed.
129         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
130             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
131             cachedDevice.setVisible(false);
132         }
133     }
134 
onBtClassChanged(BluetoothDevice device)135     public synchronized void onBtClassChanged(BluetoothDevice device) {
136         CachedBluetoothDevice cachedDevice = findDevice(device);
137         if (cachedDevice != null) {
138             cachedDevice.refreshBtClass();
139         }
140     }
141 
onUuidChanged(BluetoothDevice device)142     public synchronized void onUuidChanged(BluetoothDevice device) {
143         CachedBluetoothDevice cachedDevice = findDevice(device);
144         if (cachedDevice != null) {
145             cachedDevice.onUuidChanged();
146         }
147     }
148 
onBluetoothStateChanged(int bluetoothState)149     public synchronized void onBluetoothStateChanged(int bluetoothState) {
150         // When Bluetooth is turning off, we need to clear the non-bonded devices
151         // Otherwise, they end up showing up on the next BT enable
152         if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
153             for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
154                 CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
155                 if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
156                     cachedDevice.setVisible(false);
157                     mCachedDevices.remove(i);
158                 } else {
159                     // For bonded devices, we need to clear the connection status so that
160                     // when BT is enabled next time, device connection status shall be retrieved
161                     // by making a binder call.
162                     cachedDevice.clearProfileConnectionState();
163                 }
164             }
165         }
166     }
log(String msg)167     private void log(String msg) {
168         if (DEBUG) {
169             Log.d(TAG, msg);
170         }
171     }
172 }
173