CachedBluetoothDevice.java revision 1083b4726ba915261034612ae9b757d67ed19fcb
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
711083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private int mPhonebookRejectedTimes;
723fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu
731083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private int mMessageRejectedTimes;
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";
901083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private final static String PHONEBOOK_REJECT_TIMES = "bluetooth_phonebook_reject";
911083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private final static String MESSAGE_REJECT_TIMES = "bluetooth_message_reject";
92b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
93afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
94afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * When we connect to multiple profiles, we only want to display a single
95afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * error even if they all fail. This tracks that state.
96afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
97afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mIsConnectingErrorPossible;
98afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
992aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
100eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * Last time a bt profile auto-connect was attempted.
101eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * If an ACTION_UUID intent comes in within
1022aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
1032aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * again with the new UUIDs
1042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
105eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    private long mConnectAttempted;
1062aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
107eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    // See mConnectAttempted
1082aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
1092aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
110dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    /** Auto-connect after pairing only if locally initiated. */
111dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    private boolean mConnectAfterPairing;
11284905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
113e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    /**
114f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * Describes the current device and profile for logging.
11584905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh     *
116f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @param profile Profile to describe
117f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @return Description of the device and profile
118e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     */
119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private String describe(LocalBluetoothProfile profile) {
120f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        StringBuilder sb = new StringBuilder();
121e79f990490de49b39097433707c2bae6d8238330Jake Hamby        sb.append("Address:").append(mDevice);
122f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        if (profile != null) {
123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            sb.append(" Profile:").append(profile);
124097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        }
125e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
126f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        return sb.toString();
127f907e0bb891eca4d498871a1cc862117a462a076Adam Powell    }
12884905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (Utils.D) {
131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Log.d(TAG, "onProfileStateChanged: profile " + profile +
132f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    " newProfileState " + newProfileState);
1336c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        }
1347951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
1357951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        {
1367951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
1377951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            return;
1387951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
13950e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState.put(profile, newProfileState);
140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
141f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (!mProfiles.contains(profile)) {
142c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                mRemovedProfiles.remove(profile);
143f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                mProfiles.add(profile);
144c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                if (profile instanceof PanProfile &&
145c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                        ((PanProfile) profile).isLocalRoleNap(mDevice)) {
146c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    // Device doesn't support NAP, so remove PanProfile on disconnect
147c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    mLocalNapRoleConnected = true;
148c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                }
149e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
1505d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            if (profile instanceof MapProfile) {
1515d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                profile.setPreferred(mDevice, true);
1525d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                refresh();
1535d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            }
1545d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz        } else if (profile instanceof MapProfile &&
1555d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
1565d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            if (mProfiles.contains(profile)) {
1575d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                mRemovedProfiles.add(profile);
1585d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                mProfiles.remove(profile);
1595d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            }
1605d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            profile.setPreferred(mDevice, false);
1615d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            refresh();
162c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        } else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
163c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                ((PanProfile) profile).isLocalRoleNap(mDevice) &&
164c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
165c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
166c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mProfiles.remove(profile);
167c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mRemovedProfiles.add(profile);
168c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mLocalNapRoleConnected = false;
169e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
170e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
171e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
172b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    CachedBluetoothDevice(Context context,
173b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothAdapter adapter,
174b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothProfileManager profileManager,
175b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          BluetoothDevice device) {
176b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mContext = context;
177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mLocalAdapter = adapter;
178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mProfileManager = profileManager;
179d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mDevice = device;
18050e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
181afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fillData();
182afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
183afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
184436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect() {
185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
186afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            disconnect(profile);
187afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
1880654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // Disconnect  PBAP server in case its connected
1890654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // This is to ensure all the profiles are disconnected as some CK/Hs do not
1900654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // disconnect  PBAP connection when HF connection is brought down
1910654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
1920654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
1930654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        {
1940654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta            PbapProfile.disconnect(mDevice);
1950654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        }
196afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
197afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
198436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect(LocalBluetoothProfile profile) {
199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.disconnect(mDevice)) {
200436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
201d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
202f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
203afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
204afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
205afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
206436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connect(boolean connectAllProfiles) {
207436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
208afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return;
209afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
210afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
211eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
2124bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connectWithoutResettingTimer(connectAllProfiles);
213eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
214eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
215436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingDockConnect() {
216582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // Attempt to connect if UUIDs are available. Otherwise,
217582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // we will connect when the ACTION_UUID intent arrives.
2184bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connect(false);
219b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh    }
220b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh
22139ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby    private void connectWithoutResettingTimer(boolean connectAllProfiles) {
222a0d39a39c2f53ebe858685c75c756b51dfac49daJake Hamby        // Try to initialize the profiles if they were not.
223436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mProfiles.isEmpty()) {
2246e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
2256e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
2266e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // from bluetooth stack but ACTION.uuid is not sent yet.
2276e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // Eventually ACTION.uuid will be received which shall trigger the connection of the
2286e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // various profiles
2296e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // If UUIDs are not available yet, connect will be happen
2306e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // upon arrival of the ACTION_UUID intent.
2316e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            Log.d(TAG, "No profiles. Maybe we will connect later");
2326e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            return;
2332aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
2342aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
235afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
236afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
237afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
238eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        int preferredProfiles = 0;
239436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
24039ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
241436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (profile.isPreferred(mDevice)) {
242b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                    ++preferredProfiles;
243436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    connectInt(profile);
244b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                }
245afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
246afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
247eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
248afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
249eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (preferredProfiles == 0) {
250436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            connectAutoConnectableProfiles();
251afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
252afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
253afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private void connectAutoConnectableProfiles() {
255436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
257436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
258afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
259afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
260afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
26239ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isAutoConnectable()) {
263436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                profile.setPreferred(mDevice, true);
264436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                connectInt(profile);
265b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan            }
266afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
267afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
268afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
269436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /**
270436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * Connect this device to the specified profile.
271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     *
272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * @param profile the profile to use with the remote device
273436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     */
274436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connectProfile(LocalBluetoothProfile profile) {
275eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
276afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
277afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
278436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        connectInt(profile);
279f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        // Refresh the UI based on profile.connect() call
280f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        refresh();
281afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
282afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
2832ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji    synchronized void connectInt(LocalBluetoothProfile profile) {
284436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
285436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
286436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
287436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.connect(mDevice)) {
288436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
289d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
290afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
291436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
292afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
293436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
294afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
295afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
296afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean ensurePaired() {
29716cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (getBondState() == BluetoothDevice.BOND_NONE) {
298436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            startPairing();
299afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return false;
300afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else {
301afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return true;
302afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
303afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
304afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean startPairing() {
306afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Pairing is unreliable while scanning, so cancel discovery
307436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mLocalAdapter.isDiscovering()) {
308436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mLocalAdapter.cancelDiscovery();
309afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
310afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
311d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if (!mDevice.createBond()) {
312436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
313afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
314dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
315dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        mConnectAfterPairing = true;  // auto-connect after pairing
316436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return true;
317afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
318afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
319ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    /**
320ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * Return true if user initiated pairing on this device. The message text is
321ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * slightly different for local vs. remote initiated pairing dialogs.
322ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     */
323ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    boolean isUserInitiatedPairing() {
324ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby        return mConnectAfterPairing;
325ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    }
326ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby
327436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unpair() {
32896b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        int state = getBondState();
329afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
33096b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state == BluetoothDevice.BOND_BONDING) {
331d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mDevice.cancelBondProcess();
33296b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        }
33396b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan
33496b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state != BluetoothDevice.BOND_NONE) {
335436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            final BluetoothDevice dev = mDevice;
336f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (dev != null) {
337f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                final boolean successful = dev.removeBond();
338f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                if (successful) {
339436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    if (Utils.D) {
340f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                        Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
341f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    }
342436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                } else if (Utils.V) {
343f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
344f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                            describe(null));
345f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                }
346f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
347afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
348afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
349afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
35050e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    int getProfileConnectionState(LocalBluetoothProfile profile) {
35150e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        if (mProfileConnectionState == null ||
35250e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh                mProfileConnectionState.get(profile) == null) {
35350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            // If cache is empty make the binder call to get the state
35450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int state = profile.getConnectionStatus(mDevice);
35550e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            mProfileConnectionState.put(profile, state);
35650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        }
35750e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        return mProfileConnectionState.get(profile);
35850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    }
35950e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh
3607951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    public void clearProfileConnectionState ()
3617951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    {
3627951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        if (Utils.D) {
3637951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
3647951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
3657951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        for (LocalBluetoothProfile profile :getProfiles()) {
3667951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
3677951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
3687951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    }
3697951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta
370436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // TODO: do any of these need to run async on a background thread?
371afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fillData() {
372afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
373afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
3742aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
375b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        fetchPhonebookPermissionChoice();
3765b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        fetchMessagePermissionChoice();
3771083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        fetchPhonebookRejectTimes();
3781083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        fetchMessageRejectTimes();
379afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
380afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mVisible = false;
381afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
382afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
383afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
384436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothDevice getDevice() {
385d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice;
386afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
387afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
388436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    String getName() {
389afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mName;
390afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
391afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
392436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setName(String name) {
393d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        if (!mName.equals(name)) {
394d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            if (TextUtils.isEmpty(name)) {
395c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                // TODO: use friendly name for unknown device (bug 1181856)
396d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly                mName = mDevice.getAddress();
397d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            } else {
398d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh                mName = name;
3992036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie                mDevice.setAlias(name);
400d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            }
401d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
402d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
403d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
404d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
405436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshName() {
406afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
407afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
408afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
409afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
410afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchName() {
4112036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie        mName = mDevice.getAliasName();
412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
413afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (TextUtils.isEmpty(mName)) {
414d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mName = mDevice.getAddress();
415436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
416afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
417afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
418afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
419436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refresh() {
420afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
421afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
422afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
423436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isVisible() {
424afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mVisible;
425afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
426afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
427afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setVisible(boolean visible) {
428afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mVisible != visible) {
429afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mVisible = visible;
430afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
431afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
433afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
434436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    int getBondState() {
435d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getBondState();
436afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
437afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
438afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setRssi(short rssi) {
439afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mRssi != rssi) {
440afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mRssi = rssi;
441afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
442afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
443afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
444afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
445afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
446afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Checks whether we are connected to this device (any profile counts).
447afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
448afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @return Whether it is connected.
449afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
450436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnected() {
451436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
45250e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
453436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTED) {
454afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
455afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
456afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
457afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
458afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return false;
459afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
460afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
461436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnectedProfile(LocalBluetoothProfile profile) {
46250e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        int status = getProfileConnectionState(profile);
463436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return status == BluetoothProfile.STATE_CONNECTED;
464c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
465c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby    }
466c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
467436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isBusy() {
468436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
46950e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
470436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTING
471436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    || status == BluetoothProfile.STATE_DISCONNECTING) {
472afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
473afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
474afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
475436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return getBondState() == BluetoothDevice.BOND_BONDING;
476cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby    }
477cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby
478afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
479afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Fetches a new value for the cached BT class.
480afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
481afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchBtClass() {
482d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mBtClass = mDevice.getBluetoothClass();
4832aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
4842aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4852aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private boolean updateProfiles() {
4862aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        ParcelUuid[] uuids = mDevice.getUuids();
4872aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (uuids == null) return false;
4882aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
489436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
490498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh        if (localUuids == null) return false;
491498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh
4926bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M        mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles, mLocalNapRoleConnected);
4932aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4942aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (DEBUG) {
4952036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
4962aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
4972aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4988c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
4998c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            Log.v(TAG, "UUID:");
500436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            for (ParcelUuid uuid : uuids) {
501436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.v(TAG, "  " + uuid);
5022aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            }
503b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly        }
5042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        return true;
505afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
506afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
507afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
508afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Refreshes the UI for the BT class, including fetching the latest value
509afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * for the class.
510afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
511436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshBtClass() {
512afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
513afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
514afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
515afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
5162aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
5172aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * Refreshes the UI when framework alerts us of a UUID change.
5182aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
519436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onUuidChanged() {
5202aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
5212aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
522eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) {
523eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            Log.e(TAG, "onUuidChanged: Time since last connect"
524eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
525eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5262aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
5272aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        /*
5282aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * If a connect was attempted earlier without any UUID, we will do the
5292aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * connect now.
5302aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         */
531436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!mProfiles.isEmpty()
532eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
5332aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan                        .elapsedRealtime()) {
53439ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            connectWithoutResettingTimer(false);
5352aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
5362aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        dispatchAttributesChanged();
5372aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
5382aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
539436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingStateChanged(int bondState) {
540eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (bondState == BluetoothDevice.BOND_NONE) {
541eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            mProfiles.clear();
542dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;  // cancel auto-connect
5435b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            setPhonebookPermissionChoice(ACCESS_UNKNOWN);
5445b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            setMessagePermissionChoice(ACCESS_UNKNOWN);
5451083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            mPhonebookRejectedTimes = 0;
5461083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            savePhonebookRejectTimes();
5471083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            mMessageRejectedTimes = 0;
5481083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            saveMessageRejectTimes();
549eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5501308453b16c2ca85a456bd4bb7f3c71c916bd83eMichael Chan
551eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        refresh();
552dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
553dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        if (bondState == BluetoothDevice.BOND_BONDED) {
554dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            if (mDevice.isBluetoothDock()) {
555dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby                onBondingDockConnect();
556dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            } else if (mConnectAfterPairing) {
5574bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby                connect(false);
558dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            }
559dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;
560dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        }
561eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
562eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
563436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setBtClass(BluetoothClass btClass) {
56416cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (btClass != null && mBtClass != btClass) {
565d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            mBtClass = btClass;
566d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
567d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
568d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
569d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
570436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothClass getBtClass() {
571436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mBtClass;
572afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
573afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
574436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getProfiles() {
575436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return Collections.unmodifiableList(mProfiles);
57648e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani    }
577afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
578436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getConnectableProfiles() {
579436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        List<LocalBluetoothProfile> connectableProfiles =
580436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                new ArrayList<LocalBluetoothProfile>();
581436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
58239ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isConnectable()) {
583e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan                connectableProfiles.add(profile);
584e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan            }
585e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        }
586e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        return connectableProfiles;
587e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan    }
588e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan
589c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    List<LocalBluetoothProfile> getRemovedProfiles() {
590c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        return mRemovedProfiles;
591c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    }
592c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby
593436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void registerCallback(Callback callback) {
594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.add(callback);
596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
597afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
599436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unregisterCallback(Callback callback) {
600afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
601afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.remove(callback);
602afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
603afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
605afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void dispatchAttributesChanged() {
606afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
607afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            for (Callback callback : mCallbacks) {
608c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                callback.onDeviceAttributesChanged();
609afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
611afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
612afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
613afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
614afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String toString() {
615d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.toString();
616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
619afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean equals(Object o) {
620d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
621436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
622afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
623d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
624afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
625afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
626afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
627afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int hashCode() {
628d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getAddress().hashCode();
629afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
630afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
631436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // This comparison uses non-final fields so the sort order may change
632436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // when device attributes change (such as bonding state). Settings
633436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // will completely refresh the device list when this happens.
634d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly    public int compareTo(CachedBluetoothDevice another) {
635afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Connected above not connected
636436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
637afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
638afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
639afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Paired above not paired
640afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
641afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
642afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
643afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
644afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Visible above not visible
645afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
646afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
647afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
648afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Stronger signal above weaker signal
649afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = another.mRssi - mRssi;
650afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
651afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
652afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Fallback on name
653436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mName.compareTo(another.mName);
654afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
655afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
656afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public interface Callback {
657c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby        void onDeviceAttributesChanged();
658afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
659b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
660b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    int getPhonebookPermissionChoice() {
661b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        return mPhonebookPermissionChoice;
662b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
663b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
664b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    void setPhonebookPermissionChoice(int permissionChoice) {
6653fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        // if user reject it, only save it when reject exceed limit.
6663fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        if (permissionChoice == ACCESS_REJECTED) {
6673fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            mPhonebookRejectedTimes++;
6681083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            savePhonebookRejectTimes();
6693fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            if (mPhonebookRejectedTimes < PERSIST_REJECTED_TIMES_LIMIT) {
6703fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu                return;
6713fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            }
6723fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        }
6739998639a657825babd2514fd9af9726c068544c8Zhihai Xu
6743fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        mPhonebookPermissionChoice = permissionChoice;
6759998639a657825babd2514fd9af9726c068544c8Zhihai Xu
676b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        SharedPreferences.Editor editor =
677b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE).edit();
6785b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        if (permissionChoice == ACCESS_UNKNOWN) {
679b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            editor.remove(mDevice.getAddress());
680b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        } else {
681b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            editor.putInt(mDevice.getAddress(), permissionChoice);
682b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        }
683b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        editor.commit();
684b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
685b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
686b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private void fetchPhonebookPermissionChoice() {
687b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        SharedPreferences preference = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME,
688b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                                                                     Context.MODE_PRIVATE);
689b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mPhonebookPermissionChoice = preference.getInt(mDevice.getAddress(),
6905b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie                                                       ACCESS_UNKNOWN);
6915b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
6925b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
6931083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private void fetchPhonebookRejectTimes() {
6941083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        SharedPreferences preference = mContext.getSharedPreferences(PHONEBOOK_REJECT_TIMES,
6951083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu                                                                     Context.MODE_PRIVATE);
6961083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        mPhonebookRejectedTimes = preference.getInt(mDevice.getAddress(), 0);
6971083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    }
6981083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu
6991083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private void savePhonebookRejectTimes() {
7001083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        SharedPreferences.Editor editor =
7011083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            mContext.getSharedPreferences(PHONEBOOK_REJECT_TIMES,
7021083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu                                          Context.MODE_PRIVATE).edit();
7031083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        if (mPhonebookRejectedTimes == 0) {
7041083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            editor.remove(mDevice.getAddress());
7051083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        } else {
7061083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            editor.putInt(mDevice.getAddress(), mPhonebookRejectedTimes);
7071083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        }
7081083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        editor.commit();
7091083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    }
7105b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
7115b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    int getMessagePermissionChoice() {
7125b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        return mMessagePermissionChoice;
7135b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
7145b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
7155b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    void setMessagePermissionChoice(int permissionChoice) {
7163fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        // if user reject it, only save it when reject exceed limit.
7173fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        if (permissionChoice == ACCESS_REJECTED) {
7183fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            mMessageRejectedTimes++;
7191083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            saveMessageRejectTimes();
7203fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            if (mMessageRejectedTimes < PERSIST_REJECTED_TIMES_LIMIT) {
7213fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu                return;
7223fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu            }
7233fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        }
7249998639a657825babd2514fd9af9726c068544c8Zhihai Xu
7253fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        mMessagePermissionChoice = permissionChoice;
7269998639a657825babd2514fd9af9726c068544c8Zhihai Xu
7275b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        SharedPreferences.Editor editor =
7285b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            mContext.getSharedPreferences(MESSAGE_PREFS_NAME, Context.MODE_PRIVATE).edit();
7295b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        if (permissionChoice == ACCESS_UNKNOWN) {
7305b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            editor.remove(mDevice.getAddress());
7315b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        } else {
7325b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            editor.putInt(mDevice.getAddress(), permissionChoice);
7335b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        }
7345b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        editor.commit();
7355b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
7365b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
7375b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    private void fetchMessagePermissionChoice() {
7385b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        SharedPreferences preference = mContext.getSharedPreferences(MESSAGE_PREFS_NAME,
7395b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie                                                                     Context.MODE_PRIVATE);
7405b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        mMessagePermissionChoice = preference.getInt(mDevice.getAddress(),
7415b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie                                                       ACCESS_UNKNOWN);
742b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
743b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
7441083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private void fetchMessageRejectTimes() {
7451083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        SharedPreferences preference = mContext.getSharedPreferences(MESSAGE_REJECT_TIMES,
7461083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu                                                                     Context.MODE_PRIVATE);
7471083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        mMessageRejectedTimes = preference.getInt(mDevice.getAddress(), 0);
7481083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    }
7491083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu
7501083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    private void saveMessageRejectTimes() {
7511083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        SharedPreferences.Editor editor =
7521083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            mContext.getSharedPreferences(MESSAGE_REJECT_TIMES, Context.MODE_PRIVATE).edit();
7531083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        if (mMessageRejectedTimes == 0) {
7541083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            editor.remove(mDevice.getAddress());
7551083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        } else {
7561083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            editor.putInt(mDevice.getAddress(), mMessageRejectedTimes);
7571083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        }
7581083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        editor.commit();
7591083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    }
7601083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu
761afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
762