17ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk/*
27ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Copyright (C) 2011 The Android Open Source Project
37ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *
47ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
57ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * you may not use this file except in compliance with the License.
67ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * You may obtain a copy of the License at
77ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *
87ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
97ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *
107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Unless required by applicable law or agreed to in writing, software
117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * See the License for the specific language governing permissions and
147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * limitations under the License.
157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk */
167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkpackage com.android.settingslib.bluetooth;
187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothAdapter;
207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothClass;
217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothDevice;
227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.BroadcastReceiver;
237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.Context;
247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.Intent;
257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.IntentFilter;
267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.util.Log;
277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport com.android.settingslib.R;
297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.ArrayList;
317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.Collection;
327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.HashMap;
337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.Map;
347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.Set;
357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk/**
377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth
387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * API and dispatches the event on the UI thread to the right class in the
397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Settings.
407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk */
417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkpublic final class BluetoothEventManager {
427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private static final String TAG = "BluetoothEventManager";
437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final LocalBluetoothAdapter mLocalAdapter;
457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final CachedBluetoothDeviceManager mDeviceManager;
467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private LocalBluetoothProfileManager mProfileManager;
477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter;
487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final Map<String, Handler> mHandlerMap;
497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private Context mContext;
507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final Collection<BluetoothCallback> mCallbacks =
527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            new ArrayList<BluetoothCallback>();
537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
54744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk    private android.os.Handler mReceiverHandler;
55744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk
567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    interface Handler {
577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        void onReceive(Context context, Intent intent, BluetoothDevice device);
587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
60744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk    private void addHandler(String action, Handler handler) {
617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mHandlerMap.put(action, handler);
627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mAdapterIntentFilter.addAction(action);
637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void addProfileHandler(String action, Handler handler) {
667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mHandlerMap.put(action, handler);
677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mProfileIntentFilter.addAction(action);
687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // Set profile manager after construction due to circular dependency
717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void setProfileManager(LocalBluetoothProfileManager manager) {
727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mProfileManager = manager;
737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    BluetoothEventManager(LocalBluetoothAdapter adapter,
767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDeviceManager deviceManager, Context context) {
777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mLocalAdapter = adapter;
787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mDeviceManager = deviceManager;
797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mAdapterIntentFilter = new IntentFilter();
807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mProfileIntentFilter = new IntentFilter();
817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mHandlerMap = new HashMap<String, Handler>();
827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mContext = context;
837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Bluetooth on/off broadcasts
857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
86be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        // Generic connected/not broadcast
87be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        addHandler(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED,
88be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk                new ConnectionStateChangedHandler());
897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Discovery broadcasts
917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
968c495be48fc6973cc291fb4e6200154e2f28d571Jason Monk        addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());
977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Pairing broadcasts
997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
1007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
1017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Fine-grained state broadcasts
1037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
1047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
1057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Dock event broadcasts
1077ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
1087ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
109744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
1107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void registerProfileIntentReceiver() {
113744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk        mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
114744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk    }
115744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk
116744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk    public void setReceiverHandler(android.os.Handler handler) {
117744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk        mContext.unregisterReceiver(mBroadcastReceiver);
118744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk        mReceiverHandler = handler;
119744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
120744cf647f71b1e5a012a90ef195bf2c3c486f418Jason Monk        registerProfileIntentReceiver();
1217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /** Register to start receiving callbacks for Bluetooth events. */
1247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public void registerCallback(BluetoothCallback callback) {
1257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        synchronized (mCallbacks) {
1267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mCallbacks.add(callback);
1277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /** Unregister to stop receiving callbacks for Bluetooth events. */
1317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public void unregisterCallback(BluetoothCallback callback) {
1327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        synchronized (mCallbacks) {
1337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mCallbacks.remove(callback);
1347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        @Override
1397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent) {
1407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            String action = intent.getAction();
1417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            BluetoothDevice device = intent
1427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
1437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Handler handler = mHandlerMap.get(action);
1457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (handler != null) {
1467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                handler.onReceive(context, intent, device);
1477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
1487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    };
1507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class AdapterStateChangedHandler implements Handler {
1527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
1537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
1547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
1557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                                    BluetoothAdapter.ERROR);
1567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            // update local profiles and get paired devices
1577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mLocalAdapter.setBluetoothStateInt(state);
1587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            // send callback to update UI and possibly start scanning
1597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            synchronized (mCallbacks) {
1607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                for (BluetoothCallback callback : mCallbacks) {
1617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    callback.onBluetoothStateChanged(state);
1627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
1637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
1647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            // Inform CachedDeviceManager that the adapter state has changed
1657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mDeviceManager.onBluetoothStateChanged(state);
1667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class ScanningStateChangedHandler implements Handler {
1707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        private final boolean mStarted;
1717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        ScanningStateChangedHandler(boolean started) {
1737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mStarted = started;
1747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
1767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
1777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            synchronized (mCallbacks) {
1787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                for (BluetoothCallback callback : mCallbacks) {
1797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    callback.onScanningStateChanged(mStarted);
1807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
1817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
1827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mDeviceManager.onScanningStateChanged(mStarted);
1837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class DeviceFoundHandler implements Handler {
1877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
1887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
1897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
1907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
1917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
1927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            // TODO Pick up UUID. They should be available for 2.1 devices.
1937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
1947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
1957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (cachedDevice == null) {
1967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
1977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
1987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        + cachedDevice);
1997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.setRssi(rssi);
2017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.setBtClass(btClass);
2027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.setNewName(name);
2037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.setVisible(true);
2047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
207be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk    private class ConnectionStateChangedHandler implements Handler {
208be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        @Override
209be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
210be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
211be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
212be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk                    BluetoothAdapter.ERROR);
213be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk            dispatchConnectionStateChanged(cachedDevice, state);
214be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        }
215be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk    }
216be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk
217be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk    private void dispatchConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
218be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        synchronized (mCallbacks) {
219be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk            for (BluetoothCallback callback : mCallbacks) {
220be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk                callback.onConnectionStateChanged(cachedDevice, state);
221be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk            }
222be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk        }
223be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk    }
224be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk
225be3c5dbee66758517a8198f98ed2e20c80af326bJason Monk    void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
2267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        synchronized (mCallbacks) {
2277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            for (BluetoothCallback callback : mCallbacks) {
2287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                callback.onDeviceAdded(cachedDevice);
2297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class DeviceDisappearedHandler implements Handler {
2347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
2357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
2367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
2377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (cachedDevice == null) {
2387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
2397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                return;
2407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) {
2427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                synchronized (mCallbacks) {
2437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    for (BluetoothCallback callback : mCallbacks) {
2447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        callback.onDeviceDeleted(cachedDevice);
2457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    }
2467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
2477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class NameChangedHandler implements Handler {
2527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
2537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
2547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mDeviceManager.onDeviceNameUpdated(device);
2557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class BondStateChangedHandler implements Handler {
2597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
2607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
2617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (device == null) {
2627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
2637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                return;
2647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
2667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                                               BluetoothDevice.ERROR);
2677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
2687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (cachedDevice == null) {
2697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.w(TAG, "CachedBluetoothDevice for device " + device +
2707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        " not found, calling readPairedDevices().");
2717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                if (!readPairedDevices()) {
2727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    Log.e(TAG, "Got bonding state changed for " + device +
2737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                            ", but we have no record of that device.");
2747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    return;
2757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
2767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                cachedDevice = mDeviceManager.findDevice(device);
2777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                if (cachedDevice == null) {
2787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    Log.e(TAG, "Got bonding state changed for " + device +
2797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                            ", but device not added in cache.");
2807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    return;
2817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
2827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            synchronized (mCallbacks) {
2857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                for (BluetoothCallback callback : mCallbacks) {
2867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    callback.onDeviceBondStateChanged(cachedDevice, bondState);
2877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
2887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.onBondingStateChanged(bondState);
2907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (bondState == BluetoothDevice.BOND_NONE) {
2927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
2937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        BluetoothDevice.ERROR);
2947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                showUnbondMessage(context, cachedDevice.getName(), reason);
2967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        /**
3007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * Called when we have reached the unbonded state.
3017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         *
3027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * @param reason one of the error reasons from
3037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         *            BluetoothDevice.UNBOND_REASON_*
3047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         */
3057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        private void showUnbondMessage(Context context, String name, int reason) {
3067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int errorMsg;
3077ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3087ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            switch(reason) {
3097ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
3107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                errorMsg = R.string.bluetooth_pairing_pin_error_message;
3117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                break;
3127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
3137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                errorMsg = R.string.bluetooth_pairing_rejected_error_message;
3147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                break;
3157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
3167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                errorMsg = R.string.bluetooth_pairing_device_down_error_message;
3177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                break;
3187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
3197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
3207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
3217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
3227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                errorMsg = R.string.bluetooth_pairing_error_message;
3237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                break;
3247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            default:
3257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason);
3267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                return;
3277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
3287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Utils.showError(context, name, errorMsg);
3297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class ClassChangedHandler implements Handler {
3337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
3347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
3357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mDeviceManager.onBtClassChanged(device);
3367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class UuidChangedHandler implements Handler {
3407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent,
3417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothDevice device) {
3427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mDeviceManager.onUuidChanged(device);
3437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class PairingCancelHandler implements Handler {
3477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
3487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (device == null) {
3497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE");
3507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                return;
3517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
3527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
353d2b033aeb4123ec92892495c262e0272ffb7ecdcPavlin Radoslavov            if (cachedDevice == null) {
354d2b033aeb4123ec92892495c262e0272ffb7ecdcPavlin Radoslavov                Log.e(TAG, "ACTION_PAIRING_CANCEL with no cached device");
355d2b033aeb4123ec92892495c262e0272ffb7ecdcPavlin Radoslavov                return;
356d2b033aeb4123ec92892495c262e0272ffb7ecdcPavlin Radoslavov            }
357d2b033aeb4123ec92892495c262e0272ffb7ecdcPavlin Radoslavov            int errorMsg = R.string.bluetooth_pairing_error_message;
3584d08a485db5021638b0abcb8675ba00579bd7fccSanket Padawe            if (context != null && cachedDevice != null) {
3594d08a485db5021638b0abcb8675ba00579bd7fccSanket Padawe                Utils.showError(context, cachedDevice.getName(), errorMsg);
3604d08a485db5021638b0abcb8675ba00579bd7fccSanket Padawe            }
3617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class DockEventHandler implements Handler {
3657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
3667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            // Remove if unpair device upon undocking
3677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
3687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
3697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
3707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
3717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
3727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    if (cachedDevice != null) {
3737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        cachedDevice.setVisible(false);
3747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    }
3757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                }
3767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
3777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    boolean readPairedDevices() {
3807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
3817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (bondedDevices == null) {
3827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            return false;
3837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        boolean deviceAdded = false;
3867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        for (BluetoothDevice device : bondedDevices) {
3877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
3887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (cachedDevice == null) {
3897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
3907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                dispatchDeviceAdded(cachedDevice);
3917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                deviceAdded = true;
3927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
3937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return deviceAdded;
3967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk}
398