BluetoothEventManager.java revision 436b29e68e6608bed9e8e7d54385b8f62d89208e
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;
47436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final IntentFilter mIntentFilter;
48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final Map<String, Handler> mHandlerMap;
49436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
50436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final Collection<BluetoothCallback> mCallbacks =
51436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            new ArrayList<BluetoothCallback>();
52436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
53436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    interface Handler {
54436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        void onReceive(Context context, Intent intent, BluetoothDevice device);
55436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
56436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
57436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void addHandler(String action, Handler handler) {
58436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mHandlerMap.put(action, handler);
59436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mIntentFilter.addAction(action);
60436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
61436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
62436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // Set profile manager after construction due to circular dependency
63436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setProfileManager(LocalBluetoothProfileManager manager) {
64436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mProfileManager = manager;
65436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
66436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
67436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothEventManager(LocalBluetoothAdapter adapter,
68436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            CachedBluetoothDeviceManager deviceManager) {
69436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mLocalAdapter = adapter;
70436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mDeviceManager = deviceManager;
71436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mIntentFilter = new IntentFilter();
72436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mHandlerMap = new HashMap<String, Handler>();
73436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
74436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        // Bluetooth on/off broadcasts
75436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
77436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        // Discovery broadcasts
78436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
79436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
80436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
81436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
82436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
83436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
84436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        // Pairing broadcasts
85436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
86436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
87436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
88436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        // Fine-grained state broadcasts
89436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
90436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
91436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
92436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        // Dock event broadcasts
93436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
94436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
95436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /**
97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * A Bluetooth-related activity is now in the foreground. Register to
98436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * start receiving Bluetooth events.
99436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * @param context a Context object for the current Activity
100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     */
101436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void resume(Context context) {
102436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mLocalAdapter.syncBluetoothState()) {
103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            // adapter state changed while we were paused: send callbacks
104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int newState = mLocalAdapter.getState();
105436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            synchronized (mCallbacks) {
106436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                for (BluetoothCallback callback : mCallbacks) {
107436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    callback.onBluetoothStateChanged(newState);
108436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
109436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
110436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
111436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        context.registerReceiver(mBroadcastReceiver, mIntentFilter);
112436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
113436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
114436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void pause(Context context) {
115436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        context.unregisterReceiver(mBroadcastReceiver);
116436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
117436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /** Register to start receiving callbacks for Bluetooth events. */
119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void registerCallback(BluetoothCallback callback) {
120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        synchronized (mCallbacks) {
121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mCallbacks.add(callback);
122436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /** Unregister to stop receiving callbacks for Bluetooth events. */
126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unregisterCallback(BluetoothCallback callback) {
127436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        synchronized (mCallbacks) {
128436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mCallbacks.remove(callback);
129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
132436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // This can't be called from a broadcast receiver where the filter is set in the Manifest.
133436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static String getDockedDeviceAddress(Context context) {
134436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        // This works only because these broadcast intents are "sticky"
135436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
136436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (i != null) {
137436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (device != null) {
141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    return device.getAddress();
142436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return null;
146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        @Override
150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent) {
151436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Log.v(TAG, "Received " + intent.getAction());
152436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            String action = intent.getAction();
154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            BluetoothDevice device = intent
155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
157436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Handler handler = mHandlerMap.get(action);
158436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (handler != null) {
159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                handler.onReceive(context, intent, device);
160436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
161436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
162436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    };
163436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
164436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class AdapterStateChangedHandler implements Handler {
165436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
167436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
168436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                                    BluetoothAdapter.ERROR);
169436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            // update local profiles and get paired devices
170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mLocalAdapter.setBluetoothStateInt(state);
171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            // send callback to update UI and possibly start scanning
172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            synchronized (mCallbacks) {
173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                for (BluetoothCallback callback : mCallbacks) {
174436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    callback.onBluetoothStateChanged(state);
175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
180436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class ScanningStateChangedHandler implements Handler {
181436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        private final boolean mStarted;
182436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
183436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        ScanningStateChangedHandler(boolean started) {
184436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mStarted = started;
185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
187436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
188436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            synchronized (mCallbacks) {
189436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                for (BluetoothCallback callback : mCallbacks) {
190436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    callback.onScanningStateChanged(mStarted);
191436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
192436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
193436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mDeviceManager.onScanningStateChanged(mStarted);
194436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
195436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
196436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
197436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
198436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class DeviceFoundHandler implements Handler {
199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
200436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
201436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
202436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
203436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
204436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            // TODO Pick up UUID. They should be available for 2.1 devices.
205436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
206436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
207436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (cachedDevice == null) {
208436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
209436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
210436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        + cachedDevice);
211436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                // callback to UI to create Preference for new device
212436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                dispatchDeviceAdded(cachedDevice);
213436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
214436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            cachedDevice.setRssi(rssi);
215436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            cachedDevice.setBtClass(btClass);
216436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            cachedDevice.setName(name);
217436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            cachedDevice.setVisible(true);
218436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
219436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
220436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
221436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
222436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        synchronized (mCallbacks) {
223436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            for (BluetoothCallback callback : mCallbacks) {
224436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                callback.onDeviceAdded(cachedDevice);
225436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
226436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
227436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
228436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
229436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class DeviceDisappearedHandler implements Handler {
230436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
231436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
232436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
233436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (cachedDevice == null) {
234436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
235436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                return;
236436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
237436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (mDeviceManager.onDeviceDisappeared(cachedDevice)) {
238436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                synchronized (mCallbacks) {
239436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    for (BluetoothCallback callback : mCallbacks) {
240436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        callback.onDeviceDeleted(cachedDevice);
241436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    }
242436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
243436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
244436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
245436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
246436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
247436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class NameChangedHandler implements Handler {
248436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
249436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
250436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mDeviceManager.onDeviceNameUpdated(device);
251436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
252436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
253436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class BondStateChangedHandler implements Handler {
255436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
257436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (device == null) {
258436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
259436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                return;
260436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
262436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                                               BluetoothDevice.ERROR);
263436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
264436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (cachedDevice == null) {
265436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.w(TAG, "CachedBluetoothDevice for device " + device +
266436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        " not found, calling readPairedDevices().");
267436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (!readPairedDevices()) {
268436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    Log.e(TAG, "Got bonding state changed for " + device +
269436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                            ", but we have no record of that device.");
270436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    return;
271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                cachedDevice = mDeviceManager.findDevice(device);
273436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (cachedDevice == null) {
274436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    Log.e(TAG, "Got bonding state changed for " + device +
275436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                            ", but device not added in cache.");
276436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    return;
277436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
278436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
279436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
280436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            synchronized (mCallbacks) {
281436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                for (BluetoothCallback callback : mCallbacks) {
282436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    callback.onDeviceBondStateChanged(cachedDevice, bondState);
283436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
284436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
285436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            cachedDevice.onBondingStateChanged(bondState);
286436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
287436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (bondState == BluetoothDevice.BOND_NONE) {
288436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (device.isBluetoothDock()) {
289436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    // After a dock is unpaired, we will forget the settings
290436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    LocalBluetoothPreferences
291436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                            .removeDockAutoConnectSetting(context, device.getAddress());
292436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
293436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    // if the device is undocked, remove it from the list as well
294436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    if (!device.getAddress().equals(getDockedDeviceAddress(context))) {
295436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        mDeviceManager.onDeviceDisappeared(cachedDevice);
296436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    }
297436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
298436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
299436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        BluetoothDevice.ERROR);
300436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
301436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                showUnbondMessage(context, cachedDevice.getName(), reason);
302436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
303436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
304436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        /**
306436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby         * Called when we have reached the unbonded state.
307436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby         *
308436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby         * @param reason one of the error reasons from
309436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby         *            BluetoothDevice.UNBOND_REASON_*
310436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby         */
311436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        private void showUnbondMessage(Context context, String name, int reason) {
312436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int errorMsg;
313436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
314436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            switch(reason) {
315436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
316436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                errorMsg = R.string.bluetooth_pairing_pin_error_message;
317436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                break;
318436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
319436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                errorMsg = R.string.bluetooth_pairing_rejected_error_message;
320436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                break;
321436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
322436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                errorMsg = R.string.bluetooth_pairing_device_down_error_message;
323436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                break;
324436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
325436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
326436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
327436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
328436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                errorMsg = R.string.bluetooth_pairing_error_message;
329436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                break;
330436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            default:
331436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason);
332436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                return;
333436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
334436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Utils.showError(context, name, errorMsg);
335436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
336436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
337436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
338436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class ClassChangedHandler implements Handler {
339436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
340436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
341436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mDeviceManager.onBtClassChanged(device);
342436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
343436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
344436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
345436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class UuidChangedHandler implements Handler {
346436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent,
347436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                BluetoothDevice device) {
348436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mDeviceManager.onUuidChanged(device);
349436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
350436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
351436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
352436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class PairingCancelHandler implements Handler {
353436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
354436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (device == null) {
355436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE");
356436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                return;
357436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
358436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int errorMsg = R.string.bluetooth_pairing_error_message;
359436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
360436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Utils.showError(context, cachedDevice.getName(), errorMsg);
361436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
362436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
363436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
364436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private class DockEventHandler implements Handler {
365436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
366436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            // Remove if unpair device upon undocking
367436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
368436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
369436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
370436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
371436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
372436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    if (cachedDevice != null) {
373436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                        mDeviceManager.onDeviceDisappeared(cachedDevice);
374436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    }
375436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
376436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
377436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
378436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
379436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
380436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean readPairedDevices() {
381436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
382436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (bondedDevices == null) {
383436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
384436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
385436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
386436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        boolean deviceAdded = false;
387436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (BluetoothDevice device : bondedDevices) {
388436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
389436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (cachedDevice == null) {
390436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
391436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                dispatchDeviceAdded(cachedDevice);
392436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                deviceAdded = true;
393436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            }
394436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
395436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby
396436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return deviceAdded;
397436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    }
398436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby}
399