CachedBluetoothDevice.java revision 96b0c1dc0813f7e8c957ec17dc7751693926c6ae
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; 443327f7887328c55ef2d837a8e2a07cea2070c744Michael Chanimport java.util.Set; 45afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 46afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/** 47d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly * CachedBluetoothDevice represents a remote Bluetooth device. It contains 48afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * attributes of the device (such as the address, name, RSSI, etc.) and 49afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * functionality that can be performed on the device (connect, pair, disconnect, 50afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * etc.). 51afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 52d63c0112251ab4e4e977545368dd703d875012a4Nick Pellypublic class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { 53d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private static final String TAG = "CachedBluetoothDevice"; 54f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan private static final boolean D = LocalBluetoothManager.D; 55f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan private static final boolean V = LocalBluetoothManager.V; 56293867bd109383a1a26b35bf6accb92c0bad264cMichael Chan private static final boolean DEBUG = false; 57afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 58afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_CONNECT = Menu.FIRST + 1; 59afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_DISCONNECT = Menu.FIRST + 2; 60afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_UNPAIR = Menu.FIRST + 3; 61afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private static final int CONTEXT_ITEM_CONNECT_ADVANCED = Menu.FIRST + 4; 62afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 63d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private final BluetoothDevice mDevice; 64afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private String mName; 65afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private short mRssi; 6616cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly private BluetoothClass mBtClass; 67afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 68afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private List<Profile> mProfiles = new ArrayList<Profile>(); 69afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 70afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private boolean mVisible; 71afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 72afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private final LocalBluetoothManager mLocalManager; 73afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 74afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private List<Callback> mCallbacks = new ArrayList<Callback>(); 75afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 76afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 77afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * When we connect to multiple profiles, we only want to display a single 78afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * error even if they all fail. This tracks that state. 79afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 80afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private boolean mIsConnectingErrorPossible; 81afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 822aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan /** 83eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan * Last time a bt profile auto-connect was attempted. 84eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan * If an ACTION_UUID intent comes in within 852aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect 862aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * again with the new UUIDs 872aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan */ 88eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan private long mConnectAttempted; 892aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 90eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan // See mConnectAttempted 912aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000; 922aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 93e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Max time to hold the work queue if we don't get or missed a response 94e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // from the bt framework. 95e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private static final long MAX_WAIT_TIME_FOR_FRAMEWORK = 25 * 1000; 96e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 97e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private enum BluetoothCommand { 9896b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan CONNECT, DISCONNECT, REMOVE_BOND, 99e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 100e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 1018762093e0094e09493fa6cbac8e8fbf265f18165Michael Chan static class BluetoothJob { 102e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project final BluetoothCommand command; // CONNECT, DISCONNECT 103d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly final CachedBluetoothDevice cachedDevice; 104e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project final Profile profile; // HEADSET, A2DP, etc 105e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // 0 means this command was not been sent to the bt framework. 106e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project long timeSent; 107e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 108e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project public BluetoothJob(BluetoothCommand command, 109d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly CachedBluetoothDevice cachedDevice, Profile profile) { 110e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project this.command = command; 111d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly this.cachedDevice = cachedDevice; 112e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project this.profile = profile; 113e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project this.timeSent = 0; 114e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 115d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 116e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project @Override 117e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project public String toString() { 118e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project StringBuilder sb = new StringBuilder(); 119e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(command.name()); 120d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly sb.append(" Address:").append(cachedDevice.mDevice); 12196b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan if (profile != null) { 12296b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan sb.append(" Profile:").append(profile.name()); 12396b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan } 124e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(" TimeSent:"); 125e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (timeSent == 0) { 126e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append("not yet"); 127e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } else { 128e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project sb.append(DateFormat.getTimeInstance().format(new Date(timeSent))); 129e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 130e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return sb.toString(); 131e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 132e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 133e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 134e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project /** 135e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * We want to serialize connect and disconnect calls. http://b/170538 136e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * This are some headsets that may have L2CAP resource limitation. We want 137e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * to limit the bt bandwidth usage. 138e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * 139e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * A queue to keep track of asynchronous calls to the bt framework. The 140e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * first item, if exist, should be in progress i.e. went to the bt framework 141e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * already, waiting for a notification to come back. The second item and 142e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * beyond have not been sent to the bt framework yet. 143e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project */ 144e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private static LinkedList<BluetoothJob> workQueue = new LinkedList<BluetoothJob>(); 145e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 146e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private void queueCommand(BluetoothJob job) { 147e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project synchronized (workQueue) { 148792edfcf12f669378f218c13f8fd4e54d587d87aMichael Chan if (D) { 149792edfcf12f669378f218c13f8fd4e54d587d87aMichael Chan Log.d(TAG, workQueue.toString()); 150792edfcf12f669378f218c13f8fd4e54d587d87aMichael Chan } 151097ed6c671ed733c0967acc32e017020ede4575bMichael Chan boolean processNow = pruneQueue(job); 152e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 153e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Add job to queue 154f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 155f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "Adding: " + job.toString()); 156f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 157e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project workQueue.add(job); 158e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 159e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // if there's nothing pending from before, send the command to bt 160e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // framework immediately. 161e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (workQueue.size() == 1 || processNow) { 162e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // If the failed to process, just drop it from the queue. 163e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // There will be no callback to remove this from the queue. 164e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project processCommands(); 165e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 166e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 167e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 168d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 169097ed6c671ed733c0967acc32e017020ede4575bMichael Chan private boolean pruneQueue(BluetoothJob job) { 170097ed6c671ed733c0967acc32e017020ede4575bMichael Chan boolean removedStaleItems = false; 171097ed6c671ed733c0967acc32e017020ede4575bMichael Chan long now = System.currentTimeMillis(); 172097ed6c671ed733c0967acc32e017020ede4575bMichael Chan Iterator<BluetoothJob> it = workQueue.iterator(); 173097ed6c671ed733c0967acc32e017020ede4575bMichael Chan while (it.hasNext()) { 174097ed6c671ed733c0967acc32e017020ede4575bMichael Chan BluetoothJob existingJob = it.next(); 175097ed6c671ed733c0967acc32e017020ede4575bMichael Chan 176097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // Remove any pending CONNECTS when we receive a DISCONNECT 177097ed6c671ed733c0967acc32e017020ede4575bMichael Chan if (job != null && job.command == BluetoothCommand.DISCONNECT) { 178097ed6c671ed733c0967acc32e017020ede4575bMichael Chan if (existingJob.timeSent == 0 179097ed6c671ed733c0967acc32e017020ede4575bMichael Chan && existingJob.command == BluetoothCommand.CONNECT 180d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly && existingJob.cachedDevice.mDevice.equals(job.cachedDevice.mDevice) 181097ed6c671ed733c0967acc32e017020ede4575bMichael Chan && existingJob.profile == job.profile) { 182f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 183f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "Removed because of a pending disconnect. " + existingJob); 184f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 185097ed6c671ed733c0967acc32e017020ede4575bMichael Chan it.remove(); 186097ed6c671ed733c0967acc32e017020ede4575bMichael Chan continue; 187097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 188097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 189097ed6c671ed733c0967acc32e017020ede4575bMichael Chan 190097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // Defensive Code: Remove any job that older than a preset time. 191097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // We never got a call back. It is better to have overlapping 192097ed6c671ed733c0967acc32e017020ede4575bMichael Chan // calls than to get stuck. 193097ed6c671ed733c0967acc32e017020ede4575bMichael Chan if (existingJob.timeSent != 0 194097ed6c671ed733c0967acc32e017020ede4575bMichael Chan && (now - existingJob.timeSent) >= MAX_WAIT_TIME_FOR_FRAMEWORK) { 195097ed6c671ed733c0967acc32e017020ede4575bMichael Chan Log.w(TAG, "Timeout. Removing Job:" + existingJob.toString()); 196097ed6c671ed733c0967acc32e017020ede4575bMichael Chan it.remove(); 197097ed6c671ed733c0967acc32e017020ede4575bMichael Chan removedStaleItems = true; 198097ed6c671ed733c0967acc32e017020ede4575bMichael Chan continue; 199097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 200097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 201097ed6c671ed733c0967acc32e017020ede4575bMichael Chan return removedStaleItems; 202097ed6c671ed733c0967acc32e017020ede4575bMichael Chan } 203e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 204e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private boolean processCommand(BluetoothJob job) { 205e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project boolean successful = false; 206e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (job.timeSent == 0) { 207d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh job.timeSent = System.currentTimeMillis(); 208e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project switch (job.command) { 209e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project case CONNECT: 210d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly successful = connectInt(job.cachedDevice, job.profile); 211e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project break; 212e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project case DISCONNECT: 213d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly successful = disconnectInt(job.cachedDevice, job.profile); 214e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project break; 21596b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan case REMOVE_BOND: 21696b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan BluetoothDevice dev = job.cachedDevice.getDevice(); 21796b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan if (dev != null) { 21896b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan successful = dev.removeBond(); 21996b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan } 22096b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan break; 221e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 222e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 223e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (successful) { 224f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 225f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "Command sent successfully:" + job.toString()); 226f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 227f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } else if (V) { 228f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.v(TAG, "Framework rejected command immediately:" + job.toString()); 229e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 230f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } else if (D) { 231e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project Log.d(TAG, "Job already has a sent time. Skip. " + job.toString()); 232e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 233e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 234e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return successful; 235e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 236e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 2376c97742c88303c65e68fe08257a7ccf841f03866Michael Chan public void onProfileStateChanged(Profile profile, int newProfileState) { 238df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan synchronized (workQueue) { 239df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (D) { 240df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan Log.d(TAG, "onProfileStateChanged:" + workQueue.toString()); 241f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 242097ed6c671ed733c0967acc32e017020ede4575bMichael Chan 243df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan int newState = LocalBluetoothProfileManager.getProfileManager(mLocalManager, 244df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan profile).convertState(newProfileState); 245df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan 246df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED) { 247df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (!mProfiles.contains(profile)) { 248df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan mProfiles.add(profile); 2496c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 250df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 2516c97742c88303c65e68fe08257a7ccf841f03866Michael Chan 252df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan /* Ignore the transient states e.g. connecting, disconnecting */ 253df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED || 254df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan newState == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) { 255df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan BluetoothJob job = workQueue.peek(); 256df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (job == null) { 2576c97742c88303c65e68fe08257a7ccf841f03866Michael Chan return; 258df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } else if (!job.cachedDevice.mDevice.equals(mDevice)) { 259df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan // This can happen in 2 cases: 1) BT device initiated pairing and 260df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan // 2) disconnects of one headset that's triggered by connects of 261df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan // another. 262df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (D) { 263df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan Log.d(TAG, "mDevice:" + mDevice + " != head:" + job.toString()); 264df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 265df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan 266df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan // Check to see if we need to remove the stale items from the queue 267df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan if (!pruneQueue(null)) { 268df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan // nothing in the queue was modify. Just ignore the notification and return. 269df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan return; 270df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 271df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } else { 272df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan // Remove the first item and process the next one 273df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan workQueue.poll(); 2746c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 275e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 276df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan processCommands(); 277df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 2786c97742c88303c65e68fe08257a7ccf841f03866Michael Chan } 279e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 280e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 281e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project /* 282e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * This method is called in 2 places: 283e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * 1) queryCommand() - when someone or something want to connect or 284e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * disconnect 285e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * 2) onProfileStateChanged() - when the framework sends an intent 286e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * notification when it finishes processing a command 287e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project */ 288e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project private void processCommands() { 289f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan if (D) { 290f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan Log.d(TAG, "processCommands:" + workQueue.toString()); 291f25063aee3d8eeaf3767b3a4bf43e1895f2deb2dMichael Chan } 292e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project Iterator<BluetoothJob> it = workQueue.iterator(); 293e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project while (it.hasNext()) { 294e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project BluetoothJob job = it.next(); 295e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project if (processCommand(job)) { 296e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Sent to bt framework. Done for now. Will remove this job 297e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // from queue when we get an event 298e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return; 299e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } else { 300e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project /* 301e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * If the command failed immediately, there will be no event 302e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * callbacks. So delete the job immediately and move on to the 303e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project * next one 304e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project */ 305e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project it.remove(); 306e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 307e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 308e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 309e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 310d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly CachedBluetoothDevice(Context context, BluetoothDevice device) { 311afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mLocalManager = LocalBluetoothManager.getInstance(context); 312afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mLocalManager == null) { 313afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project throw new IllegalStateException( 314d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly "Cannot use CachedBluetoothDevice without Bluetooth hardware"); 315afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 316afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 317d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mDevice = device; 318afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 319afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fillData(); 320afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 321afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 322afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onClicked() { 323afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int bondState = getBondState(); 324afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 325afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (isConnected()) { 326afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project askDisconnect(); 327afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (bondState == BluetoothDevice.BOND_BONDED) { 328afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connect(); 32916cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly } else if (bondState == BluetoothDevice.BOND_NONE) { 330afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project pair(); 331afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 332afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 333afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 334afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void disconnect() { 335afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 336afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(profile); 337afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 338afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 339afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 340afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void disconnect(Profile profile) { 341e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project queueCommand(new BluetoothJob(BluetoothCommand.DISCONNECT, this, profile)); 342e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 343e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 344d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private boolean disconnectInt(CachedBluetoothDevice cachedDevice, Profile profile) { 345afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = 346afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 347d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly int status = profileManager.getConnectionStatus(cachedDevice.mDevice); 348afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusConnected(status)) { 349f4779354b39353a48d0bec6cc5c71fd73e3f369aNick Pelly if (profileManager.disconnect(cachedDevice.mDevice)) { 350e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return true; 351e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 352afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 353e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return false; 354afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 355afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 356afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void askDisconnect() { 357afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Context context = mLocalManager.getForegroundActivity(); 358afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (context == null) { 359afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Cannot ask, since we need an activity context 360afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(); 361afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return; 362afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 363afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 364afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Resources res = context.getResources(); 365afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 366afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project String name = getName(); 367afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (TextUtils.isEmpty(name)) { 368afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project name = res.getString(R.string.bluetooth_device); 369afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 370afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project String message = res.getString(R.string.bluetooth_disconnect_blank, name); 371afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 372afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() { 373afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onClick(DialogInterface dialog, int which) { 374afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(); 375afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 376afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project }; 377afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 3788762093e0094e09493fa6cbac8e8fbf265f18165Michael Chan new AlertDialog.Builder(context) 379afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setTitle(getName()) 380afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setMessage(message) 381afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setPositiveButton(android.R.string.ok, disconnectListener) 382afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .setNegativeButton(android.R.string.cancel, null) 383afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .show(); 384afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 385afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 386afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void connect() { 387afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!ensurePaired()) return; 388afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 389eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan mConnectAttempted = SystemClock.elapsedRealtime(); 390eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan 391eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan connectWithoutResettingTimer(); 392eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 393eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan 394b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh /*package*/ void onBondingDockConnect() { 395b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh // Don't connect just set the timer. 396b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh // TODO(): Fix the actual problem 397b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh mConnectAttempted = SystemClock.elapsedRealtime(); 398b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh } 399b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh 400eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan private void connectWithoutResettingTimer() { 4012aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan // Try to initialize the profiles if there were not. 4022aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (mProfiles.size() == 0) { 4032aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (!updateProfiles()) { 4042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan // If UUIDs are not available yet, connect will be happen 4052aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan // upon arrival of the ACTION_UUID intent. 406eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) Log.d(TAG, "No profiles. Maybe we will connect later"); 4072aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan return; 4082aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 4092aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 4102aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 411afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Reset the only-show-one-error-dialog tracking variable 412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = true; 413afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 414eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan int preferredProfiles = 0; 415afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 416b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan if (isConnectableProfile(profile)) { 417b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 418b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan .getProfileManager(mLocalManager, profile); 419b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan if (profileManager.isPreferred(mDevice)) { 420b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan ++preferredProfiles; 4213327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan disconnectConnected(profile); 422b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); 423b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan } 424afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 425afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 426eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles); 427afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 428eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (preferredProfiles == 0) { 429eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan connectAllProfiles(); 430afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 431afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 433eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan private void connectAllProfiles() { 434afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!ensurePaired()) return; 435afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 436afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Reset the only-show-one-error-dialog tracking variable 437afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = true; 438afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 439afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 440b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan if (isConnectableProfile(profile)) { 441b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 442b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan .getProfileManager(mLocalManager, profile); 443b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan profileManager.setPreferred(mDevice, false); 4443327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan disconnectConnected(profile); 445b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); 446b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan } 447afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 448afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 449afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 450afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void connect(Profile profile) { 451eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan mConnectAttempted = SystemClock.elapsedRealtime(); 452afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Reset the only-show-one-error-dialog tracking variable 453afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = true; 4543327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan disconnectConnected(profile); 455e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); 456afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 457afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 4583327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan private void disconnectConnected(Profile profile) { 4593327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan LocalBluetoothProfileManager profileManager = 4603327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 4613327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan CachedBluetoothDeviceManager cachedDeviceManager = mLocalManager.getCachedDeviceManager(); 4623327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan Set<BluetoothDevice> devices = profileManager.getConnectedDevices(); 4633327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan if (devices == null) return; 4643327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan for (BluetoothDevice device : devices) { 4653327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(device); 4663327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan if (cachedDevice != null) { 4673327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan queueCommand(new BluetoothJob(BluetoothCommand.DISCONNECT, cachedDevice, profile)); 4683327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan } 4693327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan } 4703327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan } 4713327f7887328c55ef2d837a8e2a07cea2070c744Michael Chan 472d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly private boolean connectInt(CachedBluetoothDevice cachedDevice, Profile profile) { 473d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (!cachedDevice.ensurePaired()) return false; 474afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 475afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = 476afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); 477d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly int status = profileManager.getConnectionStatus(cachedDevice.mDevice); 478afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!SettingsBtStatus.isConnectionStatusConnected(status)) { 479f4779354b39353a48d0bec6cc5c71fd73e3f369aNick Pelly if (profileManager.connect(cachedDevice.mDevice)) { 480e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return true; 481afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 482d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly Log.i(TAG, "Failed to connect " + profile.toString() + " to " + cachedDevice.mName); 483eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } else { 484eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan Log.i(TAG, "Already connected"); 485afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 486e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project return false; 487afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 488afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 489afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void showConnectingError() { 490afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (!mIsConnectingErrorPossible) return; 491afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mIsConnectingErrorPossible = false; 492afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 493d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mLocalManager.showError(mDevice, R.string.bluetooth_error_title, 494afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project R.string.bluetooth_connecting_error_message); 495afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 496afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 497afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private boolean ensurePaired() { 49816cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly if (getBondState() == BluetoothDevice.BOND_NONE) { 499afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project pair(); 500afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return false; 501afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else { 502afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 503afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 504afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 505afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 506afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void pair() { 507d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter(); 508afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 509afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Pairing is unreliable while scanning, so cancel discovery 510d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (adapter.isDiscovering()) { 511d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly adapter.cancelDiscovery(); 512afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 513afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 514d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if (!mDevice.createBond()) { 515d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mLocalManager.showError(mDevice, R.string.bluetooth_error_title, 516afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project R.string.bluetooth_pairing_error_message); 517afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 518afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 519afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 520afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void unpair() { 52196b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan disconnect(); 522e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 52396b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan int state = getBondState(); 524afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 52596b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan if (state == BluetoothDevice.BOND_BONDING) { 526d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mDevice.cancelBondProcess(); 52796b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan } 52896b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan 52996b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan if (state != BluetoothDevice.BOND_NONE) { 53096b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan queueCommand(new BluetoothJob(BluetoothCommand.REMOVE_BOND, this, null)); 531afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 532afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 533afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 534afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void fillData() { 535afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchName(); 536afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchBtClass(); 5372aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan updateProfiles(); 538afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 539afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mVisible = false; 540afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 541afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 542afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 543afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 544d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly public BluetoothDevice getDevice() { 545d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice; 546afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 547afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 548afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public String getName() { 549afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return mName; 550afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 551afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 552d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh public void setName(String name) { 553d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh if (!mName.equals(name)) { 554d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh if (TextUtils.isEmpty(name)) { 555d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mName = mDevice.getAddress(); 556d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } else { 557d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh mName = name; 558d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 559d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh dispatchAttributesChanged(); 560d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 561d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 562d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 563afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void refreshName() { 564afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchName(); 565afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 566afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 567afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 568afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void fetchName() { 569d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mName = mDevice.getName(); 570afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 571afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (TextUtils.isEmpty(mName)) { 572d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mName = mDevice.getAddress(); 573eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) Log.d(TAG, "Default to address. Device has no name (yet) " + mName); 574afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 575afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 576afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 577afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void refresh() { 578afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 579afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 580afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 581afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean isVisible() { 582afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return mVisible; 583afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 584afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 585afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project void setVisible(boolean visible) { 586afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mVisible != visible) { 587afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mVisible = visible; 588afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 589afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 590afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 591afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 592afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int getBondState() { 593d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.getBondState(); 594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project void setRssi(short rssi) { 597afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mRssi != rssi) { 598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mRssi = rssi; 599afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 600afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 601afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 602afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 603afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Checks whether we are connected to this device (any profile counts). 605afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 606afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * @return Whether it is connected. 607afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 608afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean isConnected() { 609afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile) 611d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly .getConnectionStatus(mDevice); 612afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusConnected(status)) { 613afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 614afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 615afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return false; 618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 619afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 620afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean isBusy() { 621afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 622afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile) 623d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly .getConnectionStatus(mDevice); 624afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusBusy(status)) { 625afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 626afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 627afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 628afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 629afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (getBondState() == BluetoothDevice.BOND_BONDING) { 630afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return true; 631afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 632afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 633afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return false; 634afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 635afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 636afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int getBtClassDrawable() { 6374d004e910732565ddd449c7c525f7d6cbd353392Michael Chan if (mBtClass != null) { 6384d004e910732565ddd449c7c525f7d6cbd353392Michael Chan switch (mBtClass.getMajorDeviceClass()) { 6394d004e910732565ddd449c7c525f7d6cbd353392Michael Chan case BluetoothClass.Device.Major.COMPUTER: 6404d004e910732565ddd449c7c525f7d6cbd353392Michael Chan return R.drawable.ic_bt_laptop; 641afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 6424d004e910732565ddd449c7c525f7d6cbd353392Michael Chan case BluetoothClass.Device.Major.PHONE: 6434d004e910732565ddd449c7c525f7d6cbd353392Michael Chan return R.drawable.ic_bt_cellphone; 6444d004e910732565ddd449c7c525f7d6cbd353392Michael Chan } 6454d004e910732565ddd449c7c525f7d6cbd353392Michael Chan } else { 6464d004e910732565ddd449c7c525f7d6cbd353392Michael Chan Log.w(TAG, "mBtClass is null"); 6473e1c1d19201e625888cdd07e06ea9502d7c4dafbMichael Chan } 648afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 649cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mProfiles.size() > 0) { 650cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mProfiles.contains(Profile.A2DP)) { 651cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headphones_a2dp; 652cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } else if (mProfiles.contains(Profile.HEADSET)) { 653cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headset_hfp; 654cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } 6554d004e910732565ddd449c7c525f7d6cbd353392Michael Chan } else if (mBtClass != null) { 656cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { 657cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headphones_a2dp; 658cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan 659cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } 660cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { 661cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return R.drawable.ic_bt_headset_hfp; 662cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan } 663afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 664cb844e2eab4efa03513c0e0a2de7bc18c79dd128Michael Chan return 0; 665afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 666afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 667afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 668afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Fetches a new value for the cached BT class. 669afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 670afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void fetchBtClass() { 671d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly mBtClass = mDevice.getBluetoothClass(); 6722aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 6732aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6742aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private boolean updateProfiles() { 6752aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan ParcelUuid[] uuids = mDevice.getUuids(); 6762aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (uuids == null) return false; 6772aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6782aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan LocalBluetoothProfileManager.updateProfiles(uuids, mProfiles); 6792aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6802aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (DEBUG) { 6812aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.e(TAG, "updating profiles for " + mDevice.getName()); 6822aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 6832aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan boolean printUuids = true; 6842aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan BluetoothClass bluetoothClass = mDevice.getBluetoothClass(); 6852aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 686a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan if (bluetoothClass != null) { 687a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET) != 688a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan mProfiles.contains(Profile.HEADSET)) { 689a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan Log.v(TAG, "headset classbits != uuid"); 690a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan printUuids = true; 691a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan } 6922aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 693a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) != 694a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan mProfiles.contains(Profile.A2DP)) { 695a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan Log.v(TAG, "a2dp classbits != uuid"); 696a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan printUuids = true; 697a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan } 6982aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 699a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP) != 700a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan mProfiles.contains(Profile.OPP)) { 701a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan Log.v(TAG, "opp classbits != uuid"); 702a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan printUuids = true; 703a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan } 7042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 7052aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 7062aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (printUuids) { 707a87f2fd7d82e5055e0f9ea2c93704ed0b58f27efMichael Chan if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString()); 7082aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, "UUID:"); 7092aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan for (int i = 0; i < uuids.length; i++) { 7102aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan Log.v(TAG, " " + uuids[i]); 7112aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 7122aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 713b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly } 7142aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan return true; 715afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 716afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 717afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 718afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Refreshes the UI for the BT class, including fetching the latest value 719afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * for the class. 720afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 721afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void refreshBtClass() { 722afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project fetchBtClass(); 723afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project dispatchAttributesChanged(); 724afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 725afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 7262aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan /** 7272aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * Refreshes the UI when framework alerts us of a UUID change. 7282aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan */ 7292aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan public void onUuidChanged() { 7302aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan updateProfiles(); 7312aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 732eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (DEBUG) { 733eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan Log.e(TAG, "onUuidChanged: Time since last connect" 734eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan + (SystemClock.elapsedRealtime() - mConnectAttempted)); 735eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 7362aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 7372aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan /* 7382aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * If a connect was attempted earlier without any UUID, we will do the 7392aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan * connect now. 7402aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan */ 7412aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan if (mProfiles.size() > 0 742eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock 7432aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan .elapsedRealtime()) { 744eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan connectWithoutResettingTimer(); 7452aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 7462aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan dispatchAttributesChanged(); 7472aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan } 7482aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 749eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan public void onBondingStateChanged(int bondState) { 750eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan if (bondState == BluetoothDevice.BOND_NONE) { 751eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan mProfiles.clear(); 752eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 753eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan refresh(); 754eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan } 755eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan 75616cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly public void setBtClass(BluetoothClass btClass) { 75716cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly if (btClass != null && mBtClass != btClass) { 758d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh mBtClass = btClass; 759d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh dispatchAttributesChanged(); 760d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 761d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh } 762d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh 763afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int getSummary() { 764afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // TODO: clean up 765afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int oneOffSummary = getOneOffSummary(); 766afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (oneOffSummary != 0) { 767afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return oneOffSummary; 768afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 769afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 770afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Profile profile : mProfiles) { 771afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 772afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .getProfileManager(mLocalManager, profile); 773d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly int connectionStatus = profileManager.getConnectionStatus(mDevice); 774afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 775afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus) || 776afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connectionStatus == SettingsBtStatus.CONNECTION_STATUS_CONNECTING || 777afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING) { 778afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return SettingsBtStatus.getConnectionStatusSummary(connectionStatus); 779afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 780afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 781afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 782afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return SettingsBtStatus.getPairingStatusSummary(getBondState()); 783afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 784afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 785afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 786afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * We have special summaries when particular profiles are connected. This 787afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * checks for those states and returns an applicable summary. 788afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 789afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * @return A one-off summary that is applicable for the current state, or 0. 790afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 791afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private int getOneOffSummary() { 792afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project boolean isA2dpConnected = false, isHeadsetConnected = false, isConnecting = false; 793afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 794afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mProfiles.contains(Profile.A2DP)) { 795afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 796afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .getProfileManager(mLocalManager, Profile.A2DP); 797d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isConnecting = profileManager.getConnectionStatus(mDevice) == 798afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 799d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isA2dpConnected = profileManager.isConnected(mDevice); 800afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 801afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 802afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (mProfiles.contains(Profile.HEADSET)) { 803afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 804afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project .getProfileManager(mLocalManager, Profile.HEADSET); 805d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isConnecting |= profileManager.getConnectionStatus(mDevice) == 806afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project SettingsBtStatus.CONNECTION_STATUS_CONNECTING; 807d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly isHeadsetConnected = profileManager.isConnected(mDevice); 808afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 809afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 810afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (isConnecting) { 811afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // If any of these important profiles is connecting, prefer that 812afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return SettingsBtStatus.getConnectionStatusSummary( 813afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project SettingsBtStatus.CONNECTION_STATUS_CONNECTING); 814afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (isA2dpConnected && isHeadsetConnected) { 815afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.string.bluetooth_summary_connected_to_a2dp_headset; 816afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (isA2dpConnected) { 817afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.string.bluetooth_summary_connected_to_a2dp; 818afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else if (isHeadsetConnected) { 819afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return R.string.bluetooth_summary_connected_to_headset; 820afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } else { 821afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return 0; 822afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 823afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 824afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 825e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan public List<Profile> getConnectableProfiles() { 826e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan ArrayList<Profile> connectableProfiles = new ArrayList<Profile>(); 827e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan for (Profile profile : mProfiles) { 828e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (isConnectableProfile(profile)) { 829e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan connectableProfiles.add(profile); 830e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 831e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 832e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan return connectableProfiles; 833e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 834e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan 835e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan private boolean isConnectableProfile(Profile profile) { 836e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan return profile.equals(Profile.HEADSET) || profile.equals(Profile.A2DP); 837afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 838afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 839afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onCreateContextMenu(ContextMenu menu) { 840afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // No context menu if it is busy (none of these items are applicable if busy) 841ca564d6bdaa56fba60f499e092e1024fff5d1abaNick Pelly if (mLocalManager.getBluetoothState() != BluetoothAdapter.STATE_ON || isBusy()) { 842487843886dc1c822ee568bb0d77e3f78356dfb87Michael Chan return; 843487843886dc1c822ee568bb0d77e3f78356dfb87Michael Chan } 844afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 845afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int bondState = getBondState(); 846afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project boolean isConnected = isConnected(); 847e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan boolean hasConnectableProfiles = false; 848e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan 849e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan for (Profile profile : mProfiles) { 850e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (isConnectableProfile(profile)) { 851e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan hasConnectableProfiles = true; 852e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan break; 853e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 854e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan } 855afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 856afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project menu.setHeaderTitle(getName()); 857afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 85816cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly if (bondState == BluetoothDevice.BOND_NONE) { // Not paired and not connected 859fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_CONNECT, 0, R.string.bluetooth_device_context_pair_connect); 860fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } else { // Paired 861fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan if (isConnected) { // Paired and connected 862fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_DISCONNECT, 0, 863fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan R.string.bluetooth_device_context_disconnect); 864fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_UNPAIR, 0, 865fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan R.string.bluetooth_device_context_disconnect_unpair); 866fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } else { // Paired but not connected 867e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (hasConnectableProfiles) { 868fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_CONNECT, 0, R.string.bluetooth_device_context_connect); 869fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } 870fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_UNPAIR, 0, R.string.bluetooth_device_context_unpair); 871fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } 872afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 873afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Show the connection options item 874e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan if (hasConnectableProfiles) { 875fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan menu.add(0, CONTEXT_ITEM_CONNECT_ADVANCED, 0, 876fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan R.string.bluetooth_device_context_connect_advanced); 877fdfb90f9e8207702700093888d0de6dea9a198ebMichael Chan } 878afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 879afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 880afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 881afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 882afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Called when a context menu item is clicked. 883afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 884afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * @param item The item that was clicked. 885afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 886afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onContextItemSelected(MenuItem item) { 887afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project switch (item.getItemId()) { 888afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_DISCONNECT: 889afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project disconnect(); 890afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 891afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 892afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_CONNECT: 893afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project connect(); 894afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 895afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 896afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_UNPAIR: 897afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project unpair(); 898afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 899afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 900afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project case CONTEXT_ITEM_CONNECT_ADVANCED: 901afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Intent intent = new Intent(); 902afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Need an activity context to open this in our task 903afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project Context context = mLocalManager.getForegroundActivity(); 904afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (context == null) { 905afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Fallback on application context, and open in a new task 906afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project context = mLocalManager.getContext(); 907afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 908afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 909afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project intent.setClass(context, ConnectSpecificProfilesActivity.class); 910d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly intent.putExtra(ConnectSpecificProfilesActivity.EXTRA_DEVICE, mDevice); 911afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project context.startActivity(intent); 912afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project break; 913afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 914afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 915afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 916afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void registerCallback(Callback callback) { 917afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project synchronized (mCallbacks) { 918afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mCallbacks.add(callback); 919afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 920afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 921afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 922afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void unregisterCallback(Callback callback) { 923afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project synchronized (mCallbacks) { 924afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project mCallbacks.remove(callback); 925afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 926afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 927afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 928afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project private void dispatchAttributesChanged() { 929afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project synchronized (mCallbacks) { 930afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project for (Callback callback : mCallbacks) { 931afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project callback.onDeviceAttributesChanged(this); 932afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 933afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 934afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 935afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 936afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 937afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public String toString() { 938d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.toString(); 939afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 940afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 941afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 942afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public boolean equals(Object o) { 943d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly if ((o == null) || !(o instanceof CachedBluetoothDevice)) { 944afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project throw new ClassCastException(); 945afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 946afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 947d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.equals(((CachedBluetoothDevice) o).mDevice); 948afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 949afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 950afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 951afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public int hashCode() { 952d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly return mDevice.getAddress().hashCode(); 953afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 954afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 955d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly public int compareTo(CachedBluetoothDevice another) { 956afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int comparison; 957afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 958afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Connected above not connected 959afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0); 960afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 961afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 962afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Paired above not paired 963afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) - 964afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0); 965afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 966afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 967afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Visible above not visible 968afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0); 969afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 970afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 971afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Stronger signal above weaker signal 972afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project comparison = another.mRssi - mRssi; 973afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project if (comparison != 0) return comparison; 974afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 975afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project // Fallback on name 976afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project return getName().compareTo(another.getName()); 977afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 978afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 979afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public interface Callback { 980d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly void onDeviceAttributesChanged(CachedBluetoothDevice cachedDevice); 981afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 982afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project} 983