CachedBluetoothDeviceManager.java revision c090feb64f674d9840993736a24f9667f8b0e0d5
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 17package com.android.settings.bluetooth; 18 19import android.bluetooth.BluetoothAdapter; 20import android.bluetooth.BluetoothClass; 21import android.bluetooth.BluetoothDevice; 22import android.util.Log; 23 24import com.android.settings.R; 25import com.android.settings.bluetooth.LocalBluetoothManager.Callback; 26import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; 27 28import java.util.ArrayList; 29import java.util.List; 30import java.util.Set; 31 32/** 33 * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices. 34 */ 35public class CachedBluetoothDeviceManager { 36 private static final String TAG = "CachedBluetoothDeviceManager"; 37 38 final LocalBluetoothManager mLocalManager; 39 final List<Callback> mCallbacks; 40 41 final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>(); 42 43 public CachedBluetoothDeviceManager(LocalBluetoothManager localManager) { 44 mLocalManager = localManager; 45 mCallbacks = localManager.getCallbacks(); 46 } 47 48 private synchronized boolean readPairedDevices() { 49 BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter(); 50 Set<BluetoothDevice> bondedDevices = adapter.getBondedDevices(); 51 if (bondedDevices == null) return false; 52 53 boolean deviceAdded = false; 54 for (BluetoothDevice device : bondedDevices) { 55 CachedBluetoothDevice cachedDevice = findDevice(device); 56 if (cachedDevice == null) { 57 cachedDevice = new CachedBluetoothDevice(mLocalManager.getContext(), device); 58 mCachedDevices.add(cachedDevice); 59 dispatchDeviceAdded(cachedDevice); 60 deviceAdded = true; 61 } 62 } 63 64 return deviceAdded; 65 } 66 67 public synchronized List<CachedBluetoothDevice> getCachedDevicesCopy() { 68 return new ArrayList<CachedBluetoothDevice>(mCachedDevices); 69 } 70 71 void onBluetoothStateChanged(boolean enabled) { 72 if (enabled) { 73 readPairedDevices(); 74 } 75 } 76 77 public synchronized void onDeviceAppeared(BluetoothDevice device, short rssi, 78 BluetoothClass btClass, String name) { 79 boolean deviceAdded = false; 80 81 CachedBluetoothDevice cachedDevice = findDevice(device); 82 if (cachedDevice == null) { 83 cachedDevice = new CachedBluetoothDevice(mLocalManager.getContext(), device); 84 mCachedDevices.add(cachedDevice); 85 deviceAdded = true; 86 } 87 cachedDevice.setRssi(rssi); 88 cachedDevice.setBtClass(btClass); 89 cachedDevice.setName(name); 90 cachedDevice.setVisible(true); 91 92 if (deviceAdded) { 93 dispatchDeviceAdded(cachedDevice); 94 } 95 } 96 97 public synchronized void onDeviceDisappeared(BluetoothDevice device) { 98 CachedBluetoothDevice cachedDevice = findDevice(device); 99 if (cachedDevice == null) return; 100 101 cachedDevice.setVisible(false); 102 checkForDeviceRemoval(cachedDevice); 103 } 104 105 private void checkForDeviceRemoval(CachedBluetoothDevice cachedDevice) { 106 if (cachedDevice.getBondState() == BluetoothDevice.BOND_NONE && 107 !cachedDevice.isVisible()) { 108 // If device isn't paired, remove it altogether 109 mCachedDevices.remove(cachedDevice); 110 dispatchDeviceDeleted(cachedDevice); 111 } 112 } 113 114 public synchronized void onDeviceNameUpdated(BluetoothDevice device) { 115 CachedBluetoothDevice cachedDevice = findDevice(device); 116 if (cachedDevice != null) { 117 cachedDevice.refreshName(); 118 } 119 } 120 121 public synchronized CachedBluetoothDevice findDevice(BluetoothDevice device) { 122 123 for (int i = mCachedDevices.size() - 1; i >= 0; i--) { 124 CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); 125 126 if (cachedDevice.getDevice().equals(device)) { 127 return cachedDevice; 128 } 129 } 130 131 return null; 132 } 133 134 /** 135 * Attempts to get the name of a remote device, otherwise returns the address. 136 * 137 * @param device The remote device. 138 * @return The name, or if unavailable, the address. 139 */ 140 public String getName(BluetoothDevice device) { 141 CachedBluetoothDevice cachedDevice = findDevice(device); 142 if (cachedDevice != null) return cachedDevice.getName(); 143 144 String name = device.getName(); 145 if (name != null) return name; 146 147 return device.getAddress(); 148 } 149 150 private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) { 151 synchronized (mCallbacks) { 152 for (Callback callback : mCallbacks) { 153 callback.onDeviceAdded(cachedDevice); 154 } 155 } 156 157 // TODO: divider between prev paired/connected and scanned 158 } 159 160 private void dispatchDeviceDeleted(CachedBluetoothDevice cachedDevice) { 161 synchronized (mCallbacks) { 162 for (Callback callback : mCallbacks) { 163 callback.onDeviceDeleted(cachedDevice); 164 } 165 } 166 } 167 168 private void dispatchDeviceBondStateChanged( 169 CachedBluetoothDevice cachedDevice, int bondState) { 170 synchronized (mCallbacks) { 171 for (Callback callback : mCallbacks) { 172 callback.onDeviceBondStateChanged(cachedDevice, bondState); 173 } 174 } 175 } 176 177 public synchronized void onBondingStateChanged(BluetoothDevice device, int bondState) { 178 CachedBluetoothDevice cachedDevice = findDevice(device); 179 if (cachedDevice == null) { 180 if (!readPairedDevices()) { 181 Log.e(TAG, "Got bonding state changed for " + device + 182 ", but we have no record of that device."); 183 return; 184 } 185 cachedDevice = findDevice(device); 186 if (cachedDevice == null) { 187 Log.e(TAG, "Got bonding state changed for " + device + 188 ", but device not added in cache."); 189 return; 190 } 191 } 192 193 dispatchDeviceBondStateChanged(cachedDevice, bondState); 194 cachedDevice.onBondingStateChanged(bondState); 195 } 196 197 /** 198 * Called when we have reached the un-bond state. 199 * 200 * @param device The remote device. 201 * @param reason The reason, one of the error reasons from 202 * BluetoothDevice.UNBOND_REASON_* 203 */ 204 public synchronized void showUnbondMessage(BluetoothDevice device, int reason) { 205 int errorMsg; 206 207 switch(reason) { 208 case BluetoothDevice.UNBOND_REASON_AUTH_FAILED: 209 errorMsg = R.string.bluetooth_pairing_pin_error_message; 210 mLocalManager.showError(device, R.string.bluetooth_error_title, errorMsg); 211 break; 212 case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED: 213 errorMsg = R.string.bluetooth_pairing_rejected_error_message; 214 mLocalManager.showError(device, R.string.bluetooth_error_title, errorMsg); 215 break; 216 case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN: 217 errorMsg = R.string.bluetooth_pairing_device_down_error_message; 218 mLocalManager.showError(device, R.string.bluetooth_error_title, errorMsg); 219 break; 220 case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS: 221 case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT: 222 case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS: 223 case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED: 224 errorMsg = R.string.bluetooth_pairing_error_message; 225 mLocalManager.showError(device, R.string.bluetooth_error_title, errorMsg); 226 break; 227 default: 228 Log.w(TAG, "showUnbondMessage: Not displaying any message for reason:" + reason); 229 break; 230 } 231 } 232 233 public synchronized void onProfileStateChanged(BluetoothDevice device, Profile profile, 234 int newProfileState) { 235 CachedBluetoothDevice cachedDevice = findDevice(device); 236 if (cachedDevice == null) return; 237 238 cachedDevice.onProfileStateChanged(profile, newProfileState); 239 cachedDevice.refresh(); 240 } 241 242 public synchronized void onConnectingError(BluetoothDevice device) { 243 CachedBluetoothDevice cachedDevice = findDevice(device); 244 if (cachedDevice == null) return; 245 246 /* 247 * Go through the device's delegate so we don't spam the user with 248 * errors connecting to different profiles, and instead make sure the 249 * user sees a single error for his single 'connect' action. 250 */ 251 cachedDevice.showConnectingError(); 252 } 253 254 public synchronized void onScanningStateChanged(boolean started) { 255 if (!started) return; 256 257 // If starting a new scan, clear old visibility 258 for (int i = mCachedDevices.size() - 1; i >= 0; i--) { 259 CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); 260 cachedDevice.setVisible(false); 261 checkForDeviceRemoval(cachedDevice); 262 } 263 } 264 265 public synchronized void onBtClassChanged(BluetoothDevice device) { 266 CachedBluetoothDevice cachedDevice = findDevice(device); 267 if (cachedDevice != null) { 268 cachedDevice.refreshBtClass(); 269 } 270 } 271 272 public synchronized void onUuidChanged(BluetoothDevice device) { 273 CachedBluetoothDevice cachedDevice = findDevice(device); 274 if (cachedDevice != null) { 275 cachedDevice.onUuidChanged(); 276 } 277 } 278} 279