CachedBluetoothDevice.java revision 3fd5e2839fba6afc18d99006d61c063c2ed4f121
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
192aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chanimport android.bluetooth.BluetoothClass;
20e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
21436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.bluetooth.BluetoothProfile;
22b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xieimport android.content.Context;
23b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xieimport android.content.SharedPreferences;
24e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chanimport android.os.ParcelUuid;
252aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chanimport android.os.SystemClock;
26afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.text.TextUtils;
27afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.util.Log;
282ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balajiimport android.bluetooth.BluetoothAdapter;
29afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.ArrayList;
31436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Collection;
32436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Collections;
3350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganeshimport java.util.HashMap;
34afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.List;
35afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
36afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/**
37d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly * CachedBluetoothDevice represents a remote Bluetooth device. It contains
38afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * attributes of the device (such as the address, name, RSSI, etc.) and
39afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * functionality that can be performed on the device (connect, pair, disconnect,
40afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * etc.).
41afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */
42436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyfinal class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
43d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly    private static final String TAG = "CachedBluetoothDevice";
44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static final boolean DEBUG = Utils.V;
45afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
46b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private final Context mContext;
47436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final LocalBluetoothAdapter mLocalAdapter;
48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final LocalBluetoothProfileManager mProfileManager;
49d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly    private final BluetoothDevice mDevice;
50afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private String mName;
51afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private short mRssi;
5216cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly    private BluetoothClass mBtClass;
5350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
54afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
55436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final List<LocalBluetoothProfile> mProfiles =
56436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            new ArrayList<LocalBluetoothProfile>();
57afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
58c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    // List of profiles that were previously in mProfiles, but have been removed
59c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    private final List<LocalBluetoothProfile> mRemovedProfiles =
60c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            new ArrayList<LocalBluetoothProfile>();
61c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby
62c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    // Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP
63c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    private boolean mLocalNapRoleConnected;
64c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby
65afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mVisible;
66afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
67b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private int mPhonebookPermissionChoice;
68b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
695b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    private int mMessagePermissionChoice;
705b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
713fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu    private int mPhonebookRejectedTimes = 0;
723fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu
733fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu    private int mMessageRejectedTimes = 0;
745b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
75436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
76afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
775b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    // Following constants indicate the user's choices of Phone book/message access settings
78b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User hasn't made any choice or settings app has wiped out the memory
795b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    final static int ACCESS_UNKNOWN = 0;
80b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User has accepted the connection and let Settings app remember the decision
815b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    final static int ACCESS_ALLOWED = 1;
82b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User has rejected the connection and let Settings app remember the decision
835b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    final static int ACCESS_REJECTED = 2;
845b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
853fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu    // how many times did User reject the connection to make the rejected persist.
863fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu    final static int PERSIST_REJECTED_TIMES_LIMIT = 2;
87b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
88b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private final static String PHONEBOOK_PREFS_NAME = "bluetooth_phonebook_permission";
895b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    private final static String MESSAGE_PREFS_NAME = "bluetooth_message_permission";
90b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
91afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
92afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * When we connect to multiple profiles, we only want to display a single
93afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * error even if they all fail. This tracks that state.
94afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
95afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mIsConnectingErrorPossible;
96afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
972aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
98eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * Last time a bt profile auto-connect was attempted.
99eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * If an ACTION_UUID intent comes in within
1002aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
1012aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * again with the new UUIDs
1022aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
103eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    private long mConnectAttempted;
1042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
105eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    // See mConnectAttempted
1062aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
1072aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
108dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    /** Auto-connect after pairing only if locally initiated. */
109dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    private boolean mConnectAfterPairing;
11084905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
111e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    /**
112f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * Describes the current device and profile for logging.
11384905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh     *
114f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @param profile Profile to describe
115f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @return Description of the device and profile
116e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     */
117436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private String describe(LocalBluetoothProfile profile) {
118f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        StringBuilder sb = new StringBuilder();
119e79f990490de49b39097433707c2bae6d8238330Jake Hamby        sb.append("Address:").append(mDevice);
120f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        if (profile != null) {
121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            sb.append(" Profile:").append(profile);
122097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        }
123e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
124f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        return sb.toString();
125f907e0bb891eca4d498871a1cc862117a462a076Adam Powell    }
12684905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
127436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
128436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (Utils.D) {
129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Log.d(TAG, "onProfileStateChanged: profile " + profile +
130f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    " newProfileState " + newProfileState);
1316c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        }
1327951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
1337951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        {
1347951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
1357951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            return;
1367951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
13750e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState.put(profile, newProfileState);
138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
139f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (!mProfiles.contains(profile)) {
140c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                mRemovedProfiles.remove(profile);
141f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                mProfiles.add(profile);
142c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                if (profile instanceof PanProfile &&
143c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                        ((PanProfile) profile).isLocalRoleNap(mDevice)) {
144c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    // Device doesn't support NAP, so remove PanProfile on disconnect
145c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    mLocalNapRoleConnected = true;
146c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                }
147e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
1485d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            if (profile instanceof MapProfile) {
1495d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                profile.setPreferred(mDevice, true);
1505d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                refresh();
1515d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            }
1525d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz        } else if (profile instanceof MapProfile &&
1535d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
1545d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            if (mProfiles.contains(profile)) {
1555d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                mRemovedProfiles.add(profile);
1565d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                mProfiles.remove(profile);
1575d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            }
1585d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            profile.setPreferred(mDevice, false);
1595d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            refresh();
160c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        } else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
161c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                ((PanProfile) profile).isLocalRoleNap(mDevice) &&
162c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
163c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
164c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mProfiles.remove(profile);
165c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mRemovedProfiles.add(profile);
166c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mLocalNapRoleConnected = false;
167e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
168e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
169e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
170b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    CachedBluetoothDevice(Context context,
171b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothAdapter adapter,
172b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothProfileManager profileManager,
173b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          BluetoothDevice device) {
174b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mContext = context;
175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mLocalAdapter = adapter;
176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mProfileManager = profileManager;
177d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mDevice = device;
17850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
179afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fillData();
180afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
181afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
182436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect() {
183436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
184afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            disconnect(profile);
185afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
1860654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // Disconnect  PBAP server in case its connected
1870654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // This is to ensure all the profiles are disconnected as some CK/Hs do not
1880654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // disconnect  PBAP connection when HF connection is brought down
1890654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
1900654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
1910654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        {
1920654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta            PbapProfile.disconnect(mDevice);
1930654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        }
194afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
195afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
196436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect(LocalBluetoothProfile profile) {
197436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.disconnect(mDevice)) {
198436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
199d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
200f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
201afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
202afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
203afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
204436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connect(boolean connectAllProfiles) {
205436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
206afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return;
207afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
208afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
209eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
2104bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connectWithoutResettingTimer(connectAllProfiles);
211eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
212eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
213436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingDockConnect() {
214582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // Attempt to connect if UUIDs are available. Otherwise,
215582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // we will connect when the ACTION_UUID intent arrives.
2164bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connect(false);
217b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh    }
218b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh
21939ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby    private void connectWithoutResettingTimer(boolean connectAllProfiles) {
220a0d39a39c2f53ebe858685c75c756b51dfac49daJake Hamby        // Try to initialize the profiles if they were not.
221436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mProfiles.isEmpty()) {
2226e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
2236e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
2246e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // from bluetooth stack but ACTION.uuid is not sent yet.
2256e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // Eventually ACTION.uuid will be received which shall trigger the connection of the
2266e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // various profiles
2276e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // If UUIDs are not available yet, connect will be happen
2286e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // upon arrival of the ACTION_UUID intent.
2296e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            Log.d(TAG, "No profiles. Maybe we will connect later");
2306e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            return;
2312aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
2322aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
233afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
234afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
235afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
236eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        int preferredProfiles = 0;
237436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
23839ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
239436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (profile.isPreferred(mDevice)) {
240b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                    ++preferredProfiles;
241436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    connectInt(profile);
242b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                }
243afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
244afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
245eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
246afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
247eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (preferredProfiles == 0) {
248436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            connectAutoConnectableProfiles();
249afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
250afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
251afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
252436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private void connectAutoConnectableProfiles() {
253436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
255436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
256afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
257afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
258afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
259436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
26039ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isAutoConnectable()) {
261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                profile.setPreferred(mDevice, true);
262436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                connectInt(profile);
263b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan            }
264afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
265afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
266afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
267436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /**
268436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * Connect this device to the specified profile.
269436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     *
270436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * @param profile the profile to use with the remote device
271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     */
272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connectProfile(LocalBluetoothProfile profile) {
273eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
274afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
275afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
276436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        connectInt(profile);
277f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        // Refresh the UI based on profile.connect() call
278f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        refresh();
279afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
280afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
2812ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji    synchronized void connectInt(LocalBluetoothProfile profile) {
282436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
283436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
284436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
285436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.connect(mDevice)) {
286436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
287d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
288afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
289436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
290afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
291436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
292afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
293afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
294afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean ensurePaired() {
29516cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (getBondState() == BluetoothDevice.BOND_NONE) {
296436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            startPairing();
297afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return false;
298afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else {
299afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return true;
300afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
301afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
302afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
303436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean startPairing() {
304afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Pairing is unreliable while scanning, so cancel discovery
305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mLocalAdapter.isDiscovering()) {
306436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mLocalAdapter.cancelDiscovery();
307afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
308afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
309d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if (!mDevice.createBond()) {
310436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
311afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
312dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
313dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        mConnectAfterPairing = true;  // auto-connect after pairing
314436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return true;
315afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
316afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
317ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    /**
318ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * Return true if user initiated pairing on this device. The message text is
319ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * slightly different for local vs. remote initiated pairing dialogs.
320ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     */
321ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    boolean isUserInitiatedPairing() {
322ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby        return mConnectAfterPairing;
323ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    }
324ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby
325436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unpair() {
32696b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        int state = getBondState();
327afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
32896b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state == BluetoothDevice.BOND_BONDING) {
329d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mDevice.cancelBondProcess();
33096b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        }
33196b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan
33296b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state != BluetoothDevice.BOND_NONE) {
333436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            final BluetoothDevice dev = mDevice;
334f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (dev != null) {
335f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                final boolean successful = dev.removeBond();
336f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                if (successful) {
337436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    if (Utils.D) {
338f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                        Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
339f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    }
340436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                } else if (Utils.V) {
341f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
342f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                            describe(null));
343f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                }
344f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
345afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
346afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
347afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
34850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    int getProfileConnectionState(LocalBluetoothProfile profile) {
34950e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        if (mProfileConnectionState == null ||
35050e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh                mProfileConnectionState.get(profile) == null) {
35150e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            // If cache is empty make the binder call to get the state
35250e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int state = profile.getConnectionStatus(mDevice);
35350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            mProfileConnectionState.put(profile, state);
35450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        }
35550e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        return mProfileConnectionState.get(profile);
35650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    }
35750e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh
3587951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    public void clearProfileConnectionState ()
3597951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    {
3607951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        if (Utils.D) {
3617951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
3627951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
3637951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        for (LocalBluetoothProfile profile :getProfiles()) {
3647951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
3657951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
3667951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    }
3677951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta
368436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // TODO: do any of these need to run async on a background thread?
369afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fillData() {
370afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
371afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
3722aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
373b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        fetchPhonebookPermissionChoice();
3745b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        fetchMessagePermissionChoice();
375afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
376afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mVisible = false;
377afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
378afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
379afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
380436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothDevice getDevice() {
381d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice;
382afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
383afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
384436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    String getName() {
385afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mName;
386afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
387afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
388436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setName(String name) {
389d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        if (!mName.equals(name)) {
390d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            if (TextUtils.isEmpty(name)) {
391c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                // TODO: use friendly name for unknown device (bug 1181856)
392d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly                mName = mDevice.getAddress();
393d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            } else {
394d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh                mName = name;
3952036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie                mDevice.setAlias(name);
396d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            }
397d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
398d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
399d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
400d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
401436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshName() {
402afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
403afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
404afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
405afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
406afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchName() {
4072036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie        mName = mDevice.getAliasName();
408afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
409afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (TextUtils.isEmpty(mName)) {
410d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mName = mDevice.getAddress();
411436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
413afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
414afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
415436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refresh() {
416afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
417afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
418afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
419436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isVisible() {
420afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mVisible;
421afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
422afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
423afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setVisible(boolean visible) {
424afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mVisible != visible) {
425afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mVisible = visible;
426afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
427afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
428afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
429afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
430436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    int getBondState() {
431d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getBondState();
432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
433afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
434afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setRssi(short rssi) {
435afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mRssi != rssi) {
436afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mRssi = rssi;
437afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
438afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
439afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
440afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
441afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
442afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Checks whether we are connected to this device (any profile counts).
443afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
444afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @return Whether it is connected.
445afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
446436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnected() {
447436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
44850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
449436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTED) {
450afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
451afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
452afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
453afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
454afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return false;
455afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
456afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
457436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnectedProfile(LocalBluetoothProfile profile) {
45850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        int status = getProfileConnectionState(profile);
459436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return status == BluetoothProfile.STATE_CONNECTED;
460c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
461c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby    }
462c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
463436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isBusy() {
464436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
46550e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
466436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTING
467436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    || status == BluetoothProfile.STATE_DISCONNECTING) {
468afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
469afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
470afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
471436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return getBondState() == BluetoothDevice.BOND_BONDING;
472cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby    }
473cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby
474afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
475afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Fetches a new value for the cached BT class.
476afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
477afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchBtClass() {
478d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mBtClass = mDevice.getBluetoothClass();
4792aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
4802aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4812aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private boolean updateProfiles() {
4822aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        ParcelUuid[] uuids = mDevice.getUuids();
4832aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (uuids == null) return false;
4842aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
485436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
486498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh        if (localUuids == null) return false;
487498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh
4886bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M        mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles, mLocalNapRoleConnected);
4892aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4902aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (DEBUG) {
4912036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
4922aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
4932aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4948c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
4958c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            Log.v(TAG, "UUID:");
496436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            for (ParcelUuid uuid : uuids) {
497436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.v(TAG, "  " + uuid);
4982aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            }
499b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly        }
5002aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        return true;
501afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
502afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
503afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
504afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Refreshes the UI for the BT class, including fetching the latest value
505afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * for the class.
506afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
507436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshBtClass() {
508afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
509afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
510afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
511afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
5122aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
5132aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * Refreshes the UI when framework alerts us of a UUID change.
5142aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
515436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onUuidChanged() {
5162aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
5172aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
518eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) {
519eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            Log.e(TAG, "onUuidChanged: Time since last connect"
520eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
521eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5222aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
5232aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        /*
5242aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * If a connect was attempted earlier without any UUID, we will do the
5252aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * connect now.
5262aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         */
527436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!mProfiles.isEmpty()
528eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
5292aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan                        .elapsedRealtime()) {
53039ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            connectWithoutResettingTimer(false);
5312aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
5322aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        dispatchAttributesChanged();
5332aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
5342aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
535436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingStateChanged(int bondState) {
536eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (bondState == BluetoothDevice.BOND_NONE) {
537eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            mProfiles.clear();
538dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;  // cancel auto-connect
5395b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            setPhonebookPermissionChoice(ACCESS_UNKNOWN);
5405b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            setMessagePermissionChoice(ACCESS_UNKNOWN);
541eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5421308453b16c2ca85a456bd4bb7f3c71c916bd83eMichael Chan
543eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        refresh();
544dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
545dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        if (bondState == BluetoothDevice.BOND_BONDED) {
546dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            if (mDevice.isBluetoothDock()) {
547dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby                onBondingDockConnect();
548dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            } else if (mConnectAfterPairing) {
5494bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby                connect(false);
550dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            }
551dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;
552dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        }
553eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
554eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
555436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setBtClass(BluetoothClass btClass) {
55616cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (btClass != null && mBtClass != btClass) {
557d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            mBtClass = btClass;
558d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
559d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
560d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
561d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
562436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothClass getBtClass() {
563436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mBtClass;
564afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
565afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
566436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getProfiles() {
567436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return Collections.unmodifiableList(mProfiles);
56848e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani    }
569afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
570436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getConnectableProfiles() {
571436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        List<LocalBluetoothProfile> connectableProfiles =
572436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                new ArrayList<LocalBluetoothProfile>();
573436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
57439ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isConnectable()) {
575e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan                connectableProfiles.add(profile);
576e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan            }
577e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        }
578e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        return connectableProfiles;
579e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan    }
580e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan
581c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    List<LocalBluetoothProfile> getRemovedProfiles() {
582c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        return mRemovedProfiles;
583c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    }
584c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby
585436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void registerCallback(Callback callback) {
586afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
587afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.add(callback);
588afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
589afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
590afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
591436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unregisterCallback(Callback callback) {
592afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
593afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.remove(callback);
594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
597afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void dispatchAttributesChanged() {
598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
599afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            for (Callback callback : mCallbacks) {
600c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                callback.onDeviceAttributesChanged();
601afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
602afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
603afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
605afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
606afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String toString() {
607d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.toString();
608afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
609afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
611afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean equals(Object o) {
612d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
613436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
614afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
615d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
619afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int hashCode() {
620d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getAddress().hashCode();
621afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
622afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
623436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // This comparison uses non-final fields so the sort order may change
624436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // when device attributes change (such as bonding state). Settings
625436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // will completely refresh the device list when this happens.
626d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly    public int compareTo(CachedBluetoothDevice another) {
627afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Connected above not connected
628436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
629afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
630afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
631afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Paired above not paired
632afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
633afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
634afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
635afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
636afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Visible above not visible
637afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
638afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
639afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
640afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Stronger signal above weaker signal
641afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = another.mRssi - mRssi;
642afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
643afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
644afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Fallback on name
645436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mName.compareTo(another.mName);
646afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
647afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
648afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public interface Callback {
649c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby        void onDeviceAttributesChanged();
650afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
651b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
652b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    int getPhonebookPermissionChoice() {
653b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        return mPhonebookPermissionChoice;
654b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
655b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
656b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    void setPhonebookPermissionChoice(int permissionChoice) {
6573fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        // if user reject it, only save it when reject exceed limit.
6583fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        if (permissionChoice == ACCESS_REJECTED) {
6593fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            mPhonebookRejectedTimes++;
6603fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            if (mPhonebookRejectedTimes < PERSIST_REJECTED_TIMES_LIMIT) {
6613fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu                return;
6623fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            }
6633fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        }
6649998639a657825babd2514fd9af9726c068544c8Zhihai Xu
6653fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        mPhonebookPermissionChoice = permissionChoice;
6669998639a657825babd2514fd9af9726c068544c8Zhihai Xu
667b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        SharedPreferences.Editor editor =
668b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE).edit();
6695b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        if (permissionChoice == ACCESS_UNKNOWN) {
670b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            editor.remove(mDevice.getAddress());
671b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        } else {
672b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            editor.putInt(mDevice.getAddress(), permissionChoice);
673b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        }
674b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        editor.commit();
675b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
676b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
677b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private void fetchPhonebookPermissionChoice() {
678b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        SharedPreferences preference = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME,
679b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                                                                     Context.MODE_PRIVATE);
680b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mPhonebookPermissionChoice = preference.getInt(mDevice.getAddress(),
6815b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie                                                       ACCESS_UNKNOWN);
6825b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
6835b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
6845b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
6855b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    int getMessagePermissionChoice() {
6865b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        return mMessagePermissionChoice;
6875b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
6885b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
6895b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    void setMessagePermissionChoice(int permissionChoice) {
6903fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        // if user reject it, only save it when reject exceed limit.
6913fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        if (permissionChoice == ACCESS_REJECTED) {
6923fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            mMessageRejectedTimes++;
6933fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            if (mMessageRejectedTimes < PERSIST_REJECTED_TIMES_LIMIT) {
6943fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu                return;
6953fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            }
6963fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        }
6979998639a657825babd2514fd9af9726c068544c8Zhihai Xu
6983fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        mMessagePermissionChoice = permissionChoice;
6999998639a657825babd2514fd9af9726c068544c8Zhihai Xu
7005b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        SharedPreferences.Editor editor =
7015b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            mContext.getSharedPreferences(MESSAGE_PREFS_NAME, Context.MODE_PRIVATE).edit();
7025b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        if (permissionChoice == ACCESS_UNKNOWN) {
7035b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            editor.remove(mDevice.getAddress());
7045b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        } else {
7055b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            editor.putInt(mDevice.getAddress(), permissionChoice);
7065b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        }
7075b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        editor.commit();
7085b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
7095b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
7105b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    private void fetchMessagePermissionChoice() {
7115b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        SharedPreferences preference = mContext.getSharedPreferences(MESSAGE_PREFS_NAME,
7125b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie                                                                     Context.MODE_PRIVATE);
7135b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        mMessagePermissionChoice = preference.getInt(mDevice.getAddress(),
7145b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie                                                       ACCESS_UNKNOWN);
715b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
716b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
717afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
718