1436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby/* 2436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Copyright (C) 2011 The Android Open Source Project 3436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 4436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Licensed under the Apache License, Version 2.0 (the "License"); 5436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * you may not use this file except in compliance with the License. 6436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * You may obtain a copy of the License at 7436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 8436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * http://www.apache.org/licenses/LICENSE-2.0 9436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 10436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Unless required by applicable law or agreed to in writing, software 11436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * distributed under the License is distributed on an "AS IS" BASIS, 12436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * See the License for the specific language governing permissions and 14436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * limitations under the License. 15436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 16436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 17436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambypackage com.android.settings.bluetooth; 18436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 19436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport com.android.settings.R; 20436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 21436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothAdapter; 22436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothClass; 23436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothDevice; 24436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.BroadcastReceiver; 25436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Context; 26436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Intent; 27436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.IntentFilter; 28436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.util.Log; 29436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 30436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.ArrayList; 31436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Collection; 32436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.HashMap; 33436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Map; 34436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Set; 35436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 36436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby/** 37436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth 38436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * API and dispatches the event on the UI thread to the right class in the 39436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Settings. 40436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 41436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyfinal class BluetoothEventManager { 42436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static final String TAG = "BluetoothEventManager"; 43436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final LocalBluetoothAdapter mLocalAdapter; 45436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final CachedBluetoothDeviceManager mDeviceManager; 46436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private LocalBluetoothProfileManager mProfileManager; 476eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter; 48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Map<String, Handler> mHandlerMap; 496eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh private Context mContext; 50436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 51436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Collection<BluetoothCallback> mCallbacks = 52436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby new ArrayList<BluetoothCallback>(); 53436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 54436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby interface Handler { 55436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void onReceive(Context context, Intent intent, BluetoothDevice device); 56436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 57436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 58436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void addHandler(String action, Handler handler) { 59436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHandlerMap.put(action, handler); 606eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mAdapterIntentFilter.addAction(action); 616eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh } 626eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh 636eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh void addProfileHandler(String action, Handler handler) { 646eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mHandlerMap.put(action, handler); 656eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mProfileIntentFilter.addAction(action); 66436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 67436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 68436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Set profile manager after construction due to circular dependency 69436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void setProfileManager(LocalBluetoothProfileManager manager) { 70436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileManager = manager; 71436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 72436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 73436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothEventManager(LocalBluetoothAdapter adapter, 746eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh CachedBluetoothDeviceManager deviceManager, Context context) { 75436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mLocalAdapter = adapter; 76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager = deviceManager; 776eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mAdapterIntentFilter = new IntentFilter(); 786eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mProfileIntentFilter = new IntentFilter(); 79436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHandlerMap = new HashMap<String, Handler>(); 806eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mContext = context; 81436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 82436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Bluetooth on/off broadcasts 83436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler()); 84436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 85436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Discovery broadcasts 86436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true)); 87436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false)); 88436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler()); 89436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler()); 90436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler()); 91436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 92436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Pairing broadcasts 93436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler()); 94436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler()); 95436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Fine-grained state broadcasts 97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler()); 98436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler()); 99436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Dock event broadcasts 101436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler()); 1026eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter); 103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 1056eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh void registerProfileIntentReceiver() { 1066eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter); 107436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 108436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 109436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** Register to start receiving callbacks for Bluetooth events. */ 110436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void registerCallback(BluetoothCallback callback) { 111436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 112436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mCallbacks.add(callback); 113436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 114436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 115436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 116436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** Unregister to stop receiving callbacks for Bluetooth events. */ 117436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void unregisterCallback(BluetoothCallback callback) { 118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mCallbacks.remove(callback); 120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 122436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // This can't be called from a broadcast receiver where the filter is set in the Manifest. 124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static String getDockedDeviceAddress(Context context) { 125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // This works only because these broadcast intents are "sticky" 126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); 127436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (i != null) { 128436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); 129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { 130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (device != null) { 132436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return device.getAddress(); 133436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 134436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 135436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 136436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return null; 137436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby @Override 141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent) { 142436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.v(TAG, "Received " + intent.getAction()); 143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby String action = intent.getAction(); 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device = intent 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Handler handler = mHandlerMap.get(action); 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (handler != null) { 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby handler.onReceive(context, intent, device); 151436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 152436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby }; 154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class AdapterStateChangedHandler implements Handler { 156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 157436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 158436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothAdapter.ERROR); 160436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // update local profiles and get paired devices 161436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mLocalAdapter.setBluetoothStateInt(state); 162436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // send callback to update UI and possibly start scanning 163436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 164436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothCallback callback : mCallbacks) { 165436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby callback.onBluetoothStateChanged(state); 166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 167436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 168436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 169436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class ScanningStateChangedHandler implements Handler { 172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final boolean mStarted; 173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 174436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ScanningStateChangedHandler(boolean started) { 175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mStarted = started; 176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 180436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothCallback callback : mCallbacks) { 181436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby callback.onScanningStateChanged(mStarted); 182436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 183436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 184436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager.onScanningStateChanged(mStarted); 185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothPreferences.persistDiscoveringTimestamp(context); 186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 187436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 188436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 189436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class DeviceFoundHandler implements Handler { 190436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 191436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 192436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE); 193436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS); 194436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME); 195436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // TODO Pick up UUID. They should be available for 2.1 devices. 196436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1. 197436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 198436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device); 200436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: " 201436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby + cachedDevice); 202436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // callback to UI to create Preference for new device 203436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby dispatchDeviceAdded(cachedDevice); 204436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 205436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.setRssi(rssi); 206436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.setBtClass(btClass); 207436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.setName(name); 208436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.setVisible(true); 209436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 210436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 211436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 212436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) { 213436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 214436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothCallback callback : mCallbacks) { 215436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby callback.onDeviceAdded(cachedDevice); 216436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 217436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 218436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 219436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 220436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class DeviceDisappearedHandler implements Handler { 221436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 222436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 223436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 224436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 225436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device); 226436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 227436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 22879be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) { 229436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 230436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothCallback callback : mCallbacks) { 231436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby callback.onDeviceDeleted(cachedDevice); 232436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 233436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 234436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 235436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 236436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 237436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 238436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class NameChangedHandler implements Handler { 239436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 240436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 241436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager.onDeviceNameUpdated(device); 242436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 243436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 244436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 245436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class BondStateChangedHandler implements Handler { 246436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 247436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 248436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (device == null) { 249436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE"); 250436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 251436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 252436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 253436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice.ERROR); 254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 255436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "CachedBluetoothDevice for device " + device + 257436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby " not found, calling readPairedDevices()."); 258436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (!readPairedDevices()) { 259436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.e(TAG, "Got bonding state changed for " + device + 260436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ", but we have no record of that device."); 261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 262436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 263436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice = mDeviceManager.findDevice(device); 264436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 265436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.e(TAG, "Got bonding state changed for " + device + 266436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ", but device not added in cache."); 267436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 268436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 269436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 270436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (mCallbacks) { 272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothCallback callback : mCallbacks) { 273436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby callback.onDeviceBondStateChanged(cachedDevice, bondState); 274436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 275436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 276436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.onBondingStateChanged(bondState); 277436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 278436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (bondState == BluetoothDevice.BOND_NONE) { 279436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (device.isBluetoothDock()) { 280436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // After a dock is unpaired, we will forget the settings 281436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothPreferences 282436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby .removeDockAutoConnectSetting(context, device.getAddress()); 283436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 284436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // if the device is undocked, remove it from the list as well 285436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (!device.getAddress().equals(getDockedDeviceAddress(context))) { 28679be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby cachedDevice.setVisible(false); 287436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 288436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 289436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON, 290436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice.ERROR); 291436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 292436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby showUnbondMessage(context, cachedDevice.getName(), reason); 293436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 294436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 295436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 296436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** 297436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Called when we have reached the unbonded state. 298436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 299436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param reason one of the error reasons from 300436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * BluetoothDevice.UNBOND_REASON_* 301436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 302436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private void showUnbondMessage(Context context, String name, int reason) { 303436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int errorMsg; 304436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby switch(reason) { 306436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_AUTH_FAILED: 307436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby errorMsg = R.string.bluetooth_pairing_pin_error_message; 308436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby break; 309436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED: 310436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby errorMsg = R.string.bluetooth_pairing_rejected_error_message; 311436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby break; 312436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN: 313436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby errorMsg = R.string.bluetooth_pairing_device_down_error_message; 314436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby break; 315436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS: 316436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT: 317436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS: 318436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED: 319436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby errorMsg = R.string.bluetooth_pairing_error_message; 320436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby break; 321436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby default: 322436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason); 323436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 324436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 325436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Utils.showError(context, name, errorMsg); 326436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 327436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 328436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 329436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class ClassChangedHandler implements Handler { 330436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 331436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 332436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager.onBtClassChanged(device); 333436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 334436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 335436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 336436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class UuidChangedHandler implements Handler { 337436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, 338436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothDevice device) { 339436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager.onUuidChanged(device); 340436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 341436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 342436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 343436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class PairingCancelHandler implements Handler { 344436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, BluetoothDevice device) { 345436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (device == null) { 346436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE"); 347436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 348436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 349436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int errorMsg = R.string.bluetooth_pairing_error_message; 350436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 351436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Utils.showError(context, cachedDevice.getName(), errorMsg); 352436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 353436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 354436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 355436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class DockEventHandler implements Handler { 356436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, BluetoothDevice device) { 357436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Remove if unpair device upon undocking 358436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1; 359436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked); 360436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) { 361436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) { 362436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 363436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice != null) { 36479be0b3e6b5639c4cbe2bbcd9adb0ec4c28716edJake Hamby cachedDevice.setVisible(false); 365436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 366436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 367436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 368436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 369436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 370436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 371436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby boolean readPairedDevices() { 372436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices(); 373436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (bondedDevices == null) { 374436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return false; 375436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 376436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 377436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby boolean deviceAdded = false; 378436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (BluetoothDevice device : bondedDevices) { 379436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 380436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 381436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device); 382436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby dispatchDeviceAdded(cachedDevice); 383436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby deviceAdded = true; 384436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 385436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 386436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 387436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return deviceAdded; 388436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 389436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby} 390