CachedBluetoothDevice.java revision d97daa064b35ee0c2b73547d46f97fa88d2da4e9
1afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/*
2afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *
4afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * you may not use this file except in compliance with the License.
6afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * You may obtain a copy of the License at
7afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *
8afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *
10afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * See the License for the specific language governing permissions and
14afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * limitations under the License.
15afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */
16afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
17afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectpackage com.android.settings.bluetooth;
18afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
19afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.app.AlertDialog;
20afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.bluetooth.BluetoothClass;
21e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
22afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.Context;
23afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.DialogInterface;
24afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.Intent;
25afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.res.Resources;
26afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.text.TextUtils;
27afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.util.Log;
28afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.ContextMenu;
29afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.Menu;
30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.MenuItem;
31afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
326c97742c88303c65e68fe08257a7ccf841f03866Michael Chanimport com.android.settings.R;
336c97742c88303c65e68fe08257a7ccf841f03866Michael Chanimport com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
346c97742c88303c65e68fe08257a7ccf841f03866Michael Chan
35e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.text.DateFormat;
36afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.ArrayList;
37e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.util.Date;
38e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.util.Iterator;
39e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.util.LinkedList;
40afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.List;
41afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
42afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/**
43afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * LocalBluetoothDevice represents a remote Bluetooth device. It contains
44afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * attributes of the device (such as the address, name, RSSI, etc.) and
45afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * functionality that can be performed on the device (connect, pair, disconnect,
46afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * etc.).
47afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */
48afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectpublic class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
49afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private static final String TAG = "LocalBluetoothDevice";
50f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan    private static final boolean D = LocalBluetoothManager.D;
51f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan    private static final boolean V = LocalBluetoothManager.V;
52afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
53afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private static final int CONTEXT_ITEM_CONNECT = Menu.FIRST + 1;
54afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private static final int CONTEXT_ITEM_DISCONNECT = Menu.FIRST + 2;
55afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private static final int CONTEXT_ITEM_UNPAIR = Menu.FIRST + 3;
56afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private static final int CONTEXT_ITEM_CONNECT_ADVANCED = Menu.FIRST + 4;
57afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
58afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private final String mAddress;
59afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private String mName;
60afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private short mRssi;
61afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private int mBtClass = BluetoothClass.ERROR;
62afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
63afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private List<Profile> mProfiles = new ArrayList<Profile>();
64afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
65afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mVisible;
66afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
67afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private final LocalBluetoothManager mLocalManager;
68afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
69afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private List<Callback> mCallbacks = new ArrayList<Callback>();
70afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
71afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
72afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * When we connect to multiple profiles, we only want to display a single
73afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * error even if they all fail. This tracks that state.
74afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
75afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mIsConnectingErrorPossible;
76afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
77e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    // Max time to hold the work queue if we don't get or missed a response
78e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    // from the bt framework.
79e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private static final long MAX_WAIT_TIME_FOR_FRAMEWORK = 25 * 1000;
80e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
81e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private enum BluetoothCommand {
82e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        CONNECT, DISCONNECT,
83e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
84e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
858762093e0094e09493fa6cbac8e8fbf265f18165Michael Chan    static class BluetoothJob {
86e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        final BluetoothCommand command; // CONNECT, DISCONNECT
87e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        final LocalBluetoothDevice device;
88e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        final Profile profile; // HEADSET, A2DP, etc
89e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        // 0 means this command was not been sent to the bt framework.
90e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        long timeSent;
91e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
92e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        public BluetoothJob(BluetoothCommand command,
93e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                LocalBluetoothDevice device, Profile profile) {
94e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            this.command = command;
95e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            this.device = device;
96e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            this.profile = profile;
97e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            this.timeSent = 0;
98e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
99d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
100e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        @Override
101e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        public String toString() {
102e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            StringBuilder sb = new StringBuilder();
103e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            sb.append(command.name());
104e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            sb.append(" Address:").append(device.mAddress);
105e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            sb.append(" Profile:").append(profile.name());
106e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            sb.append(" TimeSent:");
107e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (timeSent == 0) {
108e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                sb.append("not yet");
109e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            } else {
110e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                sb.append(DateFormat.getTimeInstance().format(new Date(timeSent)));
111e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
112e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            return sb.toString();
113e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
114e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
115e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
116e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    /**
117e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * We want to serialize connect and disconnect calls. http://b/170538
118e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * This are some headsets that may have L2CAP resource limitation. We want
119e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * to limit the bt bandwidth usage.
120e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     *
121e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * A queue to keep track of asynchronous calls to the bt framework.  The
122e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * first item, if exist, should be in progress i.e. went to the bt framework
123e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * already, waiting for a notification to come back. The second item and
124e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * beyond have not been sent to the bt framework yet.
125e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     */
126e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private static LinkedList<BluetoothJob> workQueue = new LinkedList<BluetoothJob>();
127e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
128e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private void queueCommand(BluetoothJob job) {
129f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        if (D) {
130f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            Log.d(TAG, workQueue.toString());
131f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        }
132e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        synchronized (workQueue) {
133097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            boolean processNow = pruneQueue(job);
134e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
135e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            // Add job to queue
136f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            if (D) {
137f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                Log.d(TAG, "Adding: " + job.toString());
138f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            }
139e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            workQueue.add(job);
140e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
141e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            // if there's nothing pending from before, send the command to bt
142e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            // framework immediately.
143e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (workQueue.size() == 1 || processNow) {
144e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                // If the failed to process, just drop it from the queue.
145e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                // There will be no callback to remove this from the queue.
146e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                processCommands();
147e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
148e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
149e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
150d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
151097ed6c671ed733c0967acc32e017020ede4575bMichael Chan    private boolean pruneQueue(BluetoothJob job) {
152097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        boolean removedStaleItems = false;
153097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        long now = System.currentTimeMillis();
154097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        Iterator<BluetoothJob> it = workQueue.iterator();
155097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        while (it.hasNext()) {
156097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            BluetoothJob existingJob = it.next();
157097ed6c671ed733c0967acc32e017020ede4575bMichael Chan
158097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            // Remove any pending CONNECTS when we receive a DISCONNECT
159097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            if (job != null && job.command == BluetoothCommand.DISCONNECT) {
160097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                if (existingJob.timeSent == 0
161097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                        && existingJob.command == BluetoothCommand.CONNECT
162097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                        && existingJob.device.mAddress.equals(job.device.mAddress)
163097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                        && existingJob.profile == job.profile) {
164f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                    if (D) {
165f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                        Log.d(TAG, "Removed because of a pending disconnect. " + existingJob);
166f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                    }
167097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                    it.remove();
168097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                    continue;
169097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                }
170097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            }
171097ed6c671ed733c0967acc32e017020ede4575bMichael Chan
172097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            // Defensive Code: Remove any job that older than a preset time.
173097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            // We never got a call back. It is better to have overlapping
174097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            // calls than to get stuck.
175097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            if (existingJob.timeSent != 0
176097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                    && (now - existingJob.timeSent) >= MAX_WAIT_TIME_FOR_FRAMEWORK) {
177097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                Log.w(TAG, "Timeout. Removing Job:" + existingJob.toString());
178097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                it.remove();
179097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                removedStaleItems = true;
180097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                continue;
181097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            }
182097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        }
183097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        return removedStaleItems;
184097ed6c671ed733c0967acc32e017020ede4575bMichael Chan    }
185e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
186e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private boolean processCommand(BluetoothJob job) {
187e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        boolean successful = false;
188e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        if (job.timeSent == 0) {
189d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            job.timeSent = System.currentTimeMillis();
190e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            switch (job.command) {
191e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            case CONNECT:
192e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                successful = connectInt(job.device, job.profile);
193e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                break;
194e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            case DISCONNECT:
195e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                successful = disconnectInt(job.device, job.profile);
196e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                break;
197e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
198e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
199e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (successful) {
200f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                if (D) {
201f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                    Log.d(TAG, "Command sent successfully:" + job.toString());
202f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                }
203f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            } else if (V) {
204f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan                Log.v(TAG, "Framework rejected command immediately:" + job.toString());
205e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
206f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        } else if (D) {
207e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            Log.d(TAG, "Job already has a sent time. Skip. " + job.toString());
208e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
209e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
210e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        return successful;
211e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
212e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
2136c97742c88303c65e68fe08257a7ccf841f03866Michael Chan    public void onProfileStateChanged(Profile profile, int newProfileState) {
214f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        if (D) {
215f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            Log.d(TAG, "onProfileStateChanged:" + workQueue.toString());
216f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        }
2176c97742c88303c65e68fe08257a7ccf841f03866Michael Chan
2186c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        int newState = LocalBluetoothProfileManager.getProfileManager(mLocalManager,
2196c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                profile).convertState(newProfileState);
2206c97742c88303c65e68fe08257a7ccf841f03866Michael Chan
2216c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED) {
2226c97742c88303c65e68fe08257a7ccf841f03866Michael Chan            if (!mProfiles.contains(profile)) {
2236c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                mProfiles.add(profile);
224f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            }
2256c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        }
226097ed6c671ed733c0967acc32e017020ede4575bMichael Chan
2276c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        /* Ignore the transient states e.g. connecting, disconnecting */
2286c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED ||
2296c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                newState == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) {
2306c97742c88303c65e68fe08257a7ccf841f03866Michael Chan            BluetoothJob job = workQueue.peek();
2316c97742c88303c65e68fe08257a7ccf841f03866Michael Chan            if (job == null) {
232097ed6c671ed733c0967acc32e017020ede4575bMichael Chan                return;
2336c97742c88303c65e68fe08257a7ccf841f03866Michael Chan            } else if (job.device.mAddress != mAddress) {
2346c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                // This can happen in 2 cases: 1) BT device initiated pairing and
2356c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                // 2) disconnects of one headset that's triggered by connects of
2366c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                // another.
2376c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                if (D) {
2386c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                    Log.d(TAG, "mAddresses:" + mAddress + " != head:" + job.toString());
2396c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                }
2406c97742c88303c65e68fe08257a7ccf841f03866Michael Chan
2416c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                // Check to see if we need to remove the stale items from the queue
2426c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                if (!pruneQueue(null)) {
2436c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                    // nothing in the queue was modify. Just ignore the notification and return.
2446c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                    return;
2456c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                }
2466c97742c88303c65e68fe08257a7ccf841f03866Michael Chan            } else {
2476c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                // Remove the first item and process the next one
2486c97742c88303c65e68fe08257a7ccf841f03866Michael Chan                workQueue.poll();
249097ed6c671ed733c0967acc32e017020ede4575bMichael Chan            }
250e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
2516c97742c88303c65e68fe08257a7ccf841f03866Michael Chan            processCommands();
2526c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        }
253e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
254e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
255e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    /*
256e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * This method is called in 2 places:
257e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * 1) queryCommand() - when someone or something want to connect or
258e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     *    disconnect
259e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     * 2) onProfileStateChanged() - when the framework sends an intent
260e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     *    notification when it finishes processing a command
261e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     */
262e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private void processCommands() {
263f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        if (D) {
264f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan            Log.d(TAG, "processCommands:" + workQueue.toString());
265f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan        }
266e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        Iterator<BluetoothJob> it = workQueue.iterator();
267e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        while (it.hasNext()) {
268e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            BluetoothJob job = it.next();
269e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (processCommand(job)) {
270e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                // Sent to bt framework. Done for now. Will remove this job
271e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                // from queue when we get an event
272e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                return;
273e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            } else {
274e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                /*
275e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                 * If the command failed immediately, there will be no event
276e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                 * callbacks. So delete the job immediately and move on to the
277e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                 * next one
278e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                 */
279e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                it.remove();
280e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
281e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
282e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
283e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
284afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    LocalBluetoothDevice(Context context, String address) {
285afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mLocalManager = LocalBluetoothManager.getInstance(context);
286afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mLocalManager == null) {
287afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            throw new IllegalStateException(
288afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    "Cannot use LocalBluetoothDevice without Bluetooth hardware");
289afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
290afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
291afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mAddress = address;
292afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
293afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fillData();
294afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
295afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
296afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void onClicked() {
297afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        int bondState = getBondState();
298afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
299afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (isConnected()) {
300afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            askDisconnect();
301afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (bondState == BluetoothDevice.BOND_BONDED) {
302afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            connect();
303afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (bondState == BluetoothDevice.BOND_NOT_BONDED) {
304afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            pair();
305afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
306afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
307afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
308afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void disconnect() {
309afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        for (Profile profile : mProfiles) {
310afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            disconnect(profile);
311afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
312afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
313afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
314afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void disconnect(Profile profile) {
315e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        queueCommand(new BluetoothJob(BluetoothCommand.DISCONNECT, this, profile));
316e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
317e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
318e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private boolean disconnectInt(LocalBluetoothDevice device, Profile profile) {
319afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        LocalBluetoothProfileManager profileManager =
320afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
321e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        int status = profileManager.getConnectionStatus(device.mAddress);
322afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (SettingsBtStatus.isConnectionStatusConnected(status)) {
323e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (profileManager.disconnect(device.mAddress) == BluetoothDevice.RESULT_SUCCESS) {
324e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                return true;
325e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
326afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
327e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        return false;
328afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
329afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
330afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void askDisconnect() {
331afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        Context context = mLocalManager.getForegroundActivity();
332afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (context == null) {
333afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            // Cannot ask, since we need an activity context
334afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            disconnect();
335afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return;
336afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
337afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
338afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        Resources res = context.getResources();
339afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
340afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        String name = getName();
341afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (TextUtils.isEmpty(name)) {
342afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            name = res.getString(R.string.bluetooth_device);
343afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
344afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        String message = res.getString(R.string.bluetooth_disconnect_blank, name);
345afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
346afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() {
347afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            public void onClick(DialogInterface dialog, int which) {
348afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                disconnect();
349afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
350afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        };
351afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
3528762093e0094e09493fa6cbac8e8fbf265f18165Michael Chan        new AlertDialog.Builder(context)
353afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                .setTitle(getName())
354afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                .setMessage(message)
355afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                .setPositiveButton(android.R.string.ok, disconnectListener)
356afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                .setNegativeButton(android.R.string.cancel, null)
357afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                .show();
358afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
359afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
360afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void connect() {
361afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (!ensurePaired()) return;
362afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
363afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
364afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
365afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
366afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        boolean hasAtLeastOnePreferredProfile = false;
367afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        for (Profile profile : mProfiles) {
368afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            LocalBluetoothProfileManager profileManager =
369afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
370afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            if (profileManager.isPreferred(mAddress)) {
371afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                hasAtLeastOnePreferredProfile = true;
372e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile));
373afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
374afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
375afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
376afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (!hasAtLeastOnePreferredProfile) {
377afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            connectAndPreferAllProfiles();
378afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
379afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
380afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
381afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void connectAndPreferAllProfiles() {
382afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (!ensurePaired()) return;
383afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
384afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
385afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
386afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
387afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        for (Profile profile : mProfiles) {
388afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            LocalBluetoothProfileManager profileManager =
389afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
390afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            profileManager.setPreferred(mAddress, true);
391e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile));
392afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
393afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
394afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
395afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void connect(Profile profile) {
396afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
397afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
398e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile));
399afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
400afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
401e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    private boolean connectInt(LocalBluetoothDevice device, Profile profile) {
402e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        if (!device.ensurePaired()) return false;
403afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
404afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        LocalBluetoothProfileManager profileManager =
405afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
406e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        int status = profileManager.getConnectionStatus(device.mAddress);
407afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (!SettingsBtStatus.isConnectionStatusConnected(status)) {
408e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (profileManager.connect(device.mAddress) == BluetoothDevice.RESULT_SUCCESS) {
409e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                return true;
410afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
411e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            Log.i(TAG, "Failed to connect " + profile.toString() + " to " + device.mName);
412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
413e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        Log.i(TAG, "Not connected");
414e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        return false;
415afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
416afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
417afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void showConnectingError() {
418afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (!mIsConnectingErrorPossible) return;
419afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = false;
420afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
421afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mLocalManager.showError(mAddress, R.string.bluetooth_error_title,
422afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                R.string.bluetooth_connecting_error_message);
423afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
424afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
425afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean ensurePaired() {
426afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (getBondState() == BluetoothDevice.BOND_NOT_BONDED) {
427afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            pair();
428afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return false;
429afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else {
430afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return true;
431afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
433afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
434afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void pair() {
435afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        BluetoothDevice manager = mLocalManager.getBluetoothManager();
436afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
437afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Pairing is unreliable while scanning, so cancel discovery
438afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (manager.isDiscovering()) {
439afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            manager.cancelDiscovery();
440afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
441afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
442afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (!mLocalManager.getBluetoothManager().createBond(mAddress)) {
443afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mLocalManager.showError(mAddress, R.string.bluetooth_error_title,
444afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    R.string.bluetooth_pairing_error_message);
445afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
446afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
447afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
448afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void unpair() {
449e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        synchronized (workQueue) {
450e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            // Remove any pending commands for this device
451d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            boolean processNow = false;
452e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            Iterator<BluetoothJob> it = workQueue.iterator();
453e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            while (it.hasNext()) {
454e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                BluetoothJob job = it.next();
455e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                if (job.device.mAddress.equals(this.mAddress)) {
456e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                    it.remove();
457e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                    if (job.timeSent != 0) {
458e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                        processNow = true;
459e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                    }
460e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                }
461e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
462e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            if (processNow) {
463e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project                processCommands();
464e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
465e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
466e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
467afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        BluetoothDevice manager = mLocalManager.getBluetoothManager();
468afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
469afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        switch (getBondState()) {
470afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        case BluetoothDevice.BOND_BONDED:
471afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            manager.removeBond(mAddress);
472afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            break;
473afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
474afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        case BluetoothDevice.BOND_BONDING:
475afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            manager.cancelBondProcess(mAddress);
476afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            break;
477afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
478afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
479afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
480afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fillData() {
481afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
482afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
483afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
484afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mVisible = false;
485afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
486afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
487afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
488afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
489afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String getAddress() {
490afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mAddress;
491afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
492afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
493afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String getName() {
494afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mName;
495afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
496afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
497d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    public void setName(String name) {
498d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        if (!mName.equals(name)) {
499d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            if (TextUtils.isEmpty(name)) {
500d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh                mName = mAddress;
501d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            } else {
502d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh                mName = name;
503d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            }
504d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
505d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
506d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
507d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
508afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void refreshName() {
509afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
510afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
511afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
512afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
513afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchName() {
514afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mName = mLocalManager.getBluetoothManager().getRemoteName(mAddress);
515afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
516afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (TextUtils.isEmpty(mName)) {
517afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mName = mAddress;
518afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
519afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
520afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
521afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void refresh() {
522afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
523afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
524afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
525afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean isVisible() {
526afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mVisible;
527afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
528afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
529afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setVisible(boolean visible) {
530afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mVisible != visible) {
531afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mVisible = visible;
532afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
533afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
534afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
535afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
536afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int getBondState() {
537afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mLocalManager.getBluetoothManager().getBondState(mAddress);
538afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
539afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
540afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setRssi(short rssi) {
541afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mRssi != rssi) {
542afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mRssi = rssi;
543afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
544afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
545afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
546afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
547afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
548afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Checks whether we are connected to this device (any profile counts).
549afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
550afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @return Whether it is connected.
551afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
552afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean isConnected() {
553afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        for (Profile profile : mProfiles) {
554afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
555afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    .getConnectionStatus(mAddress);
556afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            if (SettingsBtStatus.isConnectionStatusConnected(status)) {
557afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
558afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
559afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
560afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
561afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return false;
562afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
563afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
564afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean isBusy() {
565afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        for (Profile profile : mProfiles) {
566afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
567afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    .getConnectionStatus(mAddress);
568afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            if (SettingsBtStatus.isConnectionStatusBusy(status)) {
569afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
570afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
571afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
572afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
573afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (getBondState() == BluetoothDevice.BOND_BONDING) {
574afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return true;
575afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
576afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
577afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return false;
578afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
579afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
580afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int getBtClassDrawable() {
581afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
582afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // First try looking at profiles
583afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mProfiles.contains(Profile.A2DP)) {
584afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.drawable.ic_bt_headphones_a2dp;
585afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (mProfiles.contains(Profile.HEADSET)) {
586afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.drawable.ic_bt_headset_hfp;
587afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
588afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
589afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Fallback on class
590afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        switch (BluetoothClass.Device.Major.getDeviceMajor(mBtClass)) {
591afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        case BluetoothClass.Device.Major.COMPUTER:
592afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.drawable.ic_bt_laptop;
593afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        case BluetoothClass.Device.Major.PHONE:
595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.drawable.ic_bt_cellphone;
596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
597afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        default:
598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return 0;
599afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
600afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
601afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
602afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
603afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Fetches a new value for the cached BT class.
604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
605afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchBtClass() {
606afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mBtClass = mLocalManager.getBluetoothManager().getRemoteClass(mAddress);
607b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly        if (mBtClass != BluetoothClass.ERROR) {
608b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly            LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
609b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly        }
610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
611afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
612afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
613afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Refreshes the UI for the BT class, including fetching the latest value
614afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * for the class.
615afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void refreshBtClass() {
617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
619afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
620afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
621d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    public void setBtClass(int btClass) {
622d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        if (mBtClass != btClass && btClass != BluetoothClass.ERROR) {
623d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            mBtClass = btClass;
624d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
625d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
626d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
627d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
628d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
629afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int getSummary() {
630afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // TODO: clean up
631afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        int oneOffSummary = getOneOffSummary();
632afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (oneOffSummary != 0) {
633afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return oneOffSummary;
634afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
635afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
636afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        for (Profile profile : mProfiles) {
637afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
638afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    .getProfileManager(mLocalManager, profile);
639afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            int connectionStatus = profileManager.getConnectionStatus(mAddress);
640afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
641afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus) ||
642afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    connectionStatus == SettingsBtStatus.CONNECTION_STATUS_CONNECTING ||
643afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING) {
644afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
645afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
646afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
647afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
648afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return SettingsBtStatus.getPairingStatusSummary(getBondState());
649afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
650afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
651afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
652afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * We have special summaries when particular profiles are connected. This
653afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * checks for those states and returns an applicable summary.
654afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
655afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @return A one-off summary that is applicable for the current state, or 0.
656afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
657afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private int getOneOffSummary() {
658afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        boolean isA2dpConnected = false, isHeadsetConnected = false, isConnecting = false;
659afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
660afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mProfiles.contains(Profile.A2DP)) {
661afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
662afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    .getProfileManager(mLocalManager, Profile.A2DP);
663afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            isConnecting = profileManager.getConnectionStatus(mAddress) ==
664afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
665afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            isA2dpConnected = profileManager.isConnected(mAddress);
666afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
667afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
668afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mProfiles.contains(Profile.HEADSET)) {
669afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
670afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    .getProfileManager(mLocalManager, Profile.HEADSET);
671afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            isConnecting |= profileManager.getConnectionStatus(mAddress) ==
672afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
673afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            isHeadsetConnected = profileManager.isConnected(mAddress);
674afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
675afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
676afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (isConnecting) {
677afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            // If any of these important profiles is connecting, prefer that
678afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return SettingsBtStatus.getConnectionStatusSummary(
679afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    SettingsBtStatus.CONNECTION_STATUS_CONNECTING);
680afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (isA2dpConnected && isHeadsetConnected) {
681afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.string.bluetooth_summary_connected_to_a2dp_headset;
682afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (isA2dpConnected) {
683afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.string.bluetooth_summary_connected_to_a2dp;
684afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (isHeadsetConnected) {
685afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return R.string.bluetooth_summary_connected_to_headset;
686afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else {
687afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return 0;
688afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
689afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
690afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
691afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public List<Profile> getProfiles() {
692afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return new ArrayList<Profile>(mProfiles);
693afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
694afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
695afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void onCreateContextMenu(ContextMenu menu) {
696afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // No context menu if it is busy (none of these items are applicable if busy)
697afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (isBusy()) return;
698afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
699afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        int bondState = getBondState();
700afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        boolean isConnected = isConnected();
701afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        boolean hasProfiles = mProfiles.size() > 0;
702afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
703afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        menu.setHeaderTitle(getName());
704afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
705afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (isConnected) {
706afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            menu.add(0, CONTEXT_ITEM_DISCONNECT, 0, R.string.bluetooth_device_context_disconnect);
707afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else if (hasProfiles) {
708afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            // For connection action, show either "Connect" or "Pair & connect"
709afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            int connectString = (bondState == BluetoothDevice.BOND_NOT_BONDED)
710afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    ? R.string.bluetooth_device_context_pair_connect
711afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    : R.string.bluetooth_device_context_connect;
712afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            menu.add(0, CONTEXT_ITEM_CONNECT, 0, connectString);
713afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
714afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
715afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (bondState == BluetoothDevice.BOND_BONDED) {
716afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            // For unpair action, show either "Unpair" or "Disconnect & unpair"
717afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            int unpairString = isConnected
718afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    ? R.string.bluetooth_device_context_disconnect_unpair
719afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    : R.string.bluetooth_device_context_unpair;
720afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            menu.add(0, CONTEXT_ITEM_UNPAIR, 0, unpairString);
721afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
722afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            // Show the connection options item
723afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            menu.add(0, CONTEXT_ITEM_CONNECT_ADVANCED, 0,
724afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    R.string.bluetooth_device_context_connect_advanced);
725afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
726afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
727afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
728afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
729afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Called when a context menu item is clicked.
730afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
731afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @param item The item that was clicked.
732afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
733afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void onContextItemSelected(MenuItem item) {
734afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        switch (item.getItemId()) {
735afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            case CONTEXT_ITEM_DISCONNECT:
736afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                disconnect();
737afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                break;
738afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
739afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            case CONTEXT_ITEM_CONNECT:
740afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                connect();
741afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                break;
742afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
743afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            case CONTEXT_ITEM_UNPAIR:
744afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                unpair();
745afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                break;
746afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
747afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            case CONTEXT_ITEM_CONNECT_ADVANCED:
748afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                Intent intent = new Intent();
749afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                // Need an activity context to open this in our task
750afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                Context context = mLocalManager.getForegroundActivity();
751afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                if (context == null) {
752afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    // Fallback on application context, and open in a new task
753afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    context = mLocalManager.getContext();
754afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
755afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                }
756afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                intent.setClass(context, ConnectSpecificProfilesActivity.class);
757afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                intent.putExtra(ConnectSpecificProfilesActivity.EXTRA_ADDRESS, mAddress);
758afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                context.startActivity(intent);
759afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                break;
760afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
761afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
762afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
763afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void registerCallback(Callback callback) {
764afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
765afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.add(callback);
766afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
767afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
768afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
769afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public void unregisterCallback(Callback callback) {
770afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
771afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.remove(callback);
772afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
773afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
774afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
775afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void dispatchAttributesChanged() {
776afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
777afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            for (Callback callback : mCallbacks) {
778afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                callback.onDeviceAttributesChanged(this);
779afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
780afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
781afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
782afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
783afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
784afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String toString() {
785afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mAddress;
786afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
787afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
788afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
789afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean equals(Object o) {
790afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if ((o == null) || !(o instanceof LocalBluetoothDevice)) {
791afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            throw new ClassCastException();
792afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
793afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
794afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mAddress.equals(((LocalBluetoothDevice) o).mAddress);
795afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
796afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
797afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
798afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int hashCode() {
799afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mAddress.hashCode();
800afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
801afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
802afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int compareTo(LocalBluetoothDevice another) {
803afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        int comparison;
804afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
805afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Connected above not connected
806afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
807afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
808afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
809afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Paired above not paired
810afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
811afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
812afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
813afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
814afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Visible above not visible
815afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
816afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
817afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
818afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Stronger signal above weaker signal
819afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = another.mRssi - mRssi;
820afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
821afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
822afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Fallback on name
823afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return getName().compareTo(another.getName());
824afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
825afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
826afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public interface Callback {
827afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        void onDeviceAttributesChanged(LocalBluetoothDevice device);
828afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
829afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
830