CachedBluetoothDevice.java revision 6e4060212e537bdcb69b21c2ba814c23cd393d42
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
69436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
70afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
71b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // Following constants indicate the user's choices of Phone book access settings
72b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User hasn't made any choice or settings app has wiped out the memory
73b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    final static int PHONEBOOK_ACCESS_UNKNOWN = 0;
74b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User has accepted the connection and let Settings app remember the decision
75b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    final static int PHONEBOOK_ACCESS_ALLOWED = 1;
76b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User has rejected the connection and let Settings app remember the decision
77b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    final static int PHONEBOOK_ACCESS_REJECTED = 2;
78b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
79b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private final static String PHONEBOOK_PREFS_NAME = "bluetooth_phonebook_permission";
80b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
81afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
82afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * When we connect to multiple profiles, we only want to display a single
83afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * error even if they all fail. This tracks that state.
84afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
85afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mIsConnectingErrorPossible;
86afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
872aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
88eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * Last time a bt profile auto-connect was attempted.
89eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * If an ACTION_UUID intent comes in within
902aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
912aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * again with the new UUIDs
922aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
93eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    private long mConnectAttempted;
942aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
95eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    // See mConnectAttempted
962aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
972aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
98dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    /** Auto-connect after pairing only if locally initiated. */
99dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    private boolean mConnectAfterPairing;
10084905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
101e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    /**
102f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * Describes the current device and profile for logging.
10384905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh     *
104f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @param profile Profile to describe
105f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @return Description of the device and profile
106e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     */
107436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private String describe(LocalBluetoothProfile profile) {
108f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        StringBuilder sb = new StringBuilder();
109e79f990490de49b39097433707c2bae6d8238330Jake Hamby        sb.append("Address:").append(mDevice);
110f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        if (profile != null) {
111436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            sb.append(" Profile:").append(profile);
112097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        }
113e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
114f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        return sb.toString();
115f907e0bb891eca4d498871a1cc862117a462a076Adam Powell    }
11684905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
117436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (Utils.D) {
119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Log.d(TAG, "onProfileStateChanged: profile " + profile +
120f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    " newProfileState " + newProfileState);
1216c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        }
1222ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji        if (profile instanceof HeadsetProfile) {
1232ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji            if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
1242ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                if (BluetoothProfile.PRIORITY_AUTO_CONNECT != profile.getPreferred(mDevice))
1252ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                    mProfileManager.enableAutoConnectForHf(mDevice, true);
1262ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji            } else if (newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
1272ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                // dont reset auto connect priority when bluetooth turned off
1282ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                if ((BluetoothAdapter.STATE_ON == mLocalAdapter.getBluetoothState())
1292ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                    || (BluetoothAdapter.STATE_TURNING_ON == mLocalAdapter.getBluetoothState())) {
1302ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                        mProfileManager.enableAutoConnectForHf(mDevice, false);
1312ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                }
1322ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji            }
1332ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji        } else if (profile instanceof A2dpProfile ) {
1342ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji            if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
1352ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                if (BluetoothProfile.PRIORITY_AUTO_CONNECT != profile.getPreferred(mDevice))
1362ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                    mProfileManager.enableAutoConnectForA2dp(mDevice,true);
1372ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji            } else if (newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
1382ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                // dont reset auto connect priority when bluetooth turned off
1392ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                if ((BluetoothAdapter.STATE_ON == mLocalAdapter.getBluetoothState())
1402ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                    || (BluetoothAdapter.STATE_TURNING_ON == mLocalAdapter.getBluetoothState())) {
1412ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                        mProfileManager.enableAutoConnectForA2dp(mDevice, false);
1422ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji                }
1432ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji            }
1442ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji        }
145e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
14650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState.put(profile, newProfileState);
147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
148f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (!mProfiles.contains(profile)) {
149c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                mRemovedProfiles.remove(profile);
150f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                mProfiles.add(profile);
151c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                if (profile instanceof PanProfile &&
152c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                        ((PanProfile) profile).isLocalRoleNap(mDevice)) {
153c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    // Device doesn't support NAP, so remove PanProfile on disconnect
154c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    mLocalNapRoleConnected = true;
155c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                }
156e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
157c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        } else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
158c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                ((PanProfile) profile).isLocalRoleNap(mDevice) &&
159c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
160c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
161c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mProfiles.remove(profile);
162c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mRemovedProfiles.add(profile);
163c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mLocalNapRoleConnected = false;
164e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
165e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
166e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
167b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    CachedBluetoothDevice(Context context,
168b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothAdapter adapter,
169b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothProfileManager profileManager,
170b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          BluetoothDevice device) {
171b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mContext = context;
172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mLocalAdapter = adapter;
173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mProfileManager = profileManager;
174d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mDevice = device;
17550e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
176afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fillData();
177afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
178afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect() {
180436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
181afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            disconnect(profile);
182afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
183afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
184afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect(LocalBluetoothProfile profile) {
186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.disconnect(mDevice)) {
187436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
188d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
189f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
190afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
191afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
192afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
193436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connect(boolean connectAllProfiles) {
194436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
195afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return;
196afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
197afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
198eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
1994bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connectWithoutResettingTimer(connectAllProfiles);
200eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
201eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
202436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingDockConnect() {
203582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // Attempt to connect if UUIDs are available. Otherwise,
204582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // we will connect when the ACTION_UUID intent arrives.
2054bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connect(false);
206b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh    }
207b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh
20839ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby    private void connectWithoutResettingTimer(boolean connectAllProfiles) {
209a0d39a39c2f53ebe858685c75c756b51dfac49daJake Hamby        // Try to initialize the profiles if they were not.
210436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mProfiles.isEmpty()) {
2116e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
2126e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
2136e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // from bluetooth stack but ACTION.uuid is not sent yet.
2146e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // Eventually ACTION.uuid will be received which shall trigger the connection of the
2156e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // various profiles
2166e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // If UUIDs are not available yet, connect will be happen
2176e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // upon arrival of the ACTION_UUID intent.
2186e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            Log.d(TAG, "No profiles. Maybe we will connect later");
2196e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            return;
2202aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
2212aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
222afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
223afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
224afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
225eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        int preferredProfiles = 0;
226436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
22739ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
228436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (profile.isPreferred(mDevice)) {
229b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                    ++preferredProfiles;
230436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    connectInt(profile);
231b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                }
232afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
233afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
234eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
235afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
236eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (preferredProfiles == 0) {
237436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            connectAutoConnectableProfiles();
238afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
239afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
240afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
241436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private void connectAutoConnectableProfiles() {
242436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
243436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
244436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
245afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
246afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
247afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
248436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
24939ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isAutoConnectable()) {
250436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                profile.setPreferred(mDevice, true);
251436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                connectInt(profile);
252b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan            }
253afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
254afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
255afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /**
257436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * Connect this device to the specified profile.
258436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     *
259436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * @param profile the profile to use with the remote device
260436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     */
261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connectProfile(LocalBluetoothProfile profile) {
262eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
263afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
264afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
265436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        connectInt(profile);
266f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        // Refresh the UI based on profile.connect() call
267f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        refresh();
268afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
269afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
2702ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji    synchronized void connectInt(LocalBluetoothProfile profile) {
271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
273436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
274436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.connect(mDevice)) {
275436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
276d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
277afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
278436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
279afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
280436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
281afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
282afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
283afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean ensurePaired() {
28416cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (getBondState() == BluetoothDevice.BOND_NONE) {
285436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            startPairing();
286afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return false;
287afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else {
288afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return true;
289afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
290afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
291afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
292436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean startPairing() {
293afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Pairing is unreliable while scanning, so cancel discovery
294436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mLocalAdapter.isDiscovering()) {
295436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mLocalAdapter.cancelDiscovery();
296afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
297afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
298d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if (!mDevice.createBond()) {
299436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
300afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
301dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
302dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        mConnectAfterPairing = true;  // auto-connect after pairing
303436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return true;
304afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
305afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
306ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    /**
307ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * Return true if user initiated pairing on this device. The message text is
308ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * slightly different for local vs. remote initiated pairing dialogs.
309ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     */
310ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    boolean isUserInitiatedPairing() {
311ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby        return mConnectAfterPairing;
312ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    }
313ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby
314436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unpair() {
31596b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        int state = getBondState();
316afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
31796b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state == BluetoothDevice.BOND_BONDING) {
318d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mDevice.cancelBondProcess();
31996b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        }
32096b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan
32196b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state != BluetoothDevice.BOND_NONE) {
322436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            final BluetoothDevice dev = mDevice;
323f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (dev != null) {
324f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                final boolean successful = dev.removeBond();
325f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                if (successful) {
326436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    if (Utils.D) {
327f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                        Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
328f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    }
329436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                } else if (Utils.V) {
330f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
331f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                            describe(null));
332f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                }
333f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
334afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
335afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
336afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
33750e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    int getProfileConnectionState(LocalBluetoothProfile profile) {
33850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        if (mProfileConnectionState == null ||
33950e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh                mProfileConnectionState.get(profile) == null) {
34050e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            // If cache is empty make the binder call to get the state
34150e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int state = profile.getConnectionStatus(mDevice);
34250e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            mProfileConnectionState.put(profile, state);
34350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        }
34450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        return mProfileConnectionState.get(profile);
34550e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    }
34650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh
347436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // TODO: do any of these need to run async on a background thread?
348afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fillData() {
349afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
350afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
3512aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
352b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        fetchPhonebookPermissionChoice();
353afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
354afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mVisible = false;
355afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
356afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
357afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
358436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothDevice getDevice() {
359d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice;
360afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
361afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
362436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    String getName() {
363afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mName;
364afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
365afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
366436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setName(String name) {
367d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        if (!mName.equals(name)) {
368d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            if (TextUtils.isEmpty(name)) {
369c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                // TODO: use friendly name for unknown device (bug 1181856)
370d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly                mName = mDevice.getAddress();
371d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            } else {
372d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh                mName = name;
3732036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie                mDevice.setAlias(name);
374d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            }
375d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
376d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
377d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
378d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
379436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshName() {
380afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
381afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
382afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
383afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
384afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchName() {
3852036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie        mName = mDevice.getAliasName();
386afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
387afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (TextUtils.isEmpty(mName)) {
388d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mName = mDevice.getAddress();
389436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
390afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
391afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
392afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
393436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refresh() {
394afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
395afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
396afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
397436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isVisible() {
398afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mVisible;
399afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
400afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
401afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setVisible(boolean visible) {
402afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mVisible != visible) {
403afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mVisible = visible;
404afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
405afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
406afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
407afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
408436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    int getBondState() {
409d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getBondState();
410afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
411afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setRssi(short rssi) {
413afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mRssi != rssi) {
414afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mRssi = rssi;
415afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
416afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
417afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
418afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
419afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
420afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Checks whether we are connected to this device (any profile counts).
421afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
422afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @return Whether it is connected.
423afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
424436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnected() {
425436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
42650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
427436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTED) {
428afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
429afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
430afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
431afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return false;
433afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
434afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
435436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnectedProfile(LocalBluetoothProfile profile) {
43650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        int status = getProfileConnectionState(profile);
437436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return status == BluetoothProfile.STATE_CONNECTED;
438c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
439c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby    }
440c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
441436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isBusy() {
442436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
44350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
444436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTING
445436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    || status == BluetoothProfile.STATE_DISCONNECTING) {
446afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
447afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
448afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
449436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return getBondState() == BluetoothDevice.BOND_BONDING;
450cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby    }
451cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby
452afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
453afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Fetches a new value for the cached BT class.
454afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
455afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchBtClass() {
456d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mBtClass = mDevice.getBluetoothClass();
4572aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
4582aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4592aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private boolean updateProfiles() {
4602aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        ParcelUuid[] uuids = mDevice.getUuids();
4612aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (uuids == null) return false;
4622aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
463436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
464498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh        if (localUuids == null) return false;
465498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh
466c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles);
4672aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4682aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (DEBUG) {
4692036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
4702aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
4712aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4728c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
4738c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            Log.v(TAG, "UUID:");
474436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            for (ParcelUuid uuid : uuids) {
475436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.v(TAG, "  " + uuid);
4762aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            }
477b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly        }
4782aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        return true;
479afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
480afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
481afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
482afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Refreshes the UI for the BT class, including fetching the latest value
483afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * for the class.
484afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
485436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshBtClass() {
486afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
487afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
488afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
489afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
4902aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
4912aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * Refreshes the UI when framework alerts us of a UUID change.
4922aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
493436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onUuidChanged() {
4942aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
4952aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
496eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) {
497eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            Log.e(TAG, "onUuidChanged: Time since last connect"
498eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
499eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5002aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
5012aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        /*
5022aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * If a connect was attempted earlier without any UUID, we will do the
5032aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * connect now.
5042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         */
505436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!mProfiles.isEmpty()
506eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
5072aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan                        .elapsedRealtime()) {
50839ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            connectWithoutResettingTimer(false);
5092aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
5102aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        dispatchAttributesChanged();
5112aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
5122aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
513436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingStateChanged(int bondState) {
514eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (bondState == BluetoothDevice.BOND_NONE) {
515eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            mProfiles.clear();
516dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;  // cancel auto-connect
517b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            setPhonebookPermissionChoice(PHONEBOOK_ACCESS_UNKNOWN);
518eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5191308453b16c2ca85a456bd4bb7f3c71c916bd83eMichael Chan
520eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        refresh();
521dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
522dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        if (bondState == BluetoothDevice.BOND_BONDED) {
523dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            if (mDevice.isBluetoothDock()) {
524dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby                onBondingDockConnect();
525dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            } else if (mConnectAfterPairing) {
5264bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby                connect(false);
527dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            }
528dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;
529dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        }
530eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
531eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
532436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setBtClass(BluetoothClass btClass) {
53316cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (btClass != null && mBtClass != btClass) {
534d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            mBtClass = btClass;
535d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
536d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
537d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
538d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
539436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothClass getBtClass() {
540436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mBtClass;
541afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
542afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
543436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getProfiles() {
544436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return Collections.unmodifiableList(mProfiles);
54548e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani    }
546afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
547436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getConnectableProfiles() {
548436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        List<LocalBluetoothProfile> connectableProfiles =
549436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                new ArrayList<LocalBluetoothProfile>();
550436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
55139ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isConnectable()) {
552e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan                connectableProfiles.add(profile);
553e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan            }
554e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        }
555e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        return connectableProfiles;
556e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan    }
557e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan
558c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    List<LocalBluetoothProfile> getRemovedProfiles() {
559c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        return mRemovedProfiles;
560c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    }
561c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby
562436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void registerCallback(Callback callback) {
563afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
564afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.add(callback);
565afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
566afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
567afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
568436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unregisterCallback(Callback callback) {
569afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
570afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.remove(callback);
571afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
572afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
573afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
574afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void dispatchAttributesChanged() {
575afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
576afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            for (Callback callback : mCallbacks) {
577c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                callback.onDeviceAttributesChanged();
578afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
579afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
580afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
581afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
582afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
583afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String toString() {
584d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.toString();
585afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
586afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
587afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
588afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean equals(Object o) {
589d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
590436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
591afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
592d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
593afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int hashCode() {
597d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getAddress().hashCode();
598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
599afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
600436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // This comparison uses non-final fields so the sort order may change
601436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // when device attributes change (such as bonding state). Settings
602436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // will completely refresh the device list when this happens.
603d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly    public int compareTo(CachedBluetoothDevice another) {
604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Connected above not connected
605436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
606afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
607afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
608afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Paired above not paired
609afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
611afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
612afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
613afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Visible above not visible
614afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
615afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Stronger signal above weaker signal
618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = another.mRssi - mRssi;
619afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
620afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
621afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Fallback on name
622436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mName.compareTo(another.mName);
623afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
624afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
625afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public interface Callback {
626c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby        void onDeviceAttributesChanged();
627afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
628b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
629b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    int getPhonebookPermissionChoice() {
630b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        return mPhonebookPermissionChoice;
631b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
632b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
633b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    void setPhonebookPermissionChoice(int permissionChoice) {
634b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        SharedPreferences.Editor editor =
635b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE).edit();
636b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        if (permissionChoice == PHONEBOOK_ACCESS_UNKNOWN) {
637b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            editor.remove(mDevice.getAddress());
638b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        } else {
639b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie            editor.putInt(mDevice.getAddress(), permissionChoice);
640b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        }
641b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        editor.commit();
642b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mPhonebookPermissionChoice = permissionChoice;
643b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
644b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
645b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    private void fetchPhonebookPermissionChoice() {
646b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        SharedPreferences preference = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME,
647b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                                                                     Context.MODE_PRIVATE);
648b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mPhonebookPermissionChoice = preference.getInt(mDevice.getAddress(),
649b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                                                       PHONEBOOK_ACCESS_UNKNOWN);
650b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
651b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
652afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
653