CachedBluetoothDevice.java revision e6531e253bf646324d3a68de0e9cc612c5e1c8ac
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; 20d63c0112251ab4e4e977545368dd703d875012a4Nick Pellyimport android.bluetooth.BluetoothAdapter; 212aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chanimport android.bluetooth.BluetoothClass; 22e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport android.bluetooth.BluetoothDevice; 23afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.Context; 24afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.DialogInterface; 25afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.Intent; 26afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.res.Resources; 27e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chanimport android.os.ParcelUuid; 282aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chanimport android.os.SystemClock; 29afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.text.TextUtils; 30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.util.Log; 31afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.ContextMenu; 32afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.Menu; 33afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.MenuItem; 34afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 356c97742c88303c65e68fe08257a7ccf841f03866Michael Chanimport com.android.settings.R; 366c97742c88303c65e68fe08257a7ccf841f03866Michael Chanimport com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; 376c97742c88303c65e68fe08257a7ccf841f03866Michael Chan 38e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.text.DateFormat; 39afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.ArrayList; 40e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.util.Date; 41e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.util.Iterator; 42e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport java.util.LinkedList; 43afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.List; 44afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 45afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/** 46d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly * CachedBluetoothDevice represents a remote Bluetooth device. It contains 47afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * attributes of the device (such as the address, name, RSSI, etc.) and 48afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * functionality that can be performed on the device (connect, pair, disconnect, 49afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * etc.). 50afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 51d63c0112251ab4e4e977545368dd703d875012a4Nick Pellypublic class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { 52d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private static final String TAG = "CachedBluetoothDevice"; 53f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan private static final boolean D = LocalBluetoothManager.D; 54f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan private static final boolean V = LocalBluetoothManager.V; 552aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private static final boolean DEBUG = true; // STOPSHIP - disable before final rom 56afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 57afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_CONNECT = Menu.FIRST + 1; 58afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_DISCONNECT = Menu.FIRST + 2; 59afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_UNPAIR = Menu.FIRST + 3; 60afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_CONNECT_ADVANCED = Menu.FIRST + 4; 61afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 62d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private final BluetoothDevice mDevice; 63afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private String mName; 64afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private short mRssi; 6516cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly private BluetoothClass mBtClass; 66afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 67afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private List<Profile> mProfiles = new ArrayList<Profile>(); 68afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 69afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private boolean mVisible; 70afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 71afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private final LocalBluetoothManager mLocalManager; 72afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 73afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private List<Callback> mCallbacks = new ArrayList<Callback>(); 74afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 75afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 76afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * When we connect to multiple profiles, we only want to display a single 77afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * error even if they all fail. This tracks that state. 78afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 79afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private boolean mIsConnectingErrorPossible; 80afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 812aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan /** 82eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan * Last time a bt profile auto-connect was attempted. 83eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan * If an ACTION_UUID intent comes in within 842aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect 852aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * again with the new UUIDs 862aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan */ 87eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan private long mConnectAttempted; 882aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 89eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan // See mConnectAttempted 902aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000; 912aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 92e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Max time to hold the work queue if we don't get or missed a response 93e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // from the bt framework. 94e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private static final long MAX_WAIT_TIME_FOR_FRAMEWORK = 25 * 1000; 95e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 96e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private enum BluetoothCommand { 97e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project CONNECT, DISCONNECT, 98e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 99e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 1008762093e0094e09493fa6cbac8e8fbf265f18165Michael Chan static class BluetoothJob { 101e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project final BluetoothCommand command; // CONNECT, DISCONNECT 102d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly final CachedBluetoothDevice cachedDevice; 103e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project final Profile profile; // HEADSET, A2DP, etc 104e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // 0 means this command was not been sent to the bt framework. 105e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project long timeSent; 106e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 107e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project public BluetoothJob(BluetoothCommand command, 108d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly CachedBluetoothDevice cachedDevice, Profile profile) { 109e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project this.command = command; 110d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly this.cachedDevice = cachedDevice; 111e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project this.profile = profile; 112e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project this.timeSent = 0; 113e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 114d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 115e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project @Override 116e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project public String toString() { 117e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project StringBuilder sb = new StringBuilder(); 118e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(command.name()); 119d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly sb.append(" Address:").append(cachedDevice.mDevice); 120e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(" Profile:").append(profile.name()); 121e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(" TimeSent:"); 122e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (timeSent == 0) { 123e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append("not yet"); 124e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } else { 125e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(DateFormat.getTimeInstance().format(new Date(timeSent))); 126e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 127e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return sb.toString(); 128e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 129e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 130e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 131e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project /** 132e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * We want to serialize connect and disconnect calls. http://b/170538 133e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * This are some headsets that may have L2CAP resource limitation. We want 134e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * to limit the bt bandwidth usage. 135e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * 136e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * A queue to keep track of asynchronous calls to the bt framework. The 137e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * first item, if exist, should be in progress i.e. went to the bt framework 138e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * already, waiting for a notification to come back. The second item and 139e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * beyond have not been sent to the bt framework yet. 140e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project */ 141e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private static LinkedList<BluetoothJob> workQueue = new LinkedList<BluetoothJob>(); 142e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 143e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private void queueCommand(BluetoothJob job) { 144f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 145f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, workQueue.toString()); 146f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 147e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project synchronized (workQueue) { 148097ed6c671ed733c0967acc32e017020ede4575bMichael Chan boolean processNow = pruneQueue(job); 149e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 150e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Add job to queue 151f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 152f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "Adding: " + job.toString()); 153f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 154e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project workQueue.add(job); 155e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 156e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // if there's nothing pending from before, send the command to bt 157e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // framework immediately. 158e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (workQueue.size() == 1 || processNow) { 159e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // If the failed to process, just drop it from the queue. 160e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // There will be no callback to remove this from the queue. 161e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project processCommands(); 162e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 163e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 164e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 165d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 166097ed6c671ed733c0967acc32e017020ede4575bMichael Chan private boolean pruneQueue(BluetoothJob job) { 167097ed6c671ed733c0967acc32e017020ede4575bMichael Chan boolean removedStaleItems = false; 168097ed6c671ed733c0967acc32e017020ede4575bMichael Chan long now = System.currentTimeMillis(); 169097ed6c671ed733c0967acc32e017020ede4575bMichael Chan Iterator<BluetoothJob> it = workQueue.iterator(); 170097ed6c671ed733c0967acc32e017020ede4575bMichael Chan while (it.hasNext()) { 171097ed6c671ed733c0967acc32e017020ede4575bMichael Chan BluetoothJob existingJob = it.next(); 172097ed6c671ed733c0967acc32e017020ede4575bMichael Chan 173097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // Remove any pending CONNECTS when we receive a DISCONNECT 174097ed6c671ed733c0967acc32e017020ede4575bMichael Chan if (job != null && job.command == BluetoothCommand.DISCONNECT) { 175097ed6c671ed733c0967acc32e017020ede4575bMichael Chan if (existingJob.timeSent == 0 176097ed6c671ed733c0967acc32e017020ede4575bMichael Chan && existingJob.command == BluetoothCommand.CONNECT 177d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly && existingJob.cachedDevice.mDevice.equals(job.cachedDevice.mDevice) 178097ed6c671ed733c0967acc32e017020ede4575bMichael Chan && existingJob.profile == job.profile) { 179f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 180f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "Removed because of a pending disconnect. " + existingJob); 181f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 182097ed6c671ed733c0967acc32e017020ede4575bMichael Chan it.remove(); 183097ed6c671ed733c0967acc32e017020ede4575bMichael Chan continue; 184097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 185097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 186097ed6c671ed733c0967acc32e017020ede4575bMichael Chan 187097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // Defensive Code: Remove any job that older than a preset time. 188097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // We never got a call back. It is better to have overlapping 189097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // calls than to get stuck. 190097ed6c671ed733c0967acc32e017020ede4575bMichael Chan if (existingJob.timeSent != 0 191097ed6c671ed733c0967acc32e017020ede4575bMichael Chan && (now - existingJob.timeSent) >= MAX_WAIT_TIME_FOR_FRAMEWORK) { 192097ed6c671ed733c0967acc32e017020ede4575bMichael Chan Log.w(TAG, "Timeout. Removing Job:" + existingJob.toString()); 193097ed6c671ed733c0967acc32e017020ede4575bMichael Chan it.remove(); 194097ed6c671ed733c0967acc32e017020ede4575bMichael Chan removedStaleItems = true; 195097ed6c671ed733c0967acc32e017020ede4575bMichael Chan continue; 196097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 197097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 198097ed6c671ed733c0967acc32e017020ede4575bMichael Chan return removedStaleItems; 199097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 200e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 201e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private boolean processCommand(BluetoothJob job) { 202e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project boolean successful = false; 203e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (job.timeSent == 0) { 204d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh job.timeSent = System.currentTimeMillis(); 205e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project switch (job.command) { 206e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project case CONNECT: 207d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly successful = connectInt(job.cachedDevice, job.profile); 208e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project break; 209e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project case DISCONNECT: 210d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly successful = disconnectInt(job.cachedDevice, job.profile); 211e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project break; 212e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 213e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 214e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (successful) { 215f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 216f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "Command sent successfully:" + job.toString()); 217f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 218f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } else if (V) { 219f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.v(TAG, "Framework rejected command immediately:" + job.toString()); 220e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 221f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } else if (D) { 222e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project Log.d(TAG, "Job already has a sent time. Skip. " + job.toString()); 223e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 224e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 225e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return successful; 226e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 227e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 2286c97742c88303c65e68fe08257a7ccf841f03866Michael Chan public void onProfileStateChanged(Profile profile, int newProfileState) { 229f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 230f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "onProfileStateChanged:" + workQueue.toString()); 231f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 2326c97742c88303c65e68fe08257a7ccf841f03866Michael Chan 2336c97742c88303c65e68fe08257a7ccf841f03866Michael Chan int newState = LocalBluetoothProfileManager.getProfileManager(mLocalManager, 2346c97742c88303c65e68fe08257a7ccf841f03866Michael Chan profile).convertState(newProfileState); 2356c97742c88303c65e68fe08257a7ccf841f03866Michael Chan 2366c97742c88303c65e68fe08257a7ccf841f03866Michael Chan if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED) { 2376c97742c88303c65e68fe08257a7ccf841f03866Michael Chan if (!mProfiles.contains(profile)) { 2386c97742c88303c65e68fe08257a7ccf841f03866Michael Chan mProfiles.add(profile); 239f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 2406c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 241097ed6c671ed733c0967acc32e017020ede4575bMichael Chan 2426c97742c88303c65e68fe08257a7ccf841f03866Michael Chan /* Ignore the transient states e.g. connecting, disconnecting */ 2436c97742c88303c65e68fe08257a7ccf841f03866Michael Chan if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED || 2446c97742c88303c65e68fe08257a7ccf841f03866Michael Chan newState == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) { 2456c97742c88303c65e68fe08257a7ccf841f03866Michael Chan BluetoothJob job = workQueue.peek(); 2466c97742c88303c65e68fe08257a7ccf841f03866Michael Chan if (job == null) { 247097ed6c671ed733c0967acc32e017020ede4575bMichael Chan return; 24853121cf110f358c30ea39224bc3ff0f4c1b56e3fJaikumar Ganesh } else if (!job.cachedDevice.mDevice.equals(mDevice)) { 2496c97742c88303c65e68fe08257a7ccf841f03866Michael Chan // This can happen in 2 cases: 1) BT device initiated pairing and 2506c97742c88303c65e68fe08257a7ccf841f03866Michael Chan // 2) disconnects of one headset that's triggered by connects of 2516c97742c88303c65e68fe08257a7ccf841f03866Michael Chan // another. 2526c97742c88303c65e68fe08257a7ccf841f03866Michael Chan if (D) { 253d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly Log.d(TAG, "mDevice:" + mDevice + " != head:" + job.toString()); 2546c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 2556c97742c88303c65e68fe08257a7ccf841f03866Michael Chan 2566c97742c88303c65e68fe08257a7ccf841f03866Michael Chan // Check to see if we need to remove the stale items from the queue 2576c97742c88303c65e68fe08257a7ccf841f03866Michael Chan if (!pruneQueue(null)) { 2586c97742c88303c65e68fe08257a7ccf841f03866Michael Chan // nothing in the queue was modify. Just ignore the notification and return. 2596c97742c88303c65e68fe08257a7ccf841f03866Michael Chan return; 2606c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 2616c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } else { 2626c97742c88303c65e68fe08257a7ccf841f03866Michael Chan // Remove the first item and process the next one 2636c97742c88303c65e68fe08257a7ccf841f03866Michael Chan workQueue.poll(); 264097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 265e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 2666c97742c88303c65e68fe08257a7ccf841f03866Michael Chan processCommands(); 2676c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 268e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 269e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 270e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project /* 271e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * This method is called in 2 places: 272e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * 1) queryCommand() - when someone or something want to connect or 273e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * disconnect 274e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * 2) onProfileStateChanged() - when the framework sends an intent 275e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * notification when it finishes processing a command 276e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project */ 277e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private void processCommands() { 278f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 279f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "processCommands:" + workQueue.toString()); 280f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 281e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project Iterator<BluetoothJob> it = workQueue.iterator(); 282e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project while (it.hasNext()) { 283e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project BluetoothJob job = it.next(); 284e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (processCommand(job)) { 285e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Sent to bt framework. Done for now. Will remove this job 286e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // from queue when we get an event 287e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return; 288e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } else { 289e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project /* 290e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * If the command failed immediately, there will be no event 291e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * callbacks. So delete the job immediately and move on to the 292e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * next one 293e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project */ 294e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project it.remove(); 295e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 296e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 297e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 298e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 299d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly CachedBluetoothDevice(Context context, BluetoothDevice device) { 300afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mLocalManager = LocalBluetoothManager.getInstance(context); 301afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mLocalManager == null) { 302afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project throw new IllegalStateException( 303d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly "Cannot use CachedBluetoothDevice without Bluetooth hardware"); 304afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 305afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 306d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mDevice = device; 307afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 308afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fillData(); 309afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 310afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 311afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onClicked() { 312afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int bondState = getBondState(); 313afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 314afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (isConnected()) { 315afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project askDisconnect(); 316afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (bondState == BluetoothDevice.BOND_BONDED) { 317afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connect(); 31816cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly } else if (bondState == BluetoothDevice.BOND_NONE) { 319afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project pair(); 320afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 321afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 322afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 323afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void disconnect() { 324afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 325afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(profile); 326afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 327afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 328afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 329afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void disconnect(Profile profile) { 330e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project queueCommand(new BluetoothJob(BluetoothCommand.DISCONNECT, this, profile)); 331e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 332e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 333d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private boolean disconnectInt(CachedBluetoothDevice cachedDevice, Profile profile) { 334afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = 335afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 336d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly int status = profileManager.getConnectionStatus(cachedDevice.mDevice); 337afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusConnected(status)) { 338f4779354b39353a48d0bec6cc5c71fd73e3f369aNick Pelly if (profileManager.disconnect(cachedDevice.mDevice)) { 339e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return true; 340e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 341afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 342e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return false; 343afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 344afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 345afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void askDisconnect() { 346afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Context context = mLocalManager.getForegroundActivity(); 347afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (context == null) { 348afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Cannot ask, since we need an activity context 349afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(); 350afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return; 351afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 352afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 353afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Resources res = context.getResources(); 354afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 355afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project String name = getName(); 356afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (TextUtils.isEmpty(name)) { 357afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project name = res.getString(R.string.bluetooth_device); 358afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 359afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project String message = res.getString(R.string.bluetooth_disconnect_blank, name); 360afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 361afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() { 362afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onClick(DialogInterface dialog, int which) { 363afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(); 364afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 365afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project }; 366afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 3678762093e0094e09493fa6cbac8e8fbf265f18165Michael Chan new AlertDialog.Builder(context) 368afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setTitle(getName()) 369afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setMessage(message) 370afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setPositiveButton(android.R.string.ok, disconnectListener) 371afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setNegativeButton(android.R.string.cancel, null) 372afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .show(); 373afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 374afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 375afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void connect() { 376afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!ensurePaired()) return; 377afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 378eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan mConnectAttempted = SystemClock.elapsedRealtime(); 379eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan 380eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan connectWithoutResettingTimer(); 381eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 382eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan 383eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan private void connectWithoutResettingTimer() { 3842aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan // Try to initialize the profiles if there were not. 3852aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (mProfiles.size() == 0) { 3862aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (!updateProfiles()) { 3872aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan // If UUIDs are not available yet, connect will be happen 3882aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan // upon arrival of the ACTION_UUID intent. 389eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) Log.d(TAG, "No profiles. Maybe we will connect later"); 3902aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan return; 3912aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 3922aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 3932aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 394afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Reset the only-show-one-error-dialog tracking variable 395afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = true; 396afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 397eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan int preferredProfiles = 0; 398afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 399afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = 400afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 401d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (profileManager.isPreferred(mDevice)) { 402eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan ++preferredProfiles; 403e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); 404afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 405afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 406eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles); 407afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 408eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (preferredProfiles == 0) { 409eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan connectAllProfiles(); 410afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 411afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 413eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan private void connectAllProfiles() { 414afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!ensurePaired()) return; 415afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 416afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Reset the only-show-one-error-dialog tracking variable 417afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = true; 418afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 419afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 420afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = 421afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 422eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan profileManager.setPreferred(mDevice, false); 423e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); 424afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 425afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 426afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 427afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void connect(Profile profile) { 428eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan mConnectAttempted = SystemClock.elapsedRealtime(); 429afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Reset the only-show-one-error-dialog tracking variable 430afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = true; 431e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); 432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 433afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 434d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private boolean connectInt(CachedBluetoothDevice cachedDevice, Profile profile) { 435d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (!cachedDevice.ensurePaired()) return false; 436afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 437afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = 438afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 439d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly int status = profileManager.getConnectionStatus(cachedDevice.mDevice); 440afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!SettingsBtStatus.isConnectionStatusConnected(status)) { 441f4779354b39353a48d0bec6cc5c71fd73e3f369aNick Pelly if (profileManager.connect(cachedDevice.mDevice)) { 442e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return true; 443afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 444d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly Log.i(TAG, "Failed to connect " + profile.toString() + " to " + cachedDevice.mName); 445eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } else { 446eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan Log.i(TAG, "Already connected"); 447afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 448e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return false; 449afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 450afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 451afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void showConnectingError() { 452afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!mIsConnectingErrorPossible) return; 453afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = false; 454afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 455d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mLocalManager.showError(mDevice, R.string.bluetooth_error_title, 456afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project R.string.bluetooth_connecting_error_message); 457afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 458afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 459afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private boolean ensurePaired() { 46016cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly if (getBondState() == BluetoothDevice.BOND_NONE) { 461afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project pair(); 462afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return false; 463afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else { 464afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 465afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 466afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 467afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 468afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void pair() { 469d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter(); 470afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 471afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Pairing is unreliable while scanning, so cancel discovery 472d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (adapter.isDiscovering()) { 473d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly adapter.cancelDiscovery(); 474afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 475afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 476d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (!mDevice.createBond()) { 477d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mLocalManager.showError(mDevice, R.string.bluetooth_error_title, 478afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project R.string.bluetooth_pairing_error_message); 479afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 480afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 481afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 482afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void unpair() { 483e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project synchronized (workQueue) { 484e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Remove any pending commands for this device 485d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh boolean processNow = false; 486e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project Iterator<BluetoothJob> it = workQueue.iterator(); 487e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project while (it.hasNext()) { 488e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project BluetoothJob job = it.next(); 489d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (job.cachedDevice.mDevice.equals(this.mDevice)) { 490e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project it.remove(); 491e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (job.timeSent != 0) { 492e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project processNow = true; 493e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 494e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 495e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 496e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (processNow) { 497e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project processCommands(); 498e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 499e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 500e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 501afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project switch (getBondState()) { 502afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case BluetoothDevice.BOND_BONDED: 503d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mDevice.removeBond(); 504afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 505afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 506afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case BluetoothDevice.BOND_BONDING: 507d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mDevice.cancelBondProcess(); 508afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 509afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 510afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 511afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 512afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void fillData() { 513afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchName(); 514afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchBtClass(); 5152aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan updateProfiles(); 516afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 517afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mVisible = false; 518afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 519afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 520afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 521afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 522d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly public BluetoothDevice getDevice() { 523d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice; 524afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 525afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 526afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public String getName() { 527afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return mName; 528afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 529afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 530d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh public void setName(String name) { 531d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh if (!mName.equals(name)) { 532d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh if (TextUtils.isEmpty(name)) { 533d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mName = mDevice.getAddress(); 534d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } else { 535d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh mName = name; 536d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 537d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh dispatchAttributesChanged(); 538d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 539d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 540d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 541afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void refreshName() { 542afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchName(); 543afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 544afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 545afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 546afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void fetchName() { 547d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mName = mDevice.getName(); 548afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 549afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (TextUtils.isEmpty(mName)) { 550d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mName = mDevice.getAddress(); 551eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) Log.d(TAG, "Default to address. Device has no name (yet) " + mName); 552afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 553afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 554afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 555afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void refresh() { 556afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 557afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 558afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 559afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean isVisible() { 560afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return mVisible; 561afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 562afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 563afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project void setVisible(boolean visible) { 564afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mVisible != visible) { 565afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mVisible = visible; 566afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 567afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 568afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 569afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 570afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int getBondState() { 571d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.getBondState(); 572afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 573afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 574afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project void setRssi(short rssi) { 575afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mRssi != rssi) { 576afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mRssi = rssi; 577afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 578afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 579afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 580afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 581afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 582afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Checks whether we are connected to this device (any profile counts). 583afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 584afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * @return Whether it is connected. 585afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 586afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean isConnected() { 587afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 588afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile) 589d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly .getConnectionStatus(mDevice); 590afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusConnected(status)) { 591afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 592afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 593afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return false; 596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 597afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean isBusy() { 599afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 600afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile) 601d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly .getConnectionStatus(mDevice); 602afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusBusy(status)) { 603afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 605afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 606afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 607afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (getBondState() == BluetoothDevice.BOND_BONDING) { 608afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 609afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 611afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return false; 612afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 613afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 614afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int getBtClassDrawable() { 61516cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly switch (mBtClass.getMajorDeviceClass()) { 616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case BluetoothClass.Device.Major.COMPUTER: 617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.drawable.ic_bt_laptop; 618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 619afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case BluetoothClass.Device.Major.PHONE: 620afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.drawable.ic_bt_cellphone; 6213e1c1d19201e625888cdd07e06ea9502d7c4dafbMichael Chan } 622afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 623cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mProfiles.size() > 0) { 624cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mProfiles.contains(Profile.A2DP)) { 625cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headphones_a2dp; 626cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } else if (mProfiles.contains(Profile.HEADSET)) { 627cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headset_hfp; 628cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } 6293e1c1d19201e625888cdd07e06ea9502d7c4dafbMichael Chan } else { 630cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { 631cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headphones_a2dp; 632cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan 633cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } 634cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { 635cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headset_hfp; 636cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } 637afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 638cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return 0; 639afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 640afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 641afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 642afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Fetches a new value for the cached BT class. 643afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 644afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void fetchBtClass() { 645d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mBtClass = mDevice.getBluetoothClass(); 6462aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 6472aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6482aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private boolean updateProfiles() { 6492aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan ParcelUuid[] uuids = mDevice.getUuids(); 6502aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (uuids == null) return false; 6512aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6522aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan LocalBluetoothProfileManager.updateProfiles(uuids, mProfiles); 6532aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6542aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (DEBUG) { 6552aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.e(TAG, "updating profiles for " + mDevice.getName()); 6562aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6572aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan boolean printUuids = true; 6582aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan BluetoothClass bluetoothClass = mDevice.getBluetoothClass(); 6592aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6602aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET) != 6612aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan mProfiles.contains(Profile.HEADSET)) { 6622aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, "headset classbits != uuid"); 6632aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan printUuids = true; 6642aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 6652aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6662aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) != 6672aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan mProfiles.contains(Profile.A2DP)) { 6682aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, "a2dp classbits != uuid"); 6692aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan printUuids = true; 6702aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 6712aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6722aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP) != 6732aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan mProfiles.contains(Profile.OPP)) { 6742aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, "opp classbits != uuid"); 6752aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan printUuids = true; 6762aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 6772aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6782aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (printUuids) { 6792aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, "Class: " + bluetoothClass.toString()); 6802aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, "UUID:"); 6812aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan for (int i = 0; i < uuids.length; i++) { 6822aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, " " + uuids[i]); 6832aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 6842aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 685b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly } 6862aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan return true; 687afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 688afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 689afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 690afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Refreshes the UI for the BT class, including fetching the latest value 691afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * for the class. 692afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 693afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void refreshBtClass() { 694afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchBtClass(); 695afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 696afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 697afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 6982aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan /** 6992aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * Refreshes the UI when framework alerts us of a UUID change. 7002aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan */ 7012aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan public void onUuidChanged() { 7022aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan updateProfiles(); 7032aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 704eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) { 705eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan Log.e(TAG, "onUuidChanged: Time since last connect" 706eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan + (SystemClock.elapsedRealtime() - mConnectAttempted)); 707eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 7082aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 7092aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan /* 7102aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * If a connect was attempted earlier without any UUID, we will do the 7112aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * connect now. 7122aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan */ 7132aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (mProfiles.size() > 0 714eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock 7152aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan .elapsedRealtime()) { 716eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan connectWithoutResettingTimer(); 7172aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 7182aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan dispatchAttributesChanged(); 7192aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 7202aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 721eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan public void onBondingStateChanged(int bondState) { 722eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (bondState == BluetoothDevice.BOND_NONE) { 723eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan mProfiles.clear(); 724eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 725eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan refresh(); 726eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 727eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan 72816cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly public void setBtClass(BluetoothClass btClass) { 72916cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly if (btClass != null && mBtClass != btClass) { 730d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh mBtClass = btClass; 731d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh dispatchAttributesChanged(); 732d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 733d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 734d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 735afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int getSummary() { 736afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // TODO: clean up 737afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int oneOffSummary = getOneOffSummary(); 738afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (oneOffSummary != 0) { 739afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return oneOffSummary; 740afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 741afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 742afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 743afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 744afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .getProfileManager(mLocalManager, profile); 745d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly int connectionStatus = profileManager.getConnectionStatus(mDevice); 746afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 747afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus) || 748afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connectionStatus == SettingsBtStatus.CONNECTION_STATUS_CONNECTING || 749afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING) { 750afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return SettingsBtStatus.getConnectionStatusSummary(connectionStatus); 751afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 752afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 753afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 754afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return SettingsBtStatus.getPairingStatusSummary(getBondState()); 755afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 756afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 757afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 758afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * We have special summaries when particular profiles are connected. This 759afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * checks for those states and returns an applicable summary. 760afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 761afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * @return A one-off summary that is applicable for the current state, or 0. 762afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 763afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private int getOneOffSummary() { 764afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project boolean isA2dpConnected = false, isHeadsetConnected = false, isConnecting = false; 765afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 766afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mProfiles.contains(Profile.A2DP)) { 767afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 768afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .getProfileManager(mLocalManager, Profile.A2DP); 769d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isConnecting = profileManager.getConnectionStatus(mDevice) == 770afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 771d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isA2dpConnected = profileManager.isConnected(mDevice); 772afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 773afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 774afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mProfiles.contains(Profile.HEADSET)) { 775afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 776afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .getProfileManager(mLocalManager, Profile.HEADSET); 777d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isConnecting |= profileManager.getConnectionStatus(mDevice) == 778afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 779d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isHeadsetConnected = profileManager.isConnected(mDevice); 780afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 781afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 782afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (isConnecting) { 783afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // If any of these important profiles is connecting, prefer that 784afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return SettingsBtStatus.getConnectionStatusSummary( 785afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project SettingsBtStatus.CONNECTION_STATUS_CONNECTING); 786afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (isA2dpConnected && isHeadsetConnected) { 787afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.string.bluetooth_summary_connected_to_a2dp_headset; 788afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (isA2dpConnected) { 789afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.string.bluetooth_summary_connected_to_a2dp; 790afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (isHeadsetConnected) { 791afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.string.bluetooth_summary_connected_to_headset; 792afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else { 793afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return 0; 794afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 795afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 796afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 797e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan public List<Profile> getConnectableProfiles() { 798e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan ArrayList<Profile> connectableProfiles = new ArrayList<Profile>(); 799e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan for (Profile profile : mProfiles) { 800e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (isConnectableProfile(profile)) { 801e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan connectableProfiles.add(profile); 802e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 803e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 804e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan return connectableProfiles; 805e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 806e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan 807e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan private boolean isConnectableProfile(Profile profile) { 808e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan return profile.equals(Profile.HEADSET) || profile.equals(Profile.A2DP); 809afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 810afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 811afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onCreateContextMenu(ContextMenu menu) { 812afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // No context menu if it is busy (none of these items are applicable if busy) 813ca564d6bdaa56fba60f499e092e1024fff5d1abaNick Pelly if (mLocalManager.getBluetoothState() != BluetoothAdapter.STATE_ON || isBusy()) { 814487843886dc1c822ee568bb0d77e3f78356dfb87Michael Chan return; 815487843886dc1c822ee568bb0d77e3f78356dfb87Michael Chan } 816afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 817afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int bondState = getBondState(); 818afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project boolean isConnected = isConnected(); 819e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan boolean hasConnectableProfiles = false; 820e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan 821e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan for (Profile profile : mProfiles) { 822e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (isConnectableProfile(profile)) { 823e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan hasConnectableProfiles = true; 824e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan break; 825e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 826e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 827afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 828afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project menu.setHeaderTitle(getName()); 829afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 83016cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly if (bondState == BluetoothDevice.BOND_NONE) { // Not paired and not connected 831fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_CONNECT, 0, R.string.bluetooth_device_context_pair_connect); 832fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } else { // Paired 833fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan if (isConnected) { // Paired and connected 834fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_DISCONNECT, 0, 835fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan R.string.bluetooth_device_context_disconnect); 836fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_UNPAIR, 0, 837fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan R.string.bluetooth_device_context_disconnect_unpair); 838fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } else { // Paired but not connected 839e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (hasConnectableProfiles) { 840fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_CONNECT, 0, R.string.bluetooth_device_context_connect); 841fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } 842fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_UNPAIR, 0, R.string.bluetooth_device_context_unpair); 843fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } 844afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 845afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Show the connection options item 846e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (hasConnectableProfiles) { 847fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_CONNECT_ADVANCED, 0, 848fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan R.string.bluetooth_device_context_connect_advanced); 849fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } 850afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 851afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 852afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 853afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 854afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Called when a context menu item is clicked. 855afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 856afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * @param item The item that was clicked. 857afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 858afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onContextItemSelected(MenuItem item) { 859afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project switch (item.getItemId()) { 860afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_DISCONNECT: 861afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(); 862afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 863afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 864afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_CONNECT: 865afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connect(); 866afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 867afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 868afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_UNPAIR: 869afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project unpair(); 870afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 871afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 872afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_CONNECT_ADVANCED: 873afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Intent intent = new Intent(); 874afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Need an activity context to open this in our task 875afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Context context = mLocalManager.getForegroundActivity(); 876afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (context == null) { 877afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Fallback on application context, and open in a new task 878afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project context = mLocalManager.getContext(); 879afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 880afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 881afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project intent.setClass(context, ConnectSpecificProfilesActivity.class); 882d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly intent.putExtra(ConnectSpecificProfilesActivity.EXTRA_DEVICE, mDevice); 883afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project context.startActivity(intent); 884afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 885afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 886afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 887afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 888afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void registerCallback(Callback callback) { 889afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project synchronized (mCallbacks) { 890afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mCallbacks.add(callback); 891afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 892afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 893afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 894afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void unregisterCallback(Callback callback) { 895afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project synchronized (mCallbacks) { 896afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mCallbacks.remove(callback); 897afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 898afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 899afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 900afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void dispatchAttributesChanged() { 901afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project synchronized (mCallbacks) { 902afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Callback callback : mCallbacks) { 903afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project callback.onDeviceAttributesChanged(this); 904afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 905afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 906afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 907afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 908afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 909afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public String toString() { 910d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.toString(); 911afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 912afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 913afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 914afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean equals(Object o) { 915d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if ((o == null) || !(o instanceof CachedBluetoothDevice)) { 916afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project throw new ClassCastException(); 917afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 918afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 919d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.equals(((CachedBluetoothDevice) o).mDevice); 920afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 921afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 922afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 923afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int hashCode() { 924d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.getAddress().hashCode(); 925afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 926afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 927d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly public int compareTo(CachedBluetoothDevice another) { 928afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int comparison; 929afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 930afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Connected above not connected 931afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0); 932afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 933afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 934afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Paired above not paired 935afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) - 936afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0); 937afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 938afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 939afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Visible above not visible 940afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0); 941afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 942afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 943afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Stronger signal above weaker signal 944afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = another.mRssi - mRssi; 945afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 946afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 947afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Fallback on name 948afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return getName().compareTo(another.getName()); 949afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 950afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 951afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public interface Callback { 952d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly void onDeviceAttributesChanged(CachedBluetoothDevice cachedDevice); 953afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 954afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project} 955