CachedBluetoothDevice.java revision ac8b5b7fd6b6774d22d39bb9a4becca1908915c7
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
71ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private int mMessageRejectionCount;
725b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
73436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
74afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
755b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    // Following constants indicate the user's choices of Phone book/message access settings
76b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User hasn't made any choice or settings app has wiped out the memory
77361d870e5415f8642cb106b4329d194673b4dd02PauloftheWest    public final static int ACCESS_UNKNOWN = 0;
78b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User has accepted the connection and let Settings app remember the decision
79361d870e5415f8642cb106b4329d194673b4dd02PauloftheWest    public final static int ACCESS_ALLOWED = 1;
80b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    // User has rejected the connection and let Settings app remember the decision
81361d870e5415f8642cb106b4329d194673b4dd02PauloftheWest    public final static int ACCESS_REJECTED = 2;
825b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
83ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    // How many times user should reject the connection to make the choice persist.
84ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2;
85b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
86ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
87b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
88afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
89afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * When we connect to multiple profiles, we only want to display a single
90afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * error even if they all fail. This tracks that state.
91afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
92afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean mIsConnectingErrorPossible;
93afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
942aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
95eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * Last time a bt profile auto-connect was attempted.
96eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan     * If an ACTION_UUID intent comes in within
972aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
982aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * again with the new UUIDs
992aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
100eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    private long mConnectAttempted;
1012aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
102eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    // See mConnectAttempted
1032aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
1042aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
105dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    /** Auto-connect after pairing only if locally initiated. */
106dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby    private boolean mConnectAfterPairing;
10784905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
108e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    /**
109f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * Describes the current device and profile for logging.
11084905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh     *
111f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @param profile Profile to describe
112f907e0bb891eca4d498871a1cc862117a462a076Adam Powell     * @return Description of the device and profile
113e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project     */
114436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private String describe(LocalBluetoothProfile profile) {
115f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        StringBuilder sb = new StringBuilder();
116e79f990490de49b39097433707c2bae6d8238330Jake Hamby        sb.append("Address:").append(mDevice);
117f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        if (profile != null) {
118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            sb.append(" Profile:").append(profile);
119097ed6c671ed733c0967acc32e017020ede4575bMichael Chan        }
120e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
121f907e0bb891eca4d498871a1cc862117a462a076Adam Powell        return sb.toString();
122f907e0bb891eca4d498871a1cc862117a462a076Adam Powell    }
12384905edb6315ac0af53141cf2f91591443d7422aJaikumar Ganesh
124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (Utils.D) {
126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            Log.d(TAG, "onProfileStateChanged: profile " + profile +
127f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    " newProfileState " + newProfileState);
1286c97742c88303c65e68fe08257a7ccf841f03866Michael Chan        }
1297951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
1307951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        {
1317951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
1327951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            return;
1337951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
13450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState.put(profile, newProfileState);
135436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
136f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (!mProfiles.contains(profile)) {
137c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                mRemovedProfiles.remove(profile);
138f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                mProfiles.add(profile);
139c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                if (profile instanceof PanProfile &&
140c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                        ((PanProfile) profile).isLocalRoleNap(mDevice)) {
141c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    // Device doesn't support NAP, so remove PanProfile on disconnect
142c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                    mLocalNapRoleConnected = true;
143c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                }
144e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project            }
1455d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            if (profile instanceof MapProfile) {
1465d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                profile.setPreferred(mDevice, true);
1475d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            }
1485d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz        } else if (profile instanceof MapProfile &&
1495d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
1505d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            if (mProfiles.contains(profile)) {
1515d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                mRemovedProfiles.add(profile);
1525d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz                mProfiles.remove(profile);
1535d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            }
1545d2595f05182910c1dd0ed1302bf59071b55ae79Kim Schulz            profile.setPreferred(mDevice, false);
155c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        } else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
156c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                ((PanProfile) profile).isLocalRoleNap(mDevice) &&
157c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
158c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
159c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mProfiles.remove(profile);
160c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mRemovedProfiles.add(profile);
161c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby            mLocalNapRoleConnected = false;
162e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project        }
163e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project    }
164e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project
165b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    CachedBluetoothDevice(Context context,
166b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothAdapter adapter,
167b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          LocalBluetoothProfileManager profileManager,
168b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie                          BluetoothDevice device) {
169b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        mContext = context;
170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mLocalAdapter = adapter;
171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        mProfileManager = profileManager;
172d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mDevice = device;
17350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
174afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fillData();
175afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
176afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
177436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect() {
178436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
179afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            disconnect(profile);
180afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
1810654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // Disconnect  PBAP server in case its connected
1820654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // This is to ensure all the profiles are disconnected as some CK/Hs do not
1830654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        // disconnect  PBAP connection when HF connection is brought down
1840654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
1850654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
1860654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        {
1870654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta            PbapProfile.disconnect(mDevice);
1880654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta        }
189afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
190afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
191436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void disconnect(LocalBluetoothProfile profile) {
192436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.disconnect(mDevice)) {
193436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
194d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
195f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
196afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
197afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
198afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connect(boolean connectAllProfiles) {
200436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
201afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return;
202afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
203afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
204eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
2054bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connectWithoutResettingTimer(connectAllProfiles);
206eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
207eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
208436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingDockConnect() {
209582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // Attempt to connect if UUIDs are available. Otherwise,
210582f1f84bb0ad4315ce17826672298c68f1c3b38Jake Hamby        // we will connect when the ACTION_UUID intent arrives.
2114bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby        connect(false);
212b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh    }
213b172cd5d232bd650d6efbb7d8b5e4cf9c213952fJaikumar Ganesh
21439ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby    private void connectWithoutResettingTimer(boolean connectAllProfiles) {
215a0d39a39c2f53ebe858685c75c756b51dfac49daJake Hamby        // Try to initialize the profiles if they were not.
216436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mProfiles.isEmpty()) {
2176e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
2186e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
2196e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // from bluetooth stack but ACTION.uuid is not sent yet.
2206e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // Eventually ACTION.uuid will be received which shall trigger the connection of the
2216e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // various profiles
2226e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // If UUIDs are not available yet, connect will be happen
2236e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            // upon arrival of the ACTION_UUID intent.
2246e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            Log.d(TAG, "No profiles. Maybe we will connect later");
2256e4060212e537bdcb69b21c2ba814c23cd393d42Kausik Sinnaswamy            return;
2262aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
2272aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
228afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
229afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
230afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
231eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        int preferredProfiles = 0;
232436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
23339ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
234436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (profile.isPreferred(mDevice)) {
235b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                    ++preferredProfiles;
236436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    connectInt(profile);
237b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan                }
238afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
239afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
240eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
241afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
242eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (preferredProfiles == 0) {
243436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            connectAutoConnectableProfiles();
244afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
245afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
246afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
247436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private void connectAutoConnectableProfiles() {
248436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
249436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
250436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
251afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
252afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
253afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
25539ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isAutoConnectable()) {
256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                profile.setPreferred(mDevice, true);
257436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                connectInt(profile);
258b547dda338f1b135076c8be59c50a12d843cebf8Michael Chan            }
259afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
260afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
261afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
262436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    /**
263436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * Connect this device to the specified profile.
264436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     *
265436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     * @param profile the profile to use with the remote device
266436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby     */
267436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void connectProfile(LocalBluetoothProfile profile) {
268eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        mConnectAttempted = SystemClock.elapsedRealtime();
269afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Reset the only-show-one-error-dialog tracking variable
270afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mIsConnectingErrorPossible = true;
271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        connectInt(profile);
272f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        // Refresh the UI based on profile.connect() call
273f457e613d5d91322e0c967fb801899d55e3db9e5Syed Ibrahim M        refresh();
274afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
275afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
2762ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji    synchronized void connectInt(LocalBluetoothProfile profile) {
277436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!ensurePaired()) {
278436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
279436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        }
280436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (profile.connect(mDevice)) {
281436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (Utils.D) {
282d3a460cce7b6a4f1e81f3c15b5f7949d28fdc929Jaikumar Ganesh                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
283afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
284436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return;
285afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
286436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
287afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
288afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
289afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private boolean ensurePaired() {
29016cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (getBondState() == BluetoothDevice.BOND_NONE) {
291436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            startPairing();
292afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return false;
293afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        } else {
294afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            return true;
295afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
296afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
297afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
298436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean startPairing() {
299afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Pairing is unreliable while scanning, so cancel discovery
300436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (mLocalAdapter.isDiscovering()) {
301436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            mLocalAdapter.cancelDiscovery();
302afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
303afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
304d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if (!mDevice.createBond()) {
305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
306afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
307dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
308dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        mConnectAfterPairing = true;  // auto-connect after pairing
309436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return true;
310afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
311afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
312ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    /**
313ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * Return true if user initiated pairing on this device. The message text is
314ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     * slightly different for local vs. remote initiated pairing dialogs.
315ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby     */
316ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    boolean isUserInitiatedPairing() {
317ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby        return mConnectAfterPairing;
318ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby    }
319ca9812a8521fcc483e821fd5a88ec421de0b8f66Jake Hamby
320436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unpair() {
32196b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        int state = getBondState();
322afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
32396b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state == BluetoothDevice.BOND_BONDING) {
324d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mDevice.cancelBondProcess();
32596b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        }
32696b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan
32796b0c1dc0813f7e8c957ec17dc7751693926c6aeMichael Chan        if (state != BluetoothDevice.BOND_NONE) {
328436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            final BluetoothDevice dev = mDevice;
329f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            if (dev != null) {
330f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                final boolean successful = dev.removeBond();
331f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                if (successful) {
332436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    if (Utils.D) {
333f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                        Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
334f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    }
335436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                } else if (Utils.V) {
336f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                    Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
337f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                            describe(null));
338f907e0bb891eca4d498871a1cc862117a462a076Adam Powell                }
339f907e0bb891eca4d498871a1cc862117a462a076Adam Powell            }
340afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
341afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
342afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
34350e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    int getProfileConnectionState(LocalBluetoothProfile profile) {
34450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        if (mProfileConnectionState == null ||
34550e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh                mProfileConnectionState.get(profile) == null) {
34650e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            // If cache is empty make the binder call to get the state
34750e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int state = profile.getConnectionStatus(mDevice);
34850e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            mProfileConnectionState.put(profile, state);
34950e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        }
35050e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        return mProfileConnectionState.get(profile);
35150e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh    }
35250e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh
3537951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    public void clearProfileConnectionState ()
3547951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    {
3557951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        if (Utils.D) {
3567951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
3577951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
3587951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        for (LocalBluetoothProfile profile :getProfiles()) {
3597951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
3607951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta        }
3617951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta    }
3627951b43bd9a759b01ea994b341c102b03011ca3cGanesh Ganapathi Batta
363436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // TODO: do any of these need to run async on a background thread?
364afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fillData() {
365afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
366afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
3672aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
368ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        migratePhonebookPermissionChoice();
369ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        migrateMessagePermissionChoice();
370ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        fetchMessageRejectionCount();
371afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
372afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        mVisible = false;
373afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
374afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
375afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
376436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothDevice getDevice() {
377d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice;
378afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
379afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
380436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    String getName() {
381afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mName;
382afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
383afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
384436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setName(String name) {
385d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        if (!mName.equals(name)) {
386d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            if (TextUtils.isEmpty(name)) {
387c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                // TODO: use friendly name for unknown device (bug 1181856)
388d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly                mName = mDevice.getAddress();
389d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            } else {
390d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh                mName = name;
3912036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie                mDevice.setAlias(name);
392d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            }
393d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
394d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
395d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
396d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
397436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshName() {
398afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchName();
399afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
400afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
401afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
402afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchName() {
4032036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie        mName = mDevice.getAliasName();
404afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
405afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (TextUtils.isEmpty(mName)) {
406d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly            mName = mDevice.getAddress();
407436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
408afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
409afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
410afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
411436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refresh() {
412afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
413afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
414afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
415436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isVisible() {
416afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return mVisible;
417afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
418afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
419afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setVisible(boolean visible) {
420afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mVisible != visible) {
421afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mVisible = visible;
422afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
423afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
424afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
425afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
426436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    int getBondState() {
427d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getBondState();
428afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
429afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
430afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    void setRssi(short rssi) {
431afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (mRssi != rssi) {
432afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mRssi = rssi;
433afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            dispatchAttributesChanged();
434afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
435afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
436afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
437afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
438afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Checks whether we are connected to this device (any profile counts).
439afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     *
440afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * @return Whether it is connected.
441afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
442436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnected() {
443436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
44450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
445436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTED) {
446afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
447afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
448afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
449afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
450afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        return false;
451afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
452afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
453436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isConnectedProfile(LocalBluetoothProfile profile) {
45450e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh        int status = getProfileConnectionState(profile);
455436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return status == BluetoothProfile.STATE_CONNECTED;
456c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
457c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby    }
458c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby
459436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    boolean isBusy() {
460436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
46150e0b0cf87f724d25ada10353867f14ebbf644aaJaikumar Ganesh            int status = getProfileConnectionState(profile);
462436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (status == BluetoothProfile.STATE_CONNECTING
463436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    || status == BluetoothProfile.STATE_DISCONNECTING) {
464afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project                return true;
465afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
466afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
467436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return getBondState() == BluetoothDevice.BOND_BONDING;
468cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby    }
469cde015b3d424b0d83030f11432ad0a0589014bd5Jake Hamby
470afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
471afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Fetches a new value for the cached BT class.
472afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
473afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void fetchBtClass() {
474d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        mBtClass = mDevice.getBluetoothClass();
4752aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
4762aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4772aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    private boolean updateProfiles() {
4782aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        ParcelUuid[] uuids = mDevice.getUuids();
4792aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (uuids == null) return false;
4802aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
481436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
482498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh        if (localUuids == null) return false;
483498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh
4841b5bd091ebe4be7d714d19d5b35d8d7233a7713aZhihai Xu        mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles,
4851b5bd091ebe4be7d714d19d5b35d8d7233a7713aZhihai Xu                                       mLocalNapRoleConnected, mDevice);
4862aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4872aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        if (DEBUG) {
4882036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
4892aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
4902aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
4918c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
4928c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh            Log.v(TAG, "UUID:");
493436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            for (ParcelUuid uuid : uuids) {
494436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                Log.v(TAG, "  " + uuid);
4952aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan            }
496b20dd917e2d29045225985baa980a2a8e22e10fcNick Pelly        }
4972aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        return true;
498afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
499afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
500afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    /**
501afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * Refreshes the UI for the BT class, including fetching the latest value
502afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     * for the class.
503afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project     */
504436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void refreshBtClass() {
505afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        fetchBtClass();
506afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        dispatchAttributesChanged();
507afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
508afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
5092aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    /**
5102aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     * Refreshes the UI when framework alerts us of a UUID change.
5112aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan     */
512436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onUuidChanged() {
5132aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        updateProfiles();
5142aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
515eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (DEBUG) {
516eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            Log.e(TAG, "onUuidChanged: Time since last connect"
517eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
518eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5192aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
5202aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        /*
5212aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * If a connect was attempted earlier without any UUID, we will do the
5222aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         * connect now.
5232aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan         */
524436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        if (!mProfiles.isEmpty()
525eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
5262aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan                        .elapsedRealtime()) {
52739ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            connectWithoutResettingTimer(false);
5282aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        }
5292aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan        dispatchAttributesChanged();
5302aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan    }
5312aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan
532436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void onBondingStateChanged(int bondState) {
533eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        if (bondState == BluetoothDevice.BOND_NONE) {
534eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan            mProfiles.clear();
535dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;  // cancel auto-connect
53658938ba0d6cddb53a8a76d2e0a2217cf49c92395PauloftheWest            setPhonebookPermissionChoice(ACCESS_UNKNOWN);
5375b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie            setMessagePermissionChoice(ACCESS_UNKNOWN);
538ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            mMessageRejectionCount = 0;
539ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            saveMessageRejectionCount();
540eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        }
5411308453b16c2ca85a456bd4bb7f3c71c916bd83eMichael Chan
542eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan        refresh();
543dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby
544dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        if (bondState == BluetoothDevice.BOND_BONDED) {
545dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            if (mDevice.isBluetoothDock()) {
546dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby                onBondingDockConnect();
547dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            } else if (mConnectAfterPairing) {
5484bd7cb0e07a1fbc4e658810631132cebd5b1fdd6Jake Hamby                connect(false);
549dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            }
550dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby            mConnectAfterPairing = false;
551dd79a33ba53fec530094f4d2fe37f0538530d9f8Jake Hamby        }
552eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan    }
553eaf13a2c154a0c7bf7559b45d33fb589b5bcf3d4Michael Chan
554436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void setBtClass(BluetoothClass btClass) {
55516cc86315d7a8e1f6a0f3083d0a810a7cb097832Nick Pelly        if (btClass != null && mBtClass != btClass) {
556d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            mBtClass = btClass;
557d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh            dispatchAttributesChanged();
558d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh        }
559d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh    }
560d97daa064b35ee0c2b73547d46f97fa88d2da4e9Jaikumar Ganesh
561436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    BluetoothClass getBtClass() {
562436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mBtClass;
563afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
564afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
565436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getProfiles() {
566436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return Collections.unmodifiableList(mProfiles);
56748e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani    }
568afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
569436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    List<LocalBluetoothProfile> getConnectableProfiles() {
570436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        List<LocalBluetoothProfile> connectableProfiles =
571436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                new ArrayList<LocalBluetoothProfile>();
572436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        for (LocalBluetoothProfile profile : mProfiles) {
57339ef225e7c44a48aa9cfdf5c56ecd4ddfb95ae89Jake Hamby            if (profile.isConnectable()) {
574e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan                connectableProfiles.add(profile);
575e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan            }
576e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        }
577e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan        return connectableProfiles;
578e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan    }
579e6531e253bf646324d3a68de0e9cc612c5e1c8acMichael Chan
580c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    List<LocalBluetoothProfile> getRemovedProfiles() {
581c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby        return mRemovedProfiles;
582c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby    }
583c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby
584436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void registerCallback(Callback callback) {
585afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
586afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.add(callback);
587afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
588afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
589afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
590436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    void unregisterCallback(Callback callback) {
591afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
592afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            mCallbacks.remove(callback);
593afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
594afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
595afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
596afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    private void dispatchAttributesChanged() {
597afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        synchronized (mCallbacks) {
598afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            for (Callback callback : mCallbacks) {
599c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby                callback.onDeviceAttributesChanged();
600afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            }
601afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
602afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
603afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
604afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
605afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public String toString() {
606d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.toString();
607afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
608afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
609afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
610afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public boolean equals(Object o) {
611d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
612436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            return false;
613afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
614d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
615afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
616afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
617afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
618afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public int hashCode() {
619d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly        return mDevice.getAddress().hashCode();
620afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
621afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
622436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // This comparison uses non-final fields so the sort order may change
623436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // when device attributes change (such as bonding state). Settings
624436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    // will completely refresh the device list when this happens.
625d63c0112251ab4e4e977545368dd703d875012a4Nick Pelly    public int compareTo(CachedBluetoothDevice another) {
626afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Connected above not connected
627436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
628afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
629afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
630afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Paired above not paired
631afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
632afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
633afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
634afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
635afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Visible above not visible
636afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
637afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
638afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
639afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Stronger signal above weaker signal
640afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        comparison = another.mRssi - mRssi;
641afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        if (comparison != 0) return comparison;
642afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
643afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        // Fallback on name
644436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        return mName.compareTo(another.mName);
645afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
646afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
647afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    public interface Callback {
648c090feb64f674d9840993736a24f9667f8b0e0d5Jake Hamby        void onDeviceAttributesChanged();
649afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
650b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
651b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    int getPhonebookPermissionChoice() {
652ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        int permission = mDevice.getPhonebookAccessPermission();
653ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (permission == BluetoothDevice.ACCESS_ALLOWED) {
654ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            return ACCESS_ALLOWED;
655ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
656ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            return ACCESS_REJECTED;
657ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        }
658ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        return ACCESS_UNKNOWN;
659b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
660b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
661b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    void setPhonebookPermissionChoice(int permissionChoice) {
662ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        int permission = BluetoothDevice.ACCESS_UNKNOWN;
663ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (permissionChoice == ACCESS_ALLOWED) {
664ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            permission = BluetoothDevice.ACCESS_ALLOWED;
665ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        } else if (permissionChoice == ACCESS_REJECTED) {
666ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            permission = BluetoothDevice.ACCESS_REJECTED;
667b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie        }
668ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        mDevice.setPhonebookAccessPermission(permission);
669b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
670b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
671ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
672ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    // app's shared preferences).
673ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private void migratePhonebookPermissionChoice() {
674ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        SharedPreferences preferences = mContext.getSharedPreferences(
675ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                "bluetooth_phonebook_permission", Context.MODE_PRIVATE);
676ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (!preferences.contains(mDevice.getAddress())) {
677ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            return;
678ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        }
679ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee
680ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
681ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
682ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            if (oldPermission == ACCESS_ALLOWED) {
683ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
684ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            } else if (oldPermission == ACCESS_REJECTED) {
685ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
686ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            }
687ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        }
688ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee
689ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        SharedPreferences.Editor editor = preferences.edit();
690ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        editor.remove(mDevice.getAddress());
691ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        editor.commit();
6925b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
6935b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
6945b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    int getMessagePermissionChoice() {
695ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        int permission = mDevice.getMessageAccessPermission();
696ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (permission == BluetoothDevice.ACCESS_ALLOWED) {
697ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            return ACCESS_ALLOWED;
698ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
699ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            return ACCESS_REJECTED;
700ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        }
701ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        return ACCESS_UNKNOWN;
7025b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
7035b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
7045b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    void setMessagePermissionChoice(int permissionChoice) {
705ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        int permission = BluetoothDevice.ACCESS_UNKNOWN;
706ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (permissionChoice == ACCESS_ALLOWED) {
707ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            permission = BluetoothDevice.ACCESS_ALLOWED;
708ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        } else if (permissionChoice == ACCESS_REJECTED) {
709ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            permission = BluetoothDevice.ACCESS_REJECTED;
7103fd5e2839fba6afc18d99006d61c063c2ed4f121Zhihai Xu        }
711ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        mDevice.setMessageAccessPermission(permission);
712ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    }
7139998639a657825babd2514fd9af9726c068544c8Zhihai Xu
714ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
715ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    // app's shared preferences).
716ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private void migrateMessagePermissionChoice() {
717ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        SharedPreferences preferences = mContext.getSharedPreferences(
718ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                "bluetooth_message_permission", Context.MODE_PRIVATE);
719ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (!preferences.contains(mDevice.getAddress())) {
720ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            return;
721ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        }
7229998639a657825babd2514fd9af9726c068544c8Zhihai Xu
723ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (mDevice.getMessageAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
724ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
725ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            if (oldPermission == ACCESS_ALLOWED) {
726ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
727ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            } else if (oldPermission == ACCESS_REJECTED) {
728ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
729ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            }
7305b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        }
731ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee
732ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        SharedPreferences.Editor editor = preferences.edit();
733ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        editor.remove(mDevice.getAddress());
7345b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie        editor.commit();
7355b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie    }
7365b5b1e39ddd28af55cf5dd4a9ca9bf29828a66a6Matthew Xie
737ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    /**
738ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee     * @return Whether this rejection should persist.
739ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee     */
740ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    boolean checkAndIncreaseMessageRejectionCount() {
741ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) {
742ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            mMessageRejectionCount++;
743ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            saveMessageRejectionCount();
744ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        }
745ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST;
746b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie    }
747b707255a440e53ec2865c4b34c7ea07d16d471bdMatthew Xie
748ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private void fetchMessageRejectionCount() {
749ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        SharedPreferences preference = mContext.getSharedPreferences(
750ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE);
751ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0);
7521083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    }
7531083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu
754ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee    private void saveMessageRejectionCount() {
755ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        SharedPreferences.Editor editor = mContext.getSharedPreferences(
756ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee                MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit();
757ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee        if (mMessageRejectionCount == 0) {
7581083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu            editor.remove(mDevice.getAddress());
7591083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        } else {
760ac8b5b7fd6b6774d22d39bb9a4becca1908915c7Edward Jee            editor.putInt(mDevice.getAddress(), mMessageRejectionCount);
7611083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        }
7621083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu        editor.commit();
7631083b4726ba915261034612ae9b757d67ed19fcbZhihai Xu    }
764afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
765