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