• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18  * TODO: Move this to
19  * java/services/com/android/server/BluetoothService.java
20  * and make the contructor package private again.
21  *
22  * @hide
23  */
24 
25 package android.server;
26 
27 import android.bluetooth.BluetoothAdapter;
28 import android.bluetooth.BluetoothClass;
29 import android.bluetooth.BluetoothDevice;
30 import android.bluetooth.BluetoothDeviceProfileState;
31 import android.bluetooth.BluetoothHeadset;
32 import android.bluetooth.BluetoothHealthAppConfiguration;
33 import android.bluetooth.BluetoothInputDevice;
34 import android.bluetooth.BluetoothPan;
35 import android.bluetooth.BluetoothProfile;
36 import android.bluetooth.BluetoothProfileState;
37 import android.bluetooth.BluetoothSocket;
38 import android.bluetooth.BluetoothUuid;
39 import android.bluetooth.IBluetooth;
40 import android.bluetooth.IBluetoothCallback;
41 import android.bluetooth.IBluetoothHealthCallback;
42 import android.bluetooth.IBluetoothStateChangeCallback;
43 import android.content.BroadcastReceiver;
44 import android.content.ContentResolver;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.IntentFilter;
48 import android.content.SharedPreferences;
49 import android.content.res.Resources;
50 import android.os.Binder;
51 import android.os.Handler;
52 import android.os.IBinder;
53 import android.os.Message;
54 import android.os.ParcelFileDescriptor;
55 import android.os.ParcelUuid;
56 import android.os.RemoteException;
57 import android.os.ServiceManager;
58 import android.provider.Settings;
59 import android.util.Log;
60 import android.util.Pair;
61 
62 import com.android.internal.app.IBatteryStats;
63 
64 import java.io.BufferedInputStream;
65 import java.io.BufferedReader;
66 import java.io.BufferedWriter;
67 import java.io.DataInputStream;
68 import java.io.File;
69 import java.io.FileDescriptor;
70 import java.io.FileInputStream;
71 import java.io.FileNotFoundException;
72 import java.io.FileWriter;
73 import java.io.IOException;
74 import java.io.InputStreamReader;
75 import java.io.PrintWriter;
76 import java.io.RandomAccessFile;
77 import java.io.UnsupportedEncodingException;
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.Collection;
81 import java.util.Collections;
82 import java.util.HashMap;
83 import java.util.Iterator;
84 import java.util.List;
85 import java.util.Map;
86 
87 public class BluetoothService extends IBluetooth.Stub {
88     private static final String TAG = "BluetoothService";
89     private static final boolean DBG = true;
90 
91     private int mNativeData;
92     private BluetoothEventLoop mEventLoop;
93     private BluetoothHeadset mHeadsetProxy;
94     private BluetoothInputDevice mInputDevice;
95     private BluetoothPan mPan;
96     private boolean mIsAirplaneSensitive;
97     private boolean mIsAirplaneToggleable;
98     private BluetoothAdapterStateMachine mBluetoothState;
99     private int[] mAdapterSdpHandles;
100     private ParcelUuid[] mAdapterUuids;
101 
102     private BluetoothAdapter mAdapter;  // constant after init()
103     private final BluetoothBondState mBondState;  // local cache of bondings
104     private final IBatteryStats mBatteryStats;
105     private final Context mContext;
106     private Map<Integer, IBluetoothStateChangeCallback> mStateChangeTracker =
107         Collections.synchronizedMap(new HashMap<Integer, IBluetoothStateChangeCallback>());
108 
109     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
110     static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
111 
112     private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
113     private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
114 
115     private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
116     private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
117 
118     private static final int MESSAGE_UUID_INTENT = 1;
119     private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2;
120     private static final int MESSAGE_REMOVE_SERVICE_RECORD = 3;
121 
122     private static final int RFCOMM_RECORD_REAPER = 10;
123     private static final int STATE_CHANGE_REAPER = 11;
124 
125     // The time (in millisecs) to delay the pairing attempt after the first
126     // auto pairing attempt fails. We use an exponential delay with
127     // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
128     // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
129     private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
130     private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
131 
132     // The timeout used to sent the UUIDs Intent
133     // This timeout should be greater than the page timeout
134     private static final int UUID_INTENT_DELAY = 6000;
135 
136     /** Always retrieve RFCOMM channel for these SDP UUIDs */
137     private static final ParcelUuid[] RFCOMM_UUIDS = {
138             BluetoothUuid.Handsfree,
139             BluetoothUuid.HSP,
140             BluetoothUuid.ObexObjectPush };
141 
142     private final BluetoothAdapterProperties mAdapterProperties;
143     private final BluetoothDeviceProperties mDeviceProperties;
144 
145     private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
146     private final ArrayList<String> mUuidIntentTracker;
147     private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
148 
149     private static class ServiceRecordClient {
150         int pid;
151         IBinder binder;
152         IBinder.DeathRecipient death;
153     }
154     private final HashMap<Integer, ServiceRecordClient> mServiceRecordToPid;
155 
156     private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
157     private final BluetoothProfileState mA2dpProfileState;
158     private final BluetoothProfileState mHfpProfileState;
159 
160     private BluetoothA2dpService mA2dpService;
161     private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
162 
163     private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
164 
165     private static String mDockAddress;
166     private String mDockPin;
167 
168     private boolean mAllowConnect = true;
169 
170     private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
171     private BluetoothPanProfileHandler mBluetoothPanProfileHandler;
172     private BluetoothInputProfileHandler mBluetoothInputProfileHandler;
173     private BluetoothHealthProfileHandler mBluetoothHealthProfileHandler;
174     private static final String INCOMING_CONNECTION_FILE =
175       "/data/misc/bluetooth/incoming_connection.conf";
176     private HashMap<String, Pair<Integer, String>> mIncomingConnections;
177     private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState;
178 
179     private static class RemoteService {
180         public String address;
181         public ParcelUuid uuid;
RemoteService(String address, ParcelUuid uuid)182         public RemoteService(String address, ParcelUuid uuid) {
183             this.address = address;
184             this.uuid = uuid;
185         }
186         @Override
equals(Object o)187         public boolean equals(Object o) {
188             if (o instanceof RemoteService) {
189                 RemoteService service = (RemoteService)o;
190                 return address.equals(service.address) && uuid.equals(service.uuid);
191             }
192             return false;
193         }
194 
195         @Override
hashCode()196         public int hashCode() {
197             int hash = 1;
198             hash = hash * 31 + (address == null ? 0 : address.hashCode());
199             hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
200             return hash;
201         }
202     }
203 
204     static {
classInitNative()205         classInitNative();
206     }
207 
BluetoothService(Context context)208     public BluetoothService(Context context) {
209         mContext = context;
210 
211         // Need to do this in place of:
212         // mBatteryStats = BatteryStatsService.getService();
213         // Since we can not import BatteryStatsService from here. This class really needs to be
214         // moved to java/services/com/android/server/
215         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
216 
217         initializeNativeDataNative();
218 
219         if (isEnabledNative() == 1) {
220             Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
221             disableNative();
222         }
223 
224         mBondState = new BluetoothBondState(context, this);
225         mAdapterProperties = new BluetoothAdapterProperties(context, this);
226         mDeviceProperties = new BluetoothDeviceProperties(this);
227 
228         mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
229         mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
230         mUuidIntentTracker = new ArrayList<String>();
231         mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
232         mServiceRecordToPid = new HashMap<Integer, ServiceRecordClient>();
233         mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
234         mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
235         mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
236 
237         mHfpProfileState.start();
238         mA2dpProfileState.start();
239 
240         IntentFilter filter = new IntentFilter();
241         registerForAirplaneMode(filter);
242 
243         filter.addAction(Intent.ACTION_DOCK_EVENT);
244         mContext.registerReceiver(mReceiver, filter);
245         mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, this);
246         mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this);
247         mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this);
248         mIncomingConnections = new HashMap<String, Pair<Integer, String>>();
249         mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>();
250     }
251 
readDockBluetoothAddress()252     public static synchronized String readDockBluetoothAddress() {
253         if (mDockAddress != null) return mDockAddress;
254 
255         BufferedInputStream file = null;
256         String dockAddress;
257         try {
258             file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
259             byte[] address = new byte[17];
260             file.read(address);
261             dockAddress = new String(address);
262             dockAddress = dockAddress.toUpperCase();
263             if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
264                 mDockAddress = dockAddress;
265                 return mDockAddress;
266             } else {
267                 Log.e(TAG, "CheckBluetoothAddress failed for car dock address: "
268                         + dockAddress);
269             }
270         } catch (FileNotFoundException e) {
271             Log.e(TAG, "FileNotFoundException while trying to read dock address");
272         } catch (IOException e) {
273             Log.e(TAG, "IOException while trying to read dock address");
274         } finally {
275             if (file != null) {
276                 try {
277                     file.close();
278                 } catch (IOException e) {
279                     // Ignore
280                 }
281             }
282         }
283         mDockAddress = null;
284         return null;
285     }
286 
writeDockPin()287     private synchronized boolean writeDockPin() {
288         BufferedWriter out = null;
289         try {
290             out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
291 
292             // Generate a random 4 digit pin between 0000 and 9999
293             // This is not truly random but good enough for our purposes.
294             int pin = (int) Math.floor(Math.random() * 10000);
295 
296             mDockPin = String.format("%04d", pin);
297             out.write(mDockPin);
298             return true;
299         } catch (FileNotFoundException e) {
300             Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin");
301         } catch (IOException e) {
302             Log.e(TAG, "IOException while while trying to write dock pairing pin");
303         } finally {
304             if (out != null) {
305                 try {
306                     out.close();
307                 } catch (IOException e) {
308                     // Ignore
309                 }
310             }
311         }
312         mDockPin = null;
313         return false;
314     }
315 
getDockPin()316     /*package*/ synchronized String getDockPin() {
317         return mDockPin;
318     }
319 
initAfterRegistration()320     public synchronized void initAfterRegistration() {
321         mAdapter = BluetoothAdapter.getDefaultAdapter();
322         mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter);
323         mBluetoothState.start();
324         if (mContext.getResources().getBoolean
325             (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
326             mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT);
327         }
328         mEventLoop = mBluetoothState.getBluetoothEventLoop();
329     }
330 
initAfterA2dpRegistration()331     public synchronized void initAfterA2dpRegistration() {
332         mEventLoop.getProfileProxy();
333     }
334 
335     @Override
finalize()336     protected void finalize() throws Throwable {
337         mContext.unregisterReceiver(mReceiver);
338         try {
339             cleanupNativeDataNative();
340         } finally {
341             super.finalize();
342         }
343     }
344 
isEnabled()345     public boolean isEnabled() {
346         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
347         return isEnabledInternal();
348     }
349 
isEnabledInternal()350     private boolean isEnabledInternal() {
351         return (getBluetoothStateInternal() == BluetoothAdapter.STATE_ON);
352     }
353 
getBluetoothState()354     public int getBluetoothState() {
355         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
356         return getBluetoothStateInternal();
357     }
358 
getBluetoothStateInternal()359     int getBluetoothStateInternal() {
360         return mBluetoothState.getBluetoothAdapterState();
361     }
362 
363     /**
364      * Bring down bluetooth and disable BT in settings. Returns true on success.
365      */
disable()366     public boolean disable() {
367         return disable(true);
368     }
369 
370     /**
371      * Bring down bluetooth. Returns true on success.
372      *
373      * @param saveSetting If true, persist the new setting
374      */
disable(boolean saveSetting)375     public synchronized boolean disable(boolean saveSetting) {
376         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
377 
378         int adapterState = getBluetoothStateInternal();
379 
380         switch (adapterState) {
381         case BluetoothAdapter.STATE_OFF:
382             return true;
383         case BluetoothAdapter.STATE_ON:
384             break;
385         default:
386             return false;
387         }
388 
389         mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_OFF, saveSetting);
390         return true;
391     }
392 
disconnectDevices()393     synchronized void disconnectDevices() {
394         // Disconnect devices handled by BluetoothService.
395         for (BluetoothDevice device: getConnectedInputDevices()) {
396             disconnectInputDevice(device);
397         }
398 
399         for (BluetoothDevice device: getConnectedPanDevices()) {
400             disconnectPanDevice(device);
401         }
402     }
403 
404     /**
405      * The Bluetooth has been turned off, but hot. Do bonding, profile cleanup
406      */
finishDisable()407     synchronized void finishDisable() {
408         // mark in progress bondings as cancelled
409         for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
410             mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
411                                     BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
412         }
413 
414         // Stop the profile state machine for bonded devices.
415         for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDED)) {
416             removeProfileState(address);
417         }
418 
419         // update mode
420         Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
421         intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
422         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
423     }
424 
425     /**
426      * Local clean up after broadcasting STATE_OFF intent
427      */
cleanupAfterFinishDisable()428     synchronized void cleanupAfterFinishDisable() {
429         mAdapterProperties.clear();
430 
431         for (Integer srHandle : mServiceRecordToPid.keySet()) {
432             removeServiceRecordNative(srHandle);
433         }
434         mServiceRecordToPid.clear();
435 
436         mProfilesConnected = 0;
437         mProfilesConnecting = 0;
438         mProfilesDisconnecting = 0;
439         mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
440         mAdapterUuids = null;
441         mAdapterSdpHandles = null;
442 
443         // Log bluetooth off to battery stats.
444         long ident = Binder.clearCallingIdentity();
445         try {
446             mBatteryStats.noteBluetoothOff();
447         } catch (RemoteException e) {
448         } finally {
449             Binder.restoreCallingIdentity(ident);
450         }
451     }
452 
453     /**
454      * power off Bluetooth
455      */
shutoffBluetooth()456     synchronized void shutoffBluetooth() {
457         if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
458         setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
459                 BluetoothPanProfileHandler.NAP_BRIDGE);
460         tearDownNativeDataNative();
461     }
462 
463     /**
464      * Data clean up after Bluetooth shutoff
465      */
cleanNativeAfterShutoffBluetooth()466     synchronized void cleanNativeAfterShutoffBluetooth() {
467         // Ths method is called after shutdown of event loop in the Bluetooth shut down
468         // procedure
469 
470         // the adapter property could be changed before event loop is stoped, clear it again
471         mAdapterProperties.clear();
472         disableNative();
473     }
474 
475     /** Bring up BT and persist BT on in settings */
enable()476     public boolean enable() {
477         return enable(true, true);
478     }
479 
480     /**
481      * Enable this Bluetooth device, asynchronously.
482      * This turns on/off the underlying hardware.
483      *
484      * @param saveSetting If true, persist the new state of BT in settings
485      * @param allowConnect If true, auto-connects device when BT is turned on
486      *                     and allows incoming A2DP/HSP connections
487      * @return True on success (so far)
488      */
enable(boolean saveSetting, boolean allowConnect)489     public synchronized boolean enable(boolean saveSetting, boolean allowConnect) {
490         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
491                                                 "Need BLUETOOTH_ADMIN permission");
492 
493         // Airplane mode can prevent Bluetooth radio from being turned on.
494         if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
495             return false;
496         }
497         mAllowConnect = allowConnect;
498         mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting);
499         return true;
500     }
501 
502     /**
503      * Enable this Bluetooth device, asynchronously, but does not
504      * auto-connect devices. In this state the Bluetooth adapter
505      * also does not allow incoming A2DP/HSP connections (that
506      * must go through this service), but does allow communication
507      * on RFCOMM sockets implemented outside of this service (ie BTOPP).
508      * This method is used to temporarily enable Bluetooth
509      * for data transfer, without changing
510      *
511      * This turns on/off the underlying hardware.
512      *
513      * @return True on success (so far)
514      */
enableNoAutoConnect()515     public boolean enableNoAutoConnect() {
516         return enable(false, false);
517     }
518 
519     /**
520      * Turn on Bluetooth Module, Load firmware, and do all the preparation
521      * needed to get the Bluetooth Module ready but keep it not discoverable
522      * and not connectable.
523      */
prepareBluetooth()524     /* package */ synchronized boolean prepareBluetooth() {
525         if (!setupNativeDataNative()) {
526             return false;
527         }
528         switchConnectable(false);
529 
530         // Bluetooth stack needs a small delay here before adding
531         // SDP records, otherwise dbus stalls for over 30 seconds 1 out of 50 runs
532         try {
533             Thread.sleep(50);
534         } catch (InterruptedException e) {}
535         updateSdpRecords();
536         return true;
537     }
538 
539     private final Handler mHandler = new Handler() {
540         @Override
541         public void handleMessage(Message msg) {
542             switch (msg.what) {
543             case MESSAGE_UUID_INTENT:
544                 String address = (String)msg.obj;
545                 if (address != null) {
546                     sendUuidIntent(address);
547                     makeServiceChannelCallbacks(address);
548                 }
549                 break;
550             case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
551                 address = (String)msg.obj;
552                 if (address == null) return;
553                 int attempt = mBondState.getAttempt(address);
554 
555                 // Try only if attemps are in progress and cap it 2 attempts
556                 // The 2 attempts cap is a fail safe if the stack returns
557                 // an incorrect error code for bonding failures and if the pin
558                 // is entered wrongly twice we should abort.
559                 if (attempt > 0 && attempt <= 2) {
560                     mBondState.attempt(address);
561                     createBond(address);
562                     return;
563                 }
564                 if (attempt > 0) mBondState.clearPinAttempts(address);
565                 break;
566             case MESSAGE_REMOVE_SERVICE_RECORD:
567                 Pair<Integer, Integer> pair = (Pair<Integer, Integer>) msg.obj;
568                 checkAndRemoveRecord(pair.first, pair.second);
569                 break;
570             }
571         }
572     };
573 
addReservedSdpRecords(final ArrayList<ParcelUuid> uuids)574     private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) {
575         //Register SDP records.
576         int[] svcIdentifiers = new int[uuids.size()];
577         for (int i = 0; i < uuids.size(); i++) {
578             svcIdentifiers[i] = BluetoothUuid.getServiceIdentifierFromParcelUuid(uuids.get(i));
579         }
580         mAdapterSdpHandles = addReservedServiceRecordsNative(svcIdentifiers);
581     }
582 
updateSdpRecords()583     private synchronized void updateSdpRecords() {
584         ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
585 
586         Resources R = mContext.getResources();
587 
588         // Add the default records
589         if (R.getBoolean(com.android.internal.R.bool.config_bluetooth_default_profiles)) {
590             uuids.add(BluetoothUuid.HSP_AG);
591             uuids.add(BluetoothUuid.ObexObjectPush);
592         }
593 
594         if (R.getBoolean(com.android.internal.R.bool.config_voice_capable)) {
595             uuids.add(BluetoothUuid.Handsfree_AG);
596             uuids.add(BluetoothUuid.PBAP_PSE);
597         }
598 
599         // Add SDP records for profiles maintained by Android userspace
600         addReservedSdpRecords(uuids);
601 
602         // Bluetooth stack need some a small delay here before adding more
603         // SDP records, otherwise dbus stalls for over 30 seconds 1 out of 50 runs
604         try {
605             Thread.sleep(50);
606         } catch (InterruptedException e) {}
607 
608         if (R.getBoolean(com.android.internal.R.bool.config_bluetooth_default_profiles)) {
609             // Enable profiles maintained by Bluez userspace.
610             setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
611                    BluetoothPanProfileHandler.NAP_BRIDGE);
612 
613             // Add SDP records for profiles maintained by Bluez userspace
614             uuids.add(BluetoothUuid.AudioSource);
615             uuids.add(BluetoothUuid.AvrcpTarget);
616             uuids.add(BluetoothUuid.NAP);
617         }
618 
619         // Cannot cast uuids.toArray directly since ParcelUuid is parcelable
620         mAdapterUuids = new ParcelUuid[uuids.size()];
621         for (int i = 0; i < uuids.size(); i++) {
622             mAdapterUuids[i] = uuids.get(i);
623         }
624     }
625 
626     /**
627      * This function is called from Bluetooth Event Loop when onPropertyChanged
628      * for adapter comes in with UUID property.
629      * @param uuidsThe uuids of adapter as reported by Bluez.
630      */
updateBluetoothState(String uuids)631     /*package*/ synchronized void updateBluetoothState(String uuids) {
632         ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
633 
634         if (mAdapterUuids != null &&
635             BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
636             mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
637         }
638     }
639 
640     /**
641      * This method is called immediately before Bluetooth module is turned on after
642      * the adapter became pariable.
643      * It inits bond state and profile state before STATE_ON intent is broadcasted.
644      */
initBluetoothAfterTurningOn()645     /*package*/ void initBluetoothAfterTurningOn() {
646         String discoverable = getProperty("Discoverable", false);
647         String timeout = getProperty("DiscoverableTimeout", false);
648         if (timeout == null) {
649             Log.w(TAG, "Null DiscoverableTimeout property");
650             // assign a number, anything not 0
651             timeout = "1";
652         }
653         if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) {
654             setAdapterPropertyBooleanNative("Discoverable", 0);
655         }
656         mBondState.initBondState();
657         initProfileState();
658         getProfileProxy();
659     }
660 
661     /**
662      * This method is called immediately after Bluetooth module is turned on.
663      * It starts auto-connection and places bluetooth on sign onto the battery
664      * stats
665      */
runBluetooth()666     /*package*/ void runBluetooth() {
667         autoConnect();
668 
669         // Log bluetooth on to battery stats.
670         long ident = Binder.clearCallingIdentity();
671         try {
672             mBatteryStats.noteBluetoothOn();
673         } catch (RemoteException e) {
674             Log.e(TAG, "", e);
675         } finally {
676             Binder.restoreCallingIdentity(ident);
677         }
678     }
679 
attemptAutoPair(String address)680     /*package*/ synchronized boolean attemptAutoPair(String address) {
681         if (!mBondState.hasAutoPairingFailed(address) &&
682                 !mBondState.isAutoPairingBlacklisted(address)) {
683             mBondState.attempt(address);
684             setPin(address, BluetoothDevice.convertPinToBytes("0000"));
685             return true;
686         }
687         return false;
688     }
689 
isFixedPinZerosAutoPairKeyboard(String address)690     /*package*/ synchronized boolean isFixedPinZerosAutoPairKeyboard(String address) {
691         // Check for keyboards which have fixed PIN 0000 as the pairing pin
692         return mBondState.isFixedPinZerosAutoPairKeyboard(address);
693     }
694 
onCreatePairedDeviceResult(String address, int result)695     /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
696         if (result == BluetoothDevice.BOND_SUCCESS) {
697             setBondState(address, BluetoothDevice.BOND_BONDED);
698             if (mBondState.isAutoPairingAttemptsInProgress(address)) {
699                 mBondState.clearPinAttempts(address);
700             }
701         } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
702                 mBondState.getAttempt(address) == 1) {
703             mBondState.addAutoPairingFailure(address);
704             pairingAttempt(address, result);
705         } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
706               mBondState.isAutoPairingAttemptsInProgress(address)) {
707             pairingAttempt(address, result);
708         } else {
709             setBondState(address, BluetoothDevice.BOND_NONE, result);
710             if (mBondState.isAutoPairingAttemptsInProgress(address)) {
711                 mBondState.clearPinAttempts(address);
712             }
713         }
714     }
715 
getPendingOutgoingBonding()716     /*package*/ synchronized String getPendingOutgoingBonding() {
717         return mBondState.getPendingOutgoingBonding();
718     }
719 
pairingAttempt(String address, int result)720     private void pairingAttempt(String address, int result) {
721         // This happens when our initial guess of "0000" as the pass key
722         // fails. Try to create the bond again and display the pin dialog
723         // to the user. Use back-off while posting the delayed
724         // message. The initial value is
725         // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
726         // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
727         // reached, display an error to the user.
728         int attempt = mBondState.getAttempt(address);
729         if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
730                     MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
731             mBondState.clearPinAttempts(address);
732             setBondState(address, BluetoothDevice.BOND_NONE, result);
733             return;
734         }
735 
736         Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
737         message.obj = address;
738         boolean postResult =  mHandler.sendMessageDelayed(message,
739                                         attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
740         if (!postResult) {
741             mBondState.clearPinAttempts(address);
742             setBondState(address,
743                     BluetoothDevice.BOND_NONE, result);
744             return;
745         }
746     }
747 
getRemoteDevice(String address)748     /*package*/ BluetoothDevice getRemoteDevice(String address) {
749         return mAdapter.getRemoteDevice(address);
750     }
751 
toBondStateString(int bondState)752     private static String toBondStateString(int bondState) {
753         switch (bondState) {
754         case BluetoothDevice.BOND_NONE:
755             return "not bonded";
756         case BluetoothDevice.BOND_BONDING:
757             return "bonding";
758         case BluetoothDevice.BOND_BONDED:
759             return "bonded";
760         default:
761             return "??????";
762         }
763     }
764 
setName(String name)765     public synchronized boolean setName(String name) {
766         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
767                                                 "Need BLUETOOTH_ADMIN permission");
768         if (name == null) {
769             return false;
770         }
771         return setPropertyString("Name", name);
772     }
773 
774     //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
775     // Either have a single property function with Object as the parameter
776     // or have a function for each property and then obfuscate in the JNI layer.
777     // The following looks dirty.
setPropertyString(String key, String value)778     private boolean setPropertyString(String key, String value) {
779         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
780         if (!isEnabledInternal()) return false;
781         return setAdapterPropertyStringNative(key, value);
782     }
783 
setPropertyInteger(String key, int value)784     private boolean setPropertyInteger(String key, int value) {
785         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
786         if (!isEnabledInternal()) return false;
787         return setAdapterPropertyIntegerNative(key, value);
788     }
789 
setPropertyBoolean(String key, boolean value)790     private boolean setPropertyBoolean(String key, boolean value) {
791         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
792         if (!isEnabledInternal()) return false;
793         return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
794     }
795 
796     /**
797      * Set the discoverability window for the device.  A timeout of zero
798      * makes the device permanently discoverable (if the device is
799      * discoverable).  Setting the timeout to a nonzero value does not make
800      * a device discoverable; you need to call setMode() to make the device
801      * explicitly discoverable.
802      *
803      * @param timeout The discoverable timeout in seconds.
804      */
setDiscoverableTimeout(int timeout)805     public synchronized boolean setDiscoverableTimeout(int timeout) {
806         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
807                                                 "Need BLUETOOTH_ADMIN permission");
808         return setPropertyInteger("DiscoverableTimeout", timeout);
809     }
810 
setScanMode(int mode, int duration)811     public synchronized boolean setScanMode(int mode, int duration) {
812         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
813                                                 "Need WRITE_SECURE_SETTINGS permission");
814         boolean pairable;
815         boolean discoverable;
816 
817         switch (mode) {
818         case BluetoothAdapter.SCAN_MODE_NONE:
819             pairable = false;
820             discoverable = false;
821             break;
822         case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
823             pairable = true;
824             discoverable = false;
825             break;
826         case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
827             pairable = true;
828             discoverable = true;
829             if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
830             break;
831         default:
832             Log.w(TAG, "Requested invalid scan mode " + mode);
833             return false;
834         }
835 
836         setPropertyBoolean("Discoverable", discoverable);
837         setPropertyBoolean("Pairable", pairable);
838         return true;
839     }
840 
841     /**
842      * @param on true set the local Bluetooth module to be connectable
843      *                The dicoverability is recovered to what it was before
844      *                switchConnectable(false) call
845      *           false set the local Bluetooth module to be not connectable
846      *                 and not dicoverable
847      */
switchConnectable(boolean on)848     /*package*/ synchronized void switchConnectable(boolean on) {
849         setAdapterPropertyBooleanNative("Powered", on ? 1 : 0);
850     }
851 
setPairable()852     /*package*/ synchronized void setPairable() {
853         String pairableString = getProperty("Pairable", false);
854         if (pairableString == null) {
855             Log.e(TAG, "null pairableString");
856             return;
857         }
858         if (pairableString.equals("false")) {
859             setAdapterPropertyBooleanNative("Pairable", 1);
860         }
861     }
862 
getProperty(String name, boolean checkState)863     /*package*/ String getProperty(String name, boolean checkState) {
864         // If checkState is false, check if the event loop is running.
865         // before making the call to Bluez
866         if (checkState) {
867             if (!isEnabledInternal()) return null;
868         } else if (!mEventLoop.isEventLoopRunning()) {
869             return null;
870         }
871 
872         return mAdapterProperties.getProperty(name);
873     }
874 
getAdapterProperties()875     BluetoothAdapterProperties getAdapterProperties() {
876         return mAdapterProperties;
877     }
878 
getDeviceProperties()879     BluetoothDeviceProperties getDeviceProperties() {
880         return mDeviceProperties;
881     }
882 
isRemoteDeviceInCache(String address)883     boolean isRemoteDeviceInCache(String address) {
884         return mDeviceProperties.isInCache(address);
885     }
886 
setRemoteDeviceProperty(String address, String name, String value)887     void setRemoteDeviceProperty(String address, String name, String value) {
888         mDeviceProperties.setProperty(address, name, value);
889     }
890 
updateRemoteDevicePropertiesCache(String address)891     void updateRemoteDevicePropertiesCache(String address) {
892         mDeviceProperties.updateCache(address);
893     }
894 
getAddress()895     public synchronized String getAddress() {
896         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
897         // Don't check state since we want to provide address, even if BT is off
898         return getProperty("Address", false);
899     }
900 
getName()901     public synchronized String getName() {
902         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
903         // Don't check state since we want to provide name, even if BT is off
904         return getProperty("Name", false);
905     }
906 
getUuids()907     public ParcelUuid[] getUuids() {
908         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
909         String value =  getProperty("UUIDs", true);
910         if (value == null) return null;
911         return convertStringToParcelUuid(value);
912     }
913 
convertStringToParcelUuid(String value)914     private ParcelUuid[] convertStringToParcelUuid(String value) {
915         String[] uuidStrings = null;
916         // The UUIDs are stored as a "," separated string.
917         uuidStrings = value.split(",");
918         ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
919 
920         for (int i = 0; i < uuidStrings.length; i++) {
921             uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
922         }
923         return uuids;
924     }
925 
926     /**
927      * Returns the user-friendly name of a remote device.  This value is
928      * returned from our local cache, which is updated when onPropertyChange
929      * event is received.
930      * Do not expect to retrieve the updated remote name immediately after
931      * changing the name on the remote device.
932      *
933      * @param address Bluetooth address of remote device.
934      *
935      * @return The user-friendly name of the specified remote device.
936      */
getRemoteName(String address)937     public synchronized String getRemoteName(String address) {
938         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
939         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
940             return null;
941         }
942         return mDeviceProperties.getProperty(address, "Name");
943     }
944 
945     /**
946      * Returns alias of a remote device.  This value is returned from our
947      * local cache, which is updated when onPropertyChange event is received.
948      *
949      * @param address Bluetooth address of remote device.
950      *
951      * @return The alias of the specified remote device.
952      */
getRemoteAlias(String address)953     public synchronized String getRemoteAlias(String address) {
954 
955         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
956         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
957             return null;
958         }
959         return mDeviceProperties.getProperty(address, "Alias");
960     }
961 
962     /**
963      * Set the alias of a remote device.
964      *
965      * @param address Bluetooth address of remote device.
966      * @param alias new alias to change to
967      * @return true on success, false on error
968      */
setRemoteAlias(String address, String alias)969     public synchronized boolean setRemoteAlias(String address, String alias) {
970         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
971         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
972             return false;
973         }
974 
975         return setDevicePropertyStringNative(getObjectPathFromAddress(address),
976                                              "Alias", alias);
977     }
978 
979     /**
980      * Get the discoverability window for the device.  A timeout of zero
981      * means that the device is permanently discoverable (if the device is
982      * in the discoverable mode).
983      *
984      * @return The discoverability window of the device, in seconds.  A negative
985      *         value indicates an error.
986      */
getDiscoverableTimeout()987     public int getDiscoverableTimeout() {
988         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
989         String timeout = getProperty("DiscoverableTimeout", true);
990         if (timeout != null)
991            return Integer.valueOf(timeout);
992         else
993             return -1;
994     }
995 
getScanMode()996     public int getScanMode() {
997         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
998         if (!isEnabledInternal())
999             return BluetoothAdapter.SCAN_MODE_NONE;
1000 
1001         boolean pairable = getProperty("Pairable", true).equals("true");
1002         boolean discoverable = getProperty("Discoverable", true).equals("true");
1003         return bluezStringToScanMode (pairable, discoverable);
1004     }
1005 
startDiscovery()1006     public synchronized boolean startDiscovery() {
1007         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1008                                                 "Need BLUETOOTH_ADMIN permission");
1009         if (!isEnabledInternal()) return false;
1010 
1011         return startDiscoveryNative();
1012     }
1013 
cancelDiscovery()1014     public synchronized boolean cancelDiscovery() {
1015         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1016                                                 "Need BLUETOOTH_ADMIN permission");
1017         if (!isEnabledInternal()) return false;
1018 
1019         return stopDiscoveryNative();
1020     }
1021 
isDiscovering()1022     public boolean isDiscovering() {
1023         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1024 
1025         String discoveringProperty = getProperty("Discovering", false);
1026         if (discoveringProperty == null) {
1027             return false;
1028         }
1029 
1030         return discoveringProperty.equals("true");
1031     }
1032 
isBondingFeasible(String address)1033     private boolean isBondingFeasible(String address) {
1034         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1035                                                 "Need BLUETOOTH_ADMIN permission");
1036         if (!isEnabledInternal()) return false;
1037 
1038         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1039             return false;
1040         }
1041         address = address.toUpperCase();
1042 
1043         if (mBondState.getPendingOutgoingBonding() != null) {
1044             Log.d(TAG, "Ignoring createBond(): another device is bonding");
1045             // a different device is currently bonding, fail
1046             return false;
1047         }
1048 
1049         // Check for bond state only if we are not performing auto
1050         // pairing exponential back-off attempts.
1051         if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1052                 mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
1053             Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded");
1054             return false;
1055         }
1056 
1057         if (address.equals(mDockAddress)) {
1058             if (!writeDockPin()) {
1059                 Log.e(TAG, "Error while writing Pin for the dock");
1060                 return false;
1061             }
1062         }
1063         return true;
1064     }
1065 
createBond(String address)1066     public synchronized boolean createBond(String address) {
1067         if (!isBondingFeasible(address)) return false;
1068 
1069         if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
1070             return false;
1071         }
1072 
1073         mBondState.setPendingOutgoingBonding(address);
1074         mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
1075 
1076         return true;
1077     }
1078 
createBondOutOfBand(String address, byte[] hash, byte[] randomizer)1079     public synchronized boolean createBondOutOfBand(String address, byte[] hash,
1080                                                     byte[] randomizer) {
1081         if (!isBondingFeasible(address)) return false;
1082 
1083         if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
1084             return false;
1085         }
1086 
1087         setDeviceOutOfBandData(address, hash, randomizer);
1088         mBondState.setPendingOutgoingBonding(address);
1089         mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
1090 
1091         return true;
1092     }
1093 
setDeviceOutOfBandData(String address, byte[] hash, byte[] randomizer)1094     public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
1095             byte[] randomizer) {
1096         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1097                                                 "Need BLUETOOTH_ADMIN permission");
1098         if (!isEnabledInternal()) return false;
1099 
1100         Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
1101 
1102         if (DBG) {
1103             Log.d(TAG, "Setting out of band data for: " + address + ":" +
1104                   Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
1105         }
1106 
1107         mDeviceOobData.put(address, value);
1108         return true;
1109     }
1110 
getDeviceOutOfBandData(BluetoothDevice device)1111     Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
1112         return mDeviceOobData.get(device.getAddress());
1113     }
1114 
1115 
readOutOfBandData()1116     public synchronized byte[] readOutOfBandData() {
1117         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1118                                                 "Need BLUETOOTH permission");
1119         if (!isEnabledInternal()) return null;
1120 
1121         return readAdapterOutOfBandDataNative();
1122     }
1123 
cancelBondProcess(String address)1124     public synchronized boolean cancelBondProcess(String address) {
1125         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1126                                                 "Need BLUETOOTH_ADMIN permission");
1127         if (!isEnabledInternal()) return false;
1128 
1129         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1130             return false;
1131         }
1132         address = address.toUpperCase();
1133         if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
1134             return false;
1135         }
1136 
1137         mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1138                                 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1139         cancelDeviceCreationNative(address);
1140         return true;
1141     }
1142 
removeBond(String address)1143     public synchronized boolean removeBond(String address) {
1144         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1145                                                 "Need BLUETOOTH_ADMIN permission");
1146         if (!isEnabledInternal()) return false;
1147 
1148         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1149             return false;
1150         }
1151         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
1152         if (state != null) {
1153             state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
1154             return true;
1155         } else {
1156             return false;
1157         }
1158     }
1159 
removeBondInternal(String address)1160     public synchronized boolean removeBondInternal(String address) {
1161         // Unset the trusted device state and then unpair
1162         setTrust(address, false);
1163         return removeDeviceNative(getObjectPathFromAddress(address));
1164     }
1165 
listBonds()1166     public synchronized String[] listBonds() {
1167         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1168         return mBondState.listInState(BluetoothDevice.BOND_BONDED);
1169     }
1170 
listInState(int state)1171     /*package*/ synchronized String[] listInState(int state) {
1172       return mBondState.listInState(state);
1173     }
1174 
getBondState(String address)1175     public synchronized int getBondState(String address) {
1176         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1177         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1178             return BluetoothDevice.ERROR;
1179         }
1180         return mBondState.getBondState(address.toUpperCase());
1181     }
1182 
setBondState(String address, int state)1183     /*package*/ synchronized boolean setBondState(String address, int state) {
1184         return setBondState(address, state, 0);
1185     }
1186 
setBondState(String address, int state, int reason)1187     /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
1188         mBondState.setBondState(address.toUpperCase(), state, reason);
1189         return true;
1190     }
1191 
isBluetoothDock(String address)1192     public synchronized boolean isBluetoothDock(String address) {
1193         SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
1194                 Context.MODE_PRIVATE);
1195 
1196         return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
1197     }
1198 
getRemoteDeviceProperties(String address)1199     /*package*/ String[] getRemoteDeviceProperties(String address) {
1200         if (!isEnabledInternal()) return null;
1201 
1202         String objectPath = getObjectPathFromAddress(address);
1203         return (String [])getDevicePropertiesNative(objectPath);
1204     }
1205 
1206     /**
1207      * Sets the remote device trust state.
1208      *
1209      * @return boolean to indicate operation success or fail
1210      */
setTrust(String address, boolean value)1211     public synchronized boolean setTrust(String address, boolean value) {
1212         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1213             mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1214                     "Need BLUETOOTH_ADMIN permission");
1215             return false;
1216         }
1217 
1218         if (!isEnabledInternal()) return false;
1219 
1220         return setDevicePropertyBooleanNative(
1221                 getObjectPathFromAddress(address), "Trusted", value ? 1 : 0);
1222     }
1223 
1224     /**
1225      * Gets the remote device trust state as boolean.
1226      * Note: this value may be
1227      * retrieved from cache if we retrieved the data before *
1228      *
1229      * @return boolean to indicate trusted or untrusted state
1230      */
getTrustState(String address)1231     public synchronized boolean getTrustState(String address) {
1232         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1233             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1234             return false;
1235         }
1236 
1237         String val = mDeviceProperties.getProperty(address, "Trusted");
1238         if (val == null) {
1239             return false;
1240         } else {
1241             return val.equals("true");
1242         }
1243     }
1244 
1245     /**
1246      * Gets the remote major, minor classes encoded as a 32-bit
1247      * integer.
1248      *
1249      * Note: this value is retrieved from cache, because we get it during
1250      *       remote-device discovery.
1251      *
1252      * @return 32-bit integer encoding the remote major, minor, and service
1253      *         classes.
1254      */
getRemoteClass(String address)1255     public synchronized int getRemoteClass(String address) {
1256         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1257             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1258             return BluetoothClass.ERROR;
1259         }
1260         String val = mDeviceProperties.getProperty(address, "Class");
1261         if (val == null)
1262             return BluetoothClass.ERROR;
1263         else {
1264             return Integer.valueOf(val);
1265         }
1266     }
1267 
1268 
1269     /**
1270      * Gets the UUIDs supported by the remote device
1271      *
1272      * @return array of 128bit ParcelUuids
1273      */
getRemoteUuids(String address)1274     public synchronized ParcelUuid[] getRemoteUuids(String address) {
1275         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1276         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1277             return null;
1278         }
1279         return getUuidFromCache(address);
1280     }
1281 
getUuidFromCache(String address)1282     ParcelUuid[] getUuidFromCache(String address) {
1283         String value = mDeviceProperties.getProperty(address, "UUIDs");
1284         if (value == null) return null;
1285 
1286         String[] uuidStrings = null;
1287         // The UUIDs are stored as a "," separated string.
1288         uuidStrings = value.split(",");
1289         ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1290 
1291         for (int i = 0; i < uuidStrings.length; i++) {
1292             uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1293         }
1294         return uuids;
1295     }
1296 
1297     /**
1298      * Connect and fetch new UUID's using SDP.
1299      * The UUID's found are broadcast as intents.
1300      * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
1301      * a given uuid.
1302      * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
1303      * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
1304      * callback and broadcast intents.
1305      */
fetchRemoteUuids(String address, ParcelUuid uuid, IBluetoothCallback callback)1306     public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
1307             IBluetoothCallback callback) {
1308         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1309         if (!isEnabledInternal()) return false;
1310 
1311         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1312             return false;
1313         }
1314 
1315         RemoteService service = new RemoteService(address, uuid);
1316         if (uuid != null && mUuidCallbackTracker.get(service) != null) {
1317             // An SDP query for this address & uuid is already in progress
1318             // Do not add this callback for the uuid
1319             return false;
1320         }
1321 
1322         if (mUuidIntentTracker.contains(address)) {
1323             // An SDP query for this address is already in progress
1324             // Add this uuid onto the in-progress SDP query
1325             if (uuid != null) {
1326                 mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
1327             }
1328             return true;
1329         }
1330 
1331         // If the device is already created, we will
1332         // do the SDP on the callback of createDeviceNative.
1333         boolean ret= createDeviceNative(address);
1334 
1335         mUuidIntentTracker.add(address);
1336         if (uuid != null) {
1337             mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
1338         }
1339 
1340         Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
1341         message.obj = address;
1342         mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
1343         return ret;
1344     }
1345 
1346     /**
1347      * Gets the rfcomm channel associated with the UUID.
1348      * Pulls records from the cache only.
1349      *
1350      * @param address Address of the remote device
1351      * @param uuid ParcelUuid of the service attribute
1352      *
1353      * @return rfcomm channel associated with the service attribute
1354      *         -1 on error
1355      */
getRemoteServiceChannel(String address, ParcelUuid uuid)1356     public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
1357         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1358         if (!isEnabledInternal()) return -1;
1359 
1360         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1361             return BluetoothDevice.ERROR;
1362         }
1363         // Check if we are recovering from a crash.
1364         if (mDeviceProperties.isEmpty()) {
1365             if (mDeviceProperties.updateCache(address) == null)
1366                 return -1;
1367         }
1368 
1369         Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
1370         if (value != null && value.containsKey(uuid))
1371             return value.get(uuid);
1372         return -1;
1373     }
1374 
setPin(String address, byte[] pin)1375     public synchronized boolean setPin(String address, byte[] pin) {
1376         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1377                                                 "Need BLUETOOTH_ADMIN permission");
1378         if (!isEnabledInternal()) return false;
1379 
1380         if (pin == null || pin.length <= 0 || pin.length > 16 ||
1381             !BluetoothAdapter.checkBluetoothAddress(address)) {
1382             return false;
1383         }
1384         address = address.toUpperCase();
1385         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1386         if (data == null) {
1387             Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
1388                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1389                   " or by bluez.\n");
1390             return false;
1391         }
1392         // bluez API wants pin as a string
1393         String pinString;
1394         try {
1395             pinString = new String(pin, "UTF8");
1396         } catch (UnsupportedEncodingException uee) {
1397             Log.e(TAG, "UTF8 not supported?!?");
1398             return false;
1399         }
1400         return setPinNative(address, pinString, data.intValue());
1401     }
1402 
setPasskey(String address, int passkey)1403     public synchronized boolean setPasskey(String address, int passkey) {
1404         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1405                                                 "Need BLUETOOTH_ADMIN permission");
1406         if (!isEnabledInternal()) return false;
1407 
1408         if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1409             return false;
1410         }
1411         address = address.toUpperCase();
1412         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1413         if (data == null) {
1414             Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1415                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1416                   " or by bluez.\n");
1417             return false;
1418         }
1419         return setPasskeyNative(address, passkey, data.intValue());
1420     }
1421 
setPairingConfirmation(String address, boolean confirm)1422     public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1423         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1424                                                 "Need BLUETOOTH_ADMIN permission");
1425         if (!isEnabledInternal()) return false;
1426 
1427         address = address.toUpperCase();
1428         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1429         if (data == null) {
1430             Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1431                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1432                   " or by bluez.\n");
1433             return false;
1434         }
1435         return setPairingConfirmationNative(address, confirm, data.intValue());
1436     }
1437 
setRemoteOutOfBandData(String address)1438     public synchronized boolean setRemoteOutOfBandData(String address) {
1439         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1440                                                 "Need BLUETOOTH_ADMIN permission");
1441         if (!isEnabledInternal()) return false;
1442         address = address.toUpperCase();
1443         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1444         if (data == null) {
1445             Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
1446                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1447                   " or by bluez.\n");
1448             return false;
1449         }
1450 
1451         Pair<byte[], byte[]> val = mDeviceOobData.get(address);
1452         byte[] hash, randomizer;
1453         if (val == null) {
1454             // TODO: check what should be passed in this case.
1455             hash = new byte[16];
1456             randomizer = new byte[16];
1457         } else {
1458             hash = val.first;
1459             randomizer = val.second;
1460         }
1461         return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
1462     }
1463 
cancelPairingUserInput(String address)1464     public synchronized boolean cancelPairingUserInput(String address) {
1465         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1466                                                 "Need BLUETOOTH_ADMIN permission");
1467         if (!isEnabledInternal()) return false;
1468 
1469         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1470             return false;
1471         }
1472         mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1473                 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1474         address = address.toUpperCase();
1475         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1476         if (data == null) {
1477             Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1478                 "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1479                 "by the remote or by bluez.\n");
1480             return false;
1481         }
1482         return cancelPairingUserInputNative(address, data.intValue());
1483     }
1484 
updateDeviceServiceChannelCache(String address)1485     /*package*/ void updateDeviceServiceChannelCache(String address) {
1486         if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")");
1487 
1488         // We are storing the rfcomm channel numbers only for the uuids
1489         // we are interested in.
1490         ParcelUuid[] deviceUuids = getRemoteUuids(address);
1491 
1492         ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>();
1493 
1494         synchronized (this) {
1495             for (RemoteService service : mUuidCallbackTracker.keySet()) {
1496                 if (service.address.equals(address)) {
1497                     applicationUuids.add(service.uuid);
1498                 }
1499             }
1500         }
1501 
1502         Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>();
1503 
1504         // Retrieve RFCOMM channel for default uuids
1505         for (ParcelUuid uuid : RFCOMM_UUIDS) {
1506             if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
1507                 int channel = getDeviceServiceChannelForUuid(address, uuid);
1508                 uuidToChannelMap.put(uuid, channel);
1509                 if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel);
1510             }
1511         }
1512         // Retrieve RFCOMM channel for application requested uuids
1513         for (ParcelUuid uuid : applicationUuids) {
1514             if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
1515                 int channel = getDeviceServiceChannelForUuid(address, uuid);
1516                 uuidToChannelMap.put(uuid, channel);
1517                 if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel);
1518             }
1519         }
1520 
1521         synchronized (this) {
1522             // Make application callbacks
1523             for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
1524                     iter.hasNext();) {
1525                 RemoteService service = iter.next();
1526                 if (service.address.equals(address)) {
1527                     if (uuidToChannelMap.containsKey(service.uuid)) {
1528                         int channel = uuidToChannelMap.get(service.uuid);
1529 
1530                         if (DBG) Log.d(TAG, "Making callback for " + service.uuid +
1531                                     " with result " + channel);
1532                         IBluetoothCallback callback = mUuidCallbackTracker.get(service);
1533                         if (callback != null) {
1534                             try {
1535                                 callback.onRfcommChannelFound(channel);
1536                             } catch (RemoteException e) {Log.e(TAG, "", e);}
1537                         }
1538 
1539                         iter.remove();
1540                     }
1541                 }
1542             }
1543 
1544             // Update cache
1545             mDeviceServiceChannelCache.put(address, uuidToChannelMap);
1546         }
1547     }
1548 
getDeviceServiceChannelForUuid(String address, ParcelUuid uuid)1549     private int getDeviceServiceChannelForUuid(String address,
1550             ParcelUuid uuid) {
1551         return getDeviceServiceChannelNative(getObjectPathFromAddress(address),
1552                 uuid.toString(), 0x0004);
1553     }
1554 
1555     /**
1556      * b is a handle to a Binder instance, so that this service can be notified
1557      * for Applications that terminate unexpectedly, to clean there service
1558      * records
1559      */
addRfcommServiceRecord(String serviceName, ParcelUuid uuid, int channel, IBinder b)1560     public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
1561             int channel, IBinder b) {
1562         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1563         if (!isEnabledInternal()) return -1;
1564 
1565         if (serviceName == null || uuid == null || channel < 1 ||
1566                 channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
1567             return -1;
1568         }
1569         if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
1570             Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
1571             return -1;
1572         }
1573         int handle = addRfcommServiceRecordNative(serviceName,
1574                 uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
1575                 (short)channel);
1576         if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle));
1577         if (handle == -1) {
1578             return -1;
1579         }
1580 
1581         ServiceRecordClient client = new ServiceRecordClient();
1582         client.pid = Binder.getCallingPid();
1583         client.binder = b;
1584         client.death = new Reaper(handle, client.pid, RFCOMM_RECORD_REAPER);
1585         mServiceRecordToPid.put(new Integer(handle), client);
1586         try {
1587             b.linkToDeath(client.death, 0);
1588         } catch (RemoteException e) {
1589             Log.e(TAG, "", e);
1590             client.death = null;
1591         }
1592         return handle;
1593     }
1594 
removeServiceRecord(int handle)1595     public void removeServiceRecord(int handle) {
1596         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1597                                                 "Need BLUETOOTH permission");
1598         // Since this is a binder call check if Bluetooth is off
1599         if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
1600         Message message = mHandler.obtainMessage(MESSAGE_REMOVE_SERVICE_RECORD);
1601         message.obj = new Pair<Integer, Integer>(handle, Binder.getCallingPid());
1602         mHandler.sendMessage(message);
1603     }
1604 
checkAndRemoveRecord(int handle, int pid)1605     private synchronized void checkAndRemoveRecord(int handle, int pid) {
1606         ServiceRecordClient client = mServiceRecordToPid.get(handle);
1607         if (client != null && pid == client.pid) {
1608             if (DBG) Log.d(TAG, "Removing service record " +
1609                 Integer.toHexString(handle) + " for pid " + pid);
1610 
1611             if (client.death != null) {
1612                 client.binder.unlinkToDeath(client.death, 0);
1613             }
1614 
1615             mServiceRecordToPid.remove(handle);
1616             removeServiceRecordNative(handle);
1617         }
1618     }
1619 
1620     private class Reaper implements IBinder.DeathRecipient {
1621         int mPid;
1622         int mHandle;
1623         int mType;
1624 
Reaper(int handle, int pid, int type)1625         Reaper(int handle, int pid, int type) {
1626             mPid = pid;
1627             mHandle = handle;
1628             mType = type;
1629         }
1630 
Reaper(int pid, int type)1631         Reaper(int pid, int type) {
1632             mPid = pid;
1633             mType = type;
1634         }
1635 
1636         @Override
binderDied()1637         public void binderDied() {
1638             synchronized (BluetoothService.this) {
1639                 if (DBG) Log.d(TAG, "Tracked app " + mPid + " died" + "Type:" + mType);
1640                 if (mType == RFCOMM_RECORD_REAPER) {
1641                     checkAndRemoveRecord(mHandle, mPid);
1642                 } else if (mType == STATE_CHANGE_REAPER) {
1643                     mStateChangeTracker.remove(mPid);
1644                 }
1645             }
1646         }
1647     }
1648 
1649 
1650     @Override
changeApplicationBluetoothState(boolean on, IBluetoothStateChangeCallback callback, IBinder binder)1651     public boolean changeApplicationBluetoothState(boolean on,
1652             IBluetoothStateChangeCallback callback, IBinder binder) {
1653         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1654 
1655         int pid = Binder.getCallingPid();
1656         //mStateChangeTracker is a synchronized map
1657         if (!mStateChangeTracker.containsKey(pid)) {
1658             if (on) {
1659                 mStateChangeTracker.put(pid, callback);
1660             } else {
1661                 return false;
1662             }
1663         } else if (!on) {
1664             mStateChangeTracker.remove(pid);
1665         }
1666 
1667         if (binder != null) {
1668             try {
1669                 binder.linkToDeath(new Reaper(pid, STATE_CHANGE_REAPER), 0);
1670             } catch (RemoteException e) {
1671                 Log.e(TAG, "", e);
1672                 return false;
1673             }
1674         }
1675 
1676         int type;
1677         if (on) {
1678             type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_ON;
1679         } else {
1680             type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_OFF;
1681         }
1682 
1683         mBluetoothState.sendMessage(type, callback);
1684         return true;
1685     }
1686 
isApplicationStateChangeTrackerEmpty()1687     boolean isApplicationStateChangeTrackerEmpty() {
1688         return mStateChangeTracker.isEmpty();
1689     }
1690 
clearApplicationStateChangeTracker()1691     void clearApplicationStateChangeTracker() {
1692         mStateChangeTracker.clear();
1693     }
1694 
getApplicationStateChangeCallbacks()1695     Collection<IBluetoothStateChangeCallback> getApplicationStateChangeCallbacks() {
1696         return mStateChangeTracker.values();
1697     }
1698 
getNumberOfApplicationStateChangeTrackers()1699     int getNumberOfApplicationStateChangeTrackers() {
1700         return mStateChangeTracker.size();
1701     }
1702 
1703     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1704         @Override
1705         public void onReceive(Context context, Intent intent) {
1706             if (intent == null) return;
1707 
1708             String action = intent.getAction();
1709             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
1710                 ContentResolver resolver = context.getContentResolver();
1711                 // Query the airplane mode from Settings.System just to make sure that
1712                 // some random app is not sending this intent and disabling bluetooth
1713                 if (isAirplaneModeOn()) {
1714                     mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_ON);
1715                 } else {
1716                     mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_OFF);
1717                 }
1718             } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
1719                 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
1720                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
1721                 if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
1722                 if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
1723                     mDockAddress = null;
1724                     mDockPin = null;
1725                 } else {
1726                     SharedPreferences.Editor editor =
1727                         mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
1728                                 mContext.MODE_PRIVATE).edit();
1729                     editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
1730                     editor.apply();
1731                 }
1732             }
1733         }
1734     };
1735 
registerForAirplaneMode(IntentFilter filter)1736     private void registerForAirplaneMode(IntentFilter filter) {
1737         final ContentResolver resolver = mContext.getContentResolver();
1738         final String airplaneModeRadios = Settings.System.getString(resolver,
1739                 Settings.System.AIRPLANE_MODE_RADIOS);
1740         final String toggleableRadios = Settings.System.getString(resolver,
1741                 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
1742 
1743         mIsAirplaneSensitive = airplaneModeRadios == null ? true :
1744                 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
1745         mIsAirplaneToggleable = toggleableRadios == null ? false :
1746                 toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
1747 
1748         if (mIsAirplaneSensitive) {
1749             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
1750         }
1751     }
1752 
1753     /* Returns true if airplane mode is currently on */
isAirplaneModeOn()1754     /*package*/ final boolean isAirplaneModeOn() {
1755         return Settings.System.getInt(mContext.getContentResolver(),
1756                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1757     }
1758 
1759     /* Broadcast the Uuid intent */
sendUuidIntent(String address)1760     /*package*/ synchronized void sendUuidIntent(String address) {
1761         ParcelUuid[] uuid = getUuidFromCache(address);
1762         Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
1763         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
1764         intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
1765         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
1766         mUuidIntentTracker.remove(address);
1767     }
1768 
makeServiceChannelCallbacks(String address)1769     /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
1770         for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
1771                 iter.hasNext();) {
1772             RemoteService service = iter.next();
1773             if (service.address.equals(address)) {
1774                 if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: "
1775                     + service.address + " " + service.uuid);
1776                 IBluetoothCallback callback = mUuidCallbackTracker.get(service);
1777                 if (callback != null) {
1778                     try {
1779                         callback.onRfcommChannelFound(-1);
1780                     } catch (RemoteException e) {Log.e(TAG, "", e);}
1781                 }
1782 
1783                 iter.remove();
1784             }
1785         }
1786     }
1787 
1788     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1789     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1790         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1791 
1792         if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
1793             return;
1794         }
1795 
1796         pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
1797         pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
1798 
1799         pw.println("Local address = " + getAddress());
1800         pw.println("Local name = " + getName());
1801         pw.println("isDiscovering() = " + isDiscovering());
1802 
1803         mAdapter.getProfileProxy(mContext,
1804                                  mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
1805         mAdapter.getProfileProxy(mContext,
1806                 mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
1807         mAdapter.getProfileProxy(mContext,
1808                 mBluetoothProfileServiceListener, BluetoothProfile.PAN);
1809 
1810         dumpKnownDevices(pw);
1811         dumpAclConnectedDevices(pw);
1812         dumpHeadsetService(pw);
1813         dumpInputDeviceProfile(pw);
1814         dumpPanProfile(pw);
1815         dumpApplicationServiceRecords(pw);
1816         dumpProfileState(pw);
1817     }
1818 
dumpProfileState(PrintWriter pw)1819     private void dumpProfileState(PrintWriter pw) {
1820         pw.println("\n--Profile State dump--");
1821         pw.println("\n Headset profile state:" +
1822                 mAdapter.getProfileConnectionState(BluetoothProfile.HEADSET));
1823         pw.println("\n A2dp profile state:" +
1824                 mAdapter.getProfileConnectionState(BluetoothProfile.A2DP));
1825         pw.println("\n HID profile state:" +
1826                 mAdapter.getProfileConnectionState(BluetoothProfile.INPUT_DEVICE));
1827         pw.println("\n PAN profile state:" +
1828                 mAdapter.getProfileConnectionState(BluetoothProfile.PAN));
1829     }
1830 
dumpHeadsetService(PrintWriter pw)1831     private void dumpHeadsetService(PrintWriter pw) {
1832         pw.println("\n--Headset Service--");
1833         if (mHeadsetProxy != null) {
1834             List<BluetoothDevice> deviceList = mHeadsetProxy.getConnectedDevices();
1835             if (deviceList.size() == 0) {
1836                 pw.println("No headsets connected");
1837             } else {
1838                 BluetoothDevice device = deviceList.get(0);
1839                 pw.println("\ngetConnectedDevices[0] = " + device);
1840                 dumpHeadsetConnectionState(pw, device);
1841                 pw.println("getBatteryUsageHint() = " +
1842                              mHeadsetProxy.getBatteryUsageHint(device));
1843             }
1844 
1845             deviceList.clear();
1846             deviceList = mHeadsetProxy.getDevicesMatchingConnectionStates(new int[] {
1847                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
1848             pw.println("--Connected and Disconnected Headsets");
1849             for (BluetoothDevice device: deviceList) {
1850                 pw.println(device);
1851                 if (mHeadsetProxy.isAudioConnected(device)) {
1852                     pw.println("SCO audio connected to device:" + device);
1853                 }
1854             }
1855         }
1856     }
1857 
dumpInputDeviceProfile(PrintWriter pw)1858     private void dumpInputDeviceProfile(PrintWriter pw) {
1859         pw.println("\n--Bluetooth Service- Input Device Profile");
1860         if (mInputDevice != null) {
1861             List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
1862             if (deviceList.size() == 0) {
1863                 pw.println("No input devices connected");
1864             } else {
1865                 pw.println("Number of connected devices:" + deviceList.size());
1866                 BluetoothDevice device = deviceList.get(0);
1867                 pw.println("getConnectedDevices[0] = " + device);
1868                 pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
1869 
1870                 switch (mInputDevice.getConnectionState(device)) {
1871                     case BluetoothInputDevice.STATE_CONNECTING:
1872                         pw.println("getConnectionState() = STATE_CONNECTING");
1873                         break;
1874                     case BluetoothInputDevice.STATE_CONNECTED:
1875                         pw.println("getConnectionState() = STATE_CONNECTED");
1876                         break;
1877                     case BluetoothInputDevice.STATE_DISCONNECTING:
1878                         pw.println("getConnectionState() = STATE_DISCONNECTING");
1879                         break;
1880                 }
1881             }
1882             deviceList.clear();
1883             deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
1884                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
1885             pw.println("--Connected and Disconnected input devices");
1886             for (BluetoothDevice device: deviceList) {
1887                 pw.println(device);
1888             }
1889         }
1890     }
1891 
dumpPanProfile(PrintWriter pw)1892     private void dumpPanProfile(PrintWriter pw) {
1893         pw.println("\n--Bluetooth Service- Pan Profile");
1894         if (mPan != null) {
1895             List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
1896             if (deviceList.size() == 0) {
1897                 pw.println("No Pan devices connected");
1898             } else {
1899                 pw.println("Number of connected devices:" + deviceList.size());
1900                 BluetoothDevice device = deviceList.get(0);
1901                 pw.println("getConnectedDevices[0] = " + device);
1902 
1903                 switch (mPan.getConnectionState(device)) {
1904                     case BluetoothInputDevice.STATE_CONNECTING:
1905                         pw.println("getConnectionState() = STATE_CONNECTING");
1906                         break;
1907                     case BluetoothInputDevice.STATE_CONNECTED:
1908                         pw.println("getConnectionState() = STATE_CONNECTED");
1909                         break;
1910                     case BluetoothInputDevice.STATE_DISCONNECTING:
1911                         pw.println("getConnectionState() = STATE_DISCONNECTING");
1912                         break;
1913                 }
1914             }
1915             deviceList.clear();
1916             deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
1917                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
1918             pw.println("--Connected and Disconnected Pan devices");
1919             for (BluetoothDevice device: deviceList) {
1920                 pw.println(device);
1921             }
1922         }
1923     }
1924 
dumpHeadsetConnectionState(PrintWriter pw, BluetoothDevice device)1925     private void dumpHeadsetConnectionState(PrintWriter pw,
1926             BluetoothDevice device) {
1927         switch (mHeadsetProxy.getConnectionState(device)) {
1928             case BluetoothHeadset.STATE_CONNECTING:
1929                 pw.println("getConnectionState() = STATE_CONNECTING");
1930                 break;
1931             case BluetoothHeadset.STATE_CONNECTED:
1932                 pw.println("getConnectionState() = STATE_CONNECTED");
1933                 break;
1934             case BluetoothHeadset.STATE_DISCONNECTING:
1935                 pw.println("getConnectionState() = STATE_DISCONNECTING");
1936                 break;
1937             case BluetoothHeadset.STATE_AUDIO_CONNECTED:
1938                 pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
1939                 break;
1940         }
1941     }
1942 
dumpApplicationServiceRecords(PrintWriter pw)1943     private void dumpApplicationServiceRecords(PrintWriter pw) {
1944         pw.println("\n--Application Service Records--");
1945         for (Integer handle : mServiceRecordToPid.keySet()) {
1946             Integer pid = mServiceRecordToPid.get(handle).pid;
1947             pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
1948         }
1949     }
1950 
dumpAclConnectedDevices(PrintWriter pw)1951     private void dumpAclConnectedDevices(PrintWriter pw) {
1952         String[] devicesObjectPath = getKnownDevices();
1953         pw.println("\n--ACL connected devices--");
1954         if (devicesObjectPath != null) {
1955             for (String device : devicesObjectPath) {
1956                 pw.println(getAddressFromObjectPath(device));
1957             }
1958         }
1959     }
1960 
dumpKnownDevices(PrintWriter pw)1961     private void dumpKnownDevices(PrintWriter pw) {
1962         pw.println("\n--Known devices--");
1963         for (String address : mDeviceProperties.keySet()) {
1964             int bondState = mBondState.getBondState(address);
1965             pw.printf("%s %10s (%d) %s\n", address,
1966                        toBondStateString(bondState),
1967                        mBondState.getAttempt(address),
1968                        getRemoteName(address));
1969 
1970             Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
1971             if (uuidChannels == null) {
1972                 pw.println("\tuuids = null");
1973             } else {
1974                 for (ParcelUuid uuid : uuidChannels.keySet()) {
1975                     Integer channel = uuidChannels.get(uuid);
1976                     if (channel == null) {
1977                         pw.println("\t" + uuid);
1978                     } else {
1979                         pw.println("\t" + uuid + " RFCOMM channel = " + channel);
1980                     }
1981                 }
1982             }
1983             for (RemoteService service : mUuidCallbackTracker.keySet()) {
1984                 if (service.address.equals(address)) {
1985                     pw.println("\tPENDING CALLBACK: " + service.uuid);
1986                 }
1987             }
1988         }
1989     }
1990 
getProfileProxy()1991     private void getProfileProxy() {
1992         mAdapter.getProfileProxy(mContext,
1993                                  mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
1994     }
1995 
1996     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
1997         new BluetoothProfile.ServiceListener() {
1998         public void onServiceConnected(int profile, BluetoothProfile proxy) {
1999             if (profile == BluetoothProfile.HEADSET) {
2000                 mHeadsetProxy = (BluetoothHeadset) proxy;
2001             } else if (profile == BluetoothProfile.INPUT_DEVICE) {
2002                 mInputDevice = (BluetoothInputDevice) proxy;
2003             } else if (profile == BluetoothProfile.PAN) {
2004                 mPan = (BluetoothPan) proxy;
2005             }
2006         }
2007         public void onServiceDisconnected(int profile) {
2008             if (profile == BluetoothProfile.HEADSET) {
2009                 mHeadsetProxy = null;
2010             } else if (profile == BluetoothProfile.INPUT_DEVICE) {
2011                 mInputDevice = null;
2012             } else if (profile == BluetoothProfile.PAN) {
2013                 mPan = null;
2014             }
2015         }
2016     };
2017 
bluezStringToScanMode(boolean pairable, boolean discoverable)2018     /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
2019         if (pairable && discoverable)
2020             return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
2021         else if (pairable && !discoverable)
2022             return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
2023         else
2024             return BluetoothAdapter.SCAN_MODE_NONE;
2025     }
2026 
scanModeToBluezString(int mode)2027     /* package */ static String scanModeToBluezString(int mode) {
2028         switch (mode) {
2029         case BluetoothAdapter.SCAN_MODE_NONE:
2030             return "off";
2031         case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
2032             return "connectable";
2033         case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
2034             return "discoverable";
2035         }
2036         return null;
2037     }
2038 
getAddressFromObjectPath(String objectPath)2039     /*package*/ String getAddressFromObjectPath(String objectPath) {
2040         String adapterObjectPath = mAdapterProperties.getObjectPath();
2041         if (adapterObjectPath == null || objectPath == null) {
2042             Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
2043                     "  or deviceObjectPath:" + objectPath + " is null");
2044             return null;
2045         }
2046         if (!objectPath.startsWith(adapterObjectPath)) {
2047             Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
2048                     "  is not a prefix of deviceObjectPath:" + objectPath +
2049                     "bluetoothd crashed ?");
2050             return null;
2051         }
2052         String address = objectPath.substring(adapterObjectPath.length());
2053         if (address != null) return address.replace('_', ':');
2054 
2055         Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
2056         return null;
2057     }
2058 
getObjectPathFromAddress(String address)2059     /*package*/ String getObjectPathFromAddress(String address) {
2060         String path = mAdapterProperties.getObjectPath();
2061         if (path == null) {
2062             Log.e(TAG, "Error: Object Path is null");
2063             return null;
2064         }
2065         path = path + address.replace(":", "_");
2066         return path;
2067     }
2068 
setLinkTimeout(String address, int num_slots)2069     /*package */ void setLinkTimeout(String address, int num_slots) {
2070         String path = getObjectPathFromAddress(address);
2071         boolean result = setLinkTimeoutNative(path, num_slots);
2072 
2073         if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed");
2074     }
2075 
2076     /**** Handlers for PAN  Profile ****/
2077     // TODO: This needs to be converted to a state machine.
2078 
isTetheringOn()2079     public boolean isTetheringOn() {
2080         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2081         synchronized (mBluetoothPanProfileHandler) {
2082             return mBluetoothPanProfileHandler.isTetheringOn();
2083         }
2084     }
2085 
allowIncomingTethering()2086     /*package*/boolean allowIncomingTethering() {
2087         synchronized (mBluetoothPanProfileHandler) {
2088             return mBluetoothPanProfileHandler.allowIncomingTethering();
2089         }
2090     }
2091 
setBluetoothTethering(boolean value)2092     public void setBluetoothTethering(boolean value) {
2093         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2094         synchronized (mBluetoothPanProfileHandler) {
2095             mBluetoothPanProfileHandler.setBluetoothTethering(value);
2096         }
2097     }
2098 
getPanDeviceConnectionState(BluetoothDevice device)2099     public int getPanDeviceConnectionState(BluetoothDevice device) {
2100         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2101         synchronized (mBluetoothPanProfileHandler) {
2102             return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
2103         }
2104     }
2105 
connectPanDevice(BluetoothDevice device)2106     public boolean connectPanDevice(BluetoothDevice device) {
2107         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2108             "Need BLUETOOTH_ADMIN permission");
2109         synchronized (mBluetoothPanProfileHandler) {
2110             return mBluetoothPanProfileHandler.connectPanDevice(device);
2111         }
2112     }
2113 
getConnectedPanDevices()2114     public List<BluetoothDevice> getConnectedPanDevices() {
2115         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2116         synchronized (mBluetoothPanProfileHandler) {
2117             return mBluetoothPanProfileHandler.getConnectedPanDevices();
2118         }
2119     }
2120 
getPanDevicesMatchingConnectionStates( int[] states)2121     public List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
2122             int[] states) {
2123         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2124         synchronized (mBluetoothPanProfileHandler) {
2125             return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
2126         }
2127     }
2128 
disconnectPanDevice(BluetoothDevice device)2129     public boolean disconnectPanDevice(BluetoothDevice device) {
2130         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2131             "Need BLUETOOTH_ADMIN permission");
2132         synchronized (mBluetoothPanProfileHandler) {
2133             return mBluetoothPanProfileHandler.disconnectPanDevice(device);
2134         }
2135     }
2136 
handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int role)2137     /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
2138                                                              String iface,
2139                                                              int state,
2140                                                              int role) {
2141         synchronized (mBluetoothPanProfileHandler) {
2142             mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
2143         }
2144     }
2145 
handlePanDeviceStateChange(BluetoothDevice device, int state, int role)2146     /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
2147                                                              int state, int role) {
2148         synchronized (mBluetoothPanProfileHandler) {
2149             mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
2150         }
2151     }
2152 
2153     /**** Handlers for Input Device Profile ****/
2154     // This needs to be converted to state machine
2155 
connectInputDevice(BluetoothDevice device)2156     public boolean connectInputDevice(BluetoothDevice device) {
2157         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2158                                                 "Need BLUETOOTH_ADMIN permission");
2159         BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
2160         synchronized (mBluetoothInputProfileHandler) {
2161             return mBluetoothInputProfileHandler.connectInputDevice(device, state);
2162         }
2163     }
2164 
connectInputDeviceInternal(BluetoothDevice device)2165     public boolean connectInputDeviceInternal(BluetoothDevice device) {
2166         synchronized (mBluetoothInputProfileHandler) {
2167             return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
2168         }
2169     }
2170 
disconnectInputDevice(BluetoothDevice device)2171     public boolean disconnectInputDevice(BluetoothDevice device) {
2172         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2173                                                 "Need BLUETOOTH_ADMIN permission");
2174         BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
2175         synchronized (mBluetoothInputProfileHandler) {
2176             return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
2177         }
2178     }
2179 
disconnectInputDeviceInternal(BluetoothDevice device)2180     public boolean disconnectInputDeviceInternal(BluetoothDevice device) {
2181         synchronized (mBluetoothInputProfileHandler) {
2182             return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
2183         }
2184     }
2185 
getInputDeviceConnectionState(BluetoothDevice device)2186     public int getInputDeviceConnectionState(BluetoothDevice device) {
2187         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2188         synchronized (mBluetoothInputProfileHandler) {
2189             return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
2190         }
2191     }
2192 
getConnectedInputDevices()2193     public List<BluetoothDevice> getConnectedInputDevices() {
2194         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2195         synchronized (mBluetoothInputProfileHandler) {
2196             return mBluetoothInputProfileHandler.getConnectedInputDevices();
2197         }
2198     }
2199 
getInputDevicesMatchingConnectionStates( int[] states)2200     public List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
2201             int[] states) {
2202         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2203         synchronized (mBluetoothInputProfileHandler) {
2204             return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
2205         }
2206     }
2207 
2208 
getInputDevicePriority(BluetoothDevice device)2209     public int getInputDevicePriority(BluetoothDevice device) {
2210         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2211         synchronized (mBluetoothInputProfileHandler) {
2212             return mBluetoothInputProfileHandler.getInputDevicePriority(device);
2213         }
2214     }
2215 
setInputDevicePriority(BluetoothDevice device, int priority)2216     public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
2217         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2218                                                 "Need BLUETOOTH_ADMIN permission");
2219         synchronized (mBluetoothInputProfileHandler) {
2220             return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
2221         }
2222     }
2223 
2224     /**
2225      * Handle incoming profile acceptance for profiles handled by Bluetooth Service,
2226      * currently PAN and HID. This also is the catch all for all rejections for profiles
2227      * that is not supported.
2228      *
2229      * @param device - Bluetooth Device
2230      * @param allow - true / false
2231      * @return
2232      */
allowIncomingProfileConnect(BluetoothDevice device, boolean allow)2233     public boolean allowIncomingProfileConnect(BluetoothDevice device, boolean allow) {
2234         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2235                                                 "Need BLUETOOTH_ADMIN permission");
2236         String address = device.getAddress();
2237         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
2238             return false;
2239         }
2240 
2241         Integer data = getAuthorizationAgentRequestData(address);
2242         if (data == null) {
2243             Log.w(TAG, "allowIncomingProfileConnect(" + device +
2244                   ") called but no native data available");
2245             return false;
2246         }
2247         if (DBG) log("allowIncomingProfileConnect: " + device + " : " + allow + " : " + data);
2248         return setAuthorizationNative(address, allow, data.intValue());
2249     }
2250 
lookupInputDevicesMatchingStates(int[] states)2251     /*package*/List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
2252         synchronized (mBluetoothInputProfileHandler) {
2253             return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
2254         }
2255     }
2256 
handleInputDevicePropertyChange(String address, boolean connected)2257     /*package*/void handleInputDevicePropertyChange(String address, boolean connected) {
2258         synchronized (mBluetoothInputProfileHandler) {
2259             mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
2260         }
2261     }
2262 
2263     /**** Handlers for Health Device Profile ****/
2264     // TODO: All these need to be converted to a state machine.
2265 
registerAppConfiguration(BluetoothHealthAppConfiguration config, IBluetoothHealthCallback callback)2266     public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
2267                                             IBluetoothHealthCallback callback) {
2268         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2269                 "Need BLUETOOTH permission");
2270         synchronized (mBluetoothHealthProfileHandler) {
2271                 return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback);
2272         }
2273     }
2274 
unregisterAppConfiguration(BluetoothHealthAppConfiguration config)2275     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
2276         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2277                 "Need BLUETOOTH permission");
2278         synchronized (mBluetoothHealthProfileHandler) {
2279                 return mBluetoothHealthProfileHandler.unregisterAppConfiguration(config);
2280         }
2281     }
2282 
2283 
connectChannelToSource(BluetoothDevice device, BluetoothHealthAppConfiguration config)2284     public boolean connectChannelToSource(BluetoothDevice device,
2285             BluetoothHealthAppConfiguration config) {
2286         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2287                 "Need BLUETOOTH permission");
2288         synchronized (mBluetoothHealthProfileHandler) {
2289             return mBluetoothHealthProfileHandler.connectChannelToSource(device,
2290                     config);
2291         }
2292     }
2293 
connectChannelToSink(BluetoothDevice device, BluetoothHealthAppConfiguration config, int channelType)2294     public boolean connectChannelToSink(BluetoothDevice device,
2295             BluetoothHealthAppConfiguration config, int channelType) {
2296         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2297                                                 "Need BLUETOOTH permission");
2298         synchronized (mBluetoothHealthProfileHandler) {
2299             return mBluetoothHealthProfileHandler.connectChannel(device, config,
2300                     channelType);
2301         }
2302     }
2303 
disconnectChannel(BluetoothDevice device, BluetoothHealthAppConfiguration config, int id)2304     public boolean disconnectChannel(BluetoothDevice device,
2305             BluetoothHealthAppConfiguration config, int id) {
2306         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2307                 "Need BLUETOOTH permission");
2308         synchronized (mBluetoothHealthProfileHandler) {
2309             return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id);
2310         }
2311     }
2312 
getMainChannelFd(BluetoothDevice device, BluetoothHealthAppConfiguration config)2313     public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
2314             BluetoothHealthAppConfiguration config) {
2315         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2316                 "Need BLUETOOTH permission");
2317         synchronized (mBluetoothHealthProfileHandler) {
2318             return mBluetoothHealthProfileHandler.getMainChannelFd(device, config);
2319         }
2320     }
2321 
onHealthDevicePropertyChanged(String devicePath, String channelPath)2322     /*package*/ void onHealthDevicePropertyChanged(String devicePath,
2323             String channelPath) {
2324         synchronized (mBluetoothHealthProfileHandler) {
2325             mBluetoothHealthProfileHandler.onHealthDevicePropertyChanged(devicePath,
2326                     channelPath);
2327         }
2328     }
2329 
onHealthDeviceChannelChanged(String devicePath, String channelPath, boolean exists)2330     /*package*/ void onHealthDeviceChannelChanged(String devicePath,
2331             String channelPath, boolean exists) {
2332         synchronized(mBluetoothHealthProfileHandler) {
2333             mBluetoothHealthProfileHandler.onHealthDeviceChannelChanged(devicePath,
2334                     channelPath, exists);
2335         }
2336     }
2337 
onHealthDeviceChannelConnectionError(int channelCode, int newState)2338     /*package*/ void onHealthDeviceChannelConnectionError(int channelCode,
2339             int newState) {
2340         synchronized(mBluetoothHealthProfileHandler) {
2341             mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode,
2342                                                                                 newState);
2343         }
2344     }
2345 
getHealthDeviceConnectionState(BluetoothDevice device)2346     public int getHealthDeviceConnectionState(BluetoothDevice device) {
2347         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2348                 "Need BLUETOOTH permission");
2349         synchronized (mBluetoothHealthProfileHandler) {
2350             return mBluetoothHealthProfileHandler.getHealthDeviceConnectionState(device);
2351         }
2352     }
2353 
getConnectedHealthDevices()2354     public List<BluetoothDevice> getConnectedHealthDevices() {
2355         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2356                 "Need BLUETOOTH permission");
2357         synchronized (mBluetoothHealthProfileHandler) {
2358             return mBluetoothHealthProfileHandler.getConnectedHealthDevices();
2359         }
2360     }
2361 
getHealthDevicesMatchingConnectionStates( int[] states)2362     public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(
2363             int[] states) {
2364         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
2365                 "Need BLUETOOTH permission");
2366         synchronized (mBluetoothHealthProfileHandler) {
2367             return mBluetoothHealthProfileHandler.
2368                     getHealthDevicesMatchingConnectionStates(states);
2369         }
2370     }
2371 
notifyIncomingHidConnection(String address)2372     /*package*/boolean notifyIncomingHidConnection(String address) {
2373         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2374         if (state == null) {
2375             return false;
2376         }
2377         Message msg = new Message();
2378         msg.what = BluetoothDeviceProfileState.CONNECT_HID_INCOMING;
2379         state.sendMessage(msg);
2380         return true;
2381     }
2382 
connectHeadset(String address)2383     public boolean connectHeadset(String address) {
2384         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
2385 
2386         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2387         if (state != null) {
2388             Message msg = new Message();
2389             msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2390             msg.obj = state;
2391             mHfpProfileState.sendMessage(msg);
2392             return true;
2393         }
2394         return false;
2395     }
2396 
disconnectHeadset(String address)2397     public boolean disconnectHeadset(String address) {
2398         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
2399 
2400         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2401         if (state != null) {
2402             Message msg = new Message();
2403             msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2404             msg.obj = state;
2405             mHfpProfileState.sendMessage(msg);
2406             return true;
2407         }
2408         return false;
2409     }
2410 
connectSink(String address)2411     public boolean connectSink(String address) {
2412         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
2413 
2414         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2415         if (state != null) {
2416             Message msg = new Message();
2417             msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2418             msg.obj = state;
2419             mA2dpProfileState.sendMessage(msg);
2420             return true;
2421         }
2422         return false;
2423     }
2424 
disconnectSink(String address)2425     public boolean disconnectSink(String address) {
2426         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
2427 
2428         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2429         if (state != null) {
2430             Message msg = new Message();
2431             msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2432             msg.obj = state;
2433             mA2dpProfileState.sendMessage(msg);
2434             return true;
2435         }
2436         return false;
2437     }
2438 
addProfileState(String address, boolean setTrust)2439     BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) {
2440         BluetoothDeviceProfileState state =
2441             new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
2442         mDeviceProfileState.put(address, state);
2443         state.start();
2444         return state;
2445     }
2446 
removeProfileState(String address)2447     void removeProfileState(String address) {
2448         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2449         if (state == null) return;
2450 
2451         state.quit();
2452         mDeviceProfileState.remove(address);
2453     }
2454 
getKnownDevices()2455     String[] getKnownDevices() {
2456         String[] bonds = null;
2457         String val = getProperty("Devices", true);
2458         if (val != null) {
2459             bonds = val.split(",");
2460         }
2461         return bonds;
2462     }
2463 
initProfileState()2464     private void initProfileState() {
2465         String[] bonds = null;
2466         String val = getProperty("Devices", false);
2467         if (val != null) {
2468             bonds = val.split(",");
2469         }
2470         if (bonds == null) {
2471             return;
2472         }
2473         for (String path : bonds) {
2474             String address = getAddressFromObjectPath(path);
2475             BluetoothDeviceProfileState state = addProfileState(address, false);
2476         }
2477     }
2478 
autoConnect()2479     private void autoConnect() {
2480         synchronized (this) {
2481             if (!mAllowConnect) {
2482                 Log.d(TAG, "Not auto-connecting devices because of temporary BT on state.");
2483                 return;
2484             }
2485         }
2486 
2487         String[] bonds = getKnownDevices();
2488         if (bonds == null) {
2489             return;
2490         }
2491         for (String path : bonds) {
2492             String address = getAddressFromObjectPath(path);
2493             BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2494             if (state != null) {
2495                 Message msg = new Message();
2496                 msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
2497                 state.sendMessage(msg);
2498             }
2499         }
2500     }
2501 
notifyIncomingConnection(String address, boolean rejected)2502     public boolean notifyIncomingConnection(String address, boolean rejected) {
2503         synchronized (this) {
2504             if (!mAllowConnect) {
2505                 Log.d(TAG, "Not allowing incoming connection because of temporary BT on state.");
2506                 return false;
2507             }
2508         }
2509         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2510         if (state != null) {
2511             Message msg = new Message();
2512             if (rejected) {
2513                 if (mA2dpService.getPriority(getRemoteDevice(address)) >=
2514                     BluetoothProfile.PRIORITY_ON) {
2515                     msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
2516                     msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2517                     state.sendMessageDelayed(msg,
2518                         BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
2519                 }
2520             } else {
2521                 msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
2522                 state.sendMessage(msg);
2523             }
2524             return true;
2525         }
2526         return false;
2527     }
2528 
notifyIncomingA2dpConnection(String address, boolean rejected)2529     /*package*/ boolean notifyIncomingA2dpConnection(String address, boolean rejected) {
2530         synchronized (this) {
2531             if (!mAllowConnect) {
2532                 Log.d(TAG, "Not allowing a2dp connection because of temporary BT on state.");
2533                 return false;
2534             }
2535         }
2536 
2537        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2538        if (state != null) {
2539            Message msg = new Message();
2540            if (rejected) {
2541                if (mHeadsetProxy.getPriority(getRemoteDevice(address)) >=
2542                    BluetoothProfile.PRIORITY_ON) {
2543                    msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
2544                    msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2545                    state.sendMessageDelayed(msg,
2546                              BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
2547                }
2548            } else {
2549                msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
2550                state.sendMessage(msg);
2551            }
2552            return true;
2553        }
2554        return false;
2555     }
2556 
setA2dpService(BluetoothA2dpService a2dpService)2557     /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
2558         mA2dpService = a2dpService;
2559     }
2560 
getAuthorizationAgentRequestData(String address)2561     /*package*/ Integer getAuthorizationAgentRequestData(String address) {
2562         Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address);
2563         return data;
2564     }
2565 
sendProfileStateMessage(int profile, int cmd)2566     public void sendProfileStateMessage(int profile, int cmd) {
2567         Message msg = new Message();
2568         msg.what = cmd;
2569         if (profile == BluetoothProfileState.HFP) {
2570             mHfpProfileState.sendMessage(msg);
2571         } else if (profile == BluetoothProfileState.A2DP) {
2572             mA2dpProfileState.sendMessage(msg);
2573         }
2574     }
2575 
getAdapterConnectionState()2576     public int getAdapterConnectionState() {
2577         return mAdapterConnectionState;
2578     }
2579 
getProfileConnectionState(int profile)2580     public int getProfileConnectionState(int profile) {
2581         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2582 
2583         Pair<Integer, Integer> state = mProfileConnectionState.get(profile);
2584         if (state == null) return BluetoothProfile.STATE_DISCONNECTED;
2585 
2586         return state.first;
2587     }
2588 
updateProfileConnectionState(int profile, int newState, int oldState)2589     private void updateProfileConnectionState(int profile, int newState, int oldState) {
2590         // mProfileConnectionState is a hashmap -
2591         // <Integer, Pair<Integer, Integer>>
2592         // The key is the profile, the value is a pair. first element
2593         // is the state and the second element is the number of devices
2594         // in that state.
2595         int numDev = 1;
2596         int newHashState = newState;
2597         boolean update = true;
2598 
2599         // The following conditions are considered in this function:
2600         // 1. If there is no record of profile and state - update
2601         // 2. If a new device's state is current hash state - increment
2602         //    number of devices in the state.
2603         // 3. If a state change has happened to Connected or Connecting
2604         //    (if current state is not connected), update.
2605         // 4. If numDevices is 1 and that device state is being updated, update
2606         // 5. If numDevices is > 1 and one of the devices is changing state,
2607         //    decrement numDevices but maintain oldState if it is Connected or
2608         //    Connecting
2609         Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile);
2610         if (stateNumDev != null) {
2611             int currHashState = stateNumDev.first;
2612             numDev = stateNumDev.second;
2613 
2614             if (newState == currHashState) {
2615                 numDev ++;
2616             } else if (newState == BluetoothProfile.STATE_CONNECTED ||
2617                    (newState == BluetoothProfile.STATE_CONNECTING &&
2618                     currHashState != BluetoothProfile.STATE_CONNECTED)) {
2619                  numDev = 1;
2620             } else if (numDev == 1 && oldState == currHashState) {
2621                  update = true;
2622             } else if (numDev > 1 && oldState == currHashState) {
2623                  numDev --;
2624 
2625                  if (currHashState == BluetoothProfile.STATE_CONNECTED ||
2626                      currHashState == BluetoothProfile.STATE_CONNECTING) {
2627                     newHashState = currHashState;
2628                  }
2629             } else {
2630                  update = false;
2631             }
2632         }
2633 
2634         if (update) {
2635             mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState,
2636                     numDev));
2637         }
2638     }
2639 
sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState)2640     public synchronized void sendConnectionStateChange(BluetoothDevice
2641             device, int profile, int state, int prevState) {
2642         // Since this is a binder call check if Bluetooth is on still
2643         if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
2644 
2645         if (!validateProfileConnectionState(state) ||
2646                 !validateProfileConnectionState(prevState)) {
2647             // Previously, an invalid state was broadcast anyway,
2648             // with the invalid state converted to -1 in the intent.
2649             // Better to log an error and not send an intent with
2650             // invalid contents or set mAdapterConnectionState to -1.
2651             Log.e(TAG, "Error in sendConnectionStateChange: "
2652                     + "prevState " + prevState + " state " + state);
2653             return;
2654         }
2655 
2656         updateProfileConnectionState(profile, state, prevState);
2657 
2658         if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
2659             mAdapterConnectionState = state;
2660 
2661             if (state == BluetoothProfile.STATE_DISCONNECTED) {
2662                 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.ALL_DEVICES_DISCONNECTED);
2663             }
2664 
2665             Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
2666             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
2667             intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
2668                     convertToAdapterState(state));
2669             intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
2670                     convertToAdapterState(prevState));
2671             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2672             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
2673             Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
2674                     + prevState + " -> " + state);
2675         }
2676     }
2677 
validateProfileConnectionState(int state)2678     private boolean validateProfileConnectionState(int state) {
2679         return (state == BluetoothProfile.STATE_DISCONNECTED ||
2680                 state == BluetoothProfile.STATE_CONNECTING ||
2681                 state == BluetoothProfile.STATE_CONNECTED ||
2682                 state == BluetoothProfile.STATE_DISCONNECTING);
2683     }
2684 
convertToAdapterState(int state)2685     private int convertToAdapterState(int state) {
2686         switch (state) {
2687             case BluetoothProfile.STATE_DISCONNECTED:
2688                 return BluetoothAdapter.STATE_DISCONNECTED;
2689             case BluetoothProfile.STATE_DISCONNECTING:
2690                 return BluetoothAdapter.STATE_DISCONNECTING;
2691             case BluetoothProfile.STATE_CONNECTED:
2692                 return BluetoothAdapter.STATE_CONNECTED;
2693             case BluetoothProfile.STATE_CONNECTING:
2694                 return BluetoothAdapter.STATE_CONNECTING;
2695         }
2696         Log.e(TAG, "Error in convertToAdapterState");
2697         return -1;
2698     }
2699 
updateCountersAndCheckForConnectionStateChange(int state, int prevState)2700     private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
2701         switch (prevState) {
2702             case BluetoothProfile.STATE_CONNECTING:
2703                 mProfilesConnecting--;
2704                 break;
2705 
2706             case BluetoothProfile.STATE_CONNECTED:
2707                 mProfilesConnected--;
2708                 break;
2709 
2710             case BluetoothProfile.STATE_DISCONNECTING:
2711                 mProfilesDisconnecting--;
2712                 break;
2713         }
2714 
2715         switch (state) {
2716             case BluetoothProfile.STATE_CONNECTING:
2717                 mProfilesConnecting++;
2718                 return (mProfilesConnected == 0 && mProfilesConnecting == 1);
2719 
2720             case BluetoothProfile.STATE_CONNECTED:
2721                 mProfilesConnected++;
2722                 return (mProfilesConnected == 1);
2723 
2724             case BluetoothProfile.STATE_DISCONNECTING:
2725                 mProfilesDisconnecting++;
2726                 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
2727 
2728             case BluetoothProfile.STATE_DISCONNECTED:
2729                 return (mProfilesConnected == 0 && mProfilesConnecting == 0);
2730 
2731             default:
2732                 return true;
2733         }
2734     }
2735 
createIncomingConnectionStateFile()2736     private void createIncomingConnectionStateFile() {
2737         File f = new File(INCOMING_CONNECTION_FILE);
2738         if (!f.exists()) {
2739             try {
2740                 f.createNewFile();
2741             } catch (IOException e) {
2742                 Log.e(TAG, "IOException: cannot create file");
2743             }
2744         }
2745     }
2746 
2747     /** @hide */
getIncomingState(String address)2748     public Pair<Integer, String> getIncomingState(String address) {
2749         if (mIncomingConnections.isEmpty()) {
2750             createIncomingConnectionStateFile();
2751             readIncomingConnectionState();
2752         }
2753         return mIncomingConnections.get(address);
2754     }
2755 
readIncomingConnectionState()2756     private void readIncomingConnectionState() {
2757         synchronized(mIncomingConnections) {
2758             FileInputStream fstream = null;
2759             try {
2760               fstream = new FileInputStream(INCOMING_CONNECTION_FILE);
2761               DataInputStream in = new DataInputStream(fstream);
2762               BufferedReader file = new BufferedReader(new InputStreamReader(in));
2763               String line;
2764               while((line = file.readLine()) != null) {
2765                   line = line.trim();
2766                   if (line.length() == 0) continue;
2767                   String[] value = line.split(",");
2768                   if (value != null && value.length == 3) {
2769                       Integer val1 = Integer.parseInt(value[1]);
2770                       Pair<Integer, String> val = new Pair(val1, value[2]);
2771                       mIncomingConnections.put(value[0], val);
2772                   }
2773               }
2774             } catch (FileNotFoundException e) {
2775                 log("FileNotFoundException: readIncomingConnectionState" + e.toString());
2776             } catch (IOException e) {
2777                 log("IOException: readIncomingConnectionState" + e.toString());
2778             } finally {
2779                 if (fstream != null) {
2780                     try {
2781                         fstream.close();
2782                     } catch (IOException e) {
2783                         // Ignore
2784                     }
2785                 }
2786             }
2787         }
2788     }
2789 
truncateIncomingConnectionFile()2790     private void truncateIncomingConnectionFile() {
2791         RandomAccessFile r = null;
2792         try {
2793             r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw");
2794             r.setLength(0);
2795         } catch (FileNotFoundException e) {
2796             log("FileNotFoundException: truncateIncomingConnectionState" + e.toString());
2797         } catch (IOException e) {
2798             log("IOException: truncateIncomingConnectionState" + e.toString());
2799         } finally {
2800             if (r != null) {
2801                 try {
2802                     r.close();
2803                 } catch (IOException e) {
2804                     // ignore
2805                  }
2806             }
2807         }
2808     }
2809 
2810     /** @hide */
writeIncomingConnectionState(String address, Pair<Integer, String> data)2811     public void writeIncomingConnectionState(String address, Pair<Integer, String> data) {
2812         synchronized(mIncomingConnections) {
2813             mIncomingConnections.put(address, data);
2814 
2815             truncateIncomingConnectionFile();
2816             BufferedWriter out = null;
2817             StringBuilder value = new StringBuilder();
2818             try {
2819                 out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true));
2820                 for (String devAddress: mIncomingConnections.keySet()) {
2821                   Pair<Integer, String> val = mIncomingConnections.get(devAddress);
2822                   value.append(devAddress);
2823                   value.append(",");
2824                   value.append(val.first.toString());
2825                   value.append(",");
2826                   value.append(val.second);
2827                   value.append("\n");
2828                 }
2829                 out.write(value.toString());
2830             } catch (FileNotFoundException e) {
2831                 log("FileNotFoundException: writeIncomingConnectionState" + e.toString());
2832             } catch (IOException e) {
2833                 log("IOException: writeIncomingConnectionState" + e.toString());
2834             } finally {
2835                 if (out != null) {
2836                     try {
2837                         out.close();
2838                     } catch (IOException e) {
2839                         // Ignore
2840                     }
2841                 }
2842             }
2843         }
2844     }
2845 
log(String msg)2846     private static void log(String msg) {
2847         Log.d(TAG, msg);
2848     }
2849 
classInitNative()2850     private native static void classInitNative();
initializeNativeDataNative()2851     private native void initializeNativeDataNative();
setupNativeDataNative()2852     private native boolean setupNativeDataNative();
tearDownNativeDataNative()2853     private native boolean tearDownNativeDataNative();
cleanupNativeDataNative()2854     private native void cleanupNativeDataNative();
getAdapterPathNative()2855     /*package*/ native String getAdapterPathNative();
2856 
isEnabledNative()2857     private native int isEnabledNative();
enableNative()2858     /*package*/ native int enableNative();
disableNative()2859     /*package*/ native int disableNative();
2860 
getAdapterPropertiesNative()2861     /*package*/ native Object[] getAdapterPropertiesNative();
getDevicePropertiesNative(String objectPath)2862     private native Object[] getDevicePropertiesNative(String objectPath);
setAdapterPropertyStringNative(String key, String value)2863     private native boolean setAdapterPropertyStringNative(String key, String value);
setAdapterPropertyIntegerNative(String key, int value)2864     private native boolean setAdapterPropertyIntegerNative(String key, int value);
setAdapterPropertyBooleanNative(String key, int value)2865     private native boolean setAdapterPropertyBooleanNative(String key, int value);
2866 
startDiscoveryNative()2867     private native boolean startDiscoveryNative();
stopDiscoveryNative()2868     private native boolean stopDiscoveryNative();
2869 
createPairedDeviceNative(String address, int timeout_ms)2870     private native boolean createPairedDeviceNative(String address, int timeout_ms);
createPairedDeviceOutOfBandNative(String address, int timeout_ms)2871     private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
readAdapterOutOfBandDataNative()2872     private native byte[] readAdapterOutOfBandDataNative();
2873 
cancelDeviceCreationNative(String address)2874     private native boolean cancelDeviceCreationNative(String address);
removeDeviceNative(String objectPath)2875     private native boolean removeDeviceNative(String objectPath);
getDeviceServiceChannelNative(String objectPath, String uuid, int attributeId)2876     private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2877             int attributeId);
2878 
cancelPairingUserInputNative(String address, int nativeData)2879     private native boolean cancelPairingUserInputNative(String address, int nativeData);
setPinNative(String address, String pin, int nativeData)2880     private native boolean setPinNative(String address, String pin, int nativeData);
setPasskeyNative(String address, int passkey, int nativeData)2881     private native boolean setPasskeyNative(String address, int passkey, int nativeData);
setPairingConfirmationNative(String address, boolean confirm, int nativeData)2882     private native boolean setPairingConfirmationNative(String address, boolean confirm,
2883             int nativeData);
setRemoteOutOfBandDataNative(String address, byte[] hash, byte[] randomizer, int nativeData)2884     private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
2885                                                         byte[] randomizer, int nativeData);
2886 
setDevicePropertyBooleanNative(String objectPath, String key, int value)2887     private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
2888             int value);
setDevicePropertyStringNative(String objectPath, String key, String value)2889     private native boolean setDevicePropertyStringNative(String objectPath, String key,
2890             String value);
createDeviceNative(String address)2891     private native boolean createDeviceNative(String address);
discoverServicesNative(String objectPath, String pattern)2892     /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
2893 
addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, short channel)2894     private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
2895             short channel);
removeServiceRecordNative(int handle)2896     private native boolean removeServiceRecordNative(int handle);
setLinkTimeoutNative(String path, int num_slots)2897     private native boolean setLinkTimeoutNative(String path, int num_slots);
2898 
connectInputDeviceNative(String path)2899     native boolean connectInputDeviceNative(String path);
disconnectInputDeviceNative(String path)2900     native boolean disconnectInputDeviceNative(String path);
2901 
setBluetoothTetheringNative(boolean value, String nap, String bridge)2902     native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge);
connectPanDeviceNative(String path, String dstRole)2903     native boolean connectPanDeviceNative(String path, String dstRole);
disconnectPanDeviceNative(String path)2904     native boolean disconnectPanDeviceNative(String path);
disconnectPanServerDeviceNative(String path, String address, String iface)2905     native boolean disconnectPanServerDeviceNative(String path,
2906             String address, String iface);
2907 
addReservedServiceRecordsNative(int[] uuuids)2908     private native int[] addReservedServiceRecordsNative(int[] uuuids);
removeReservedServiceRecordsNative(int[] handles)2909     private native boolean removeReservedServiceRecordsNative(int[] handles);
2910 
2911     // Health API
registerHealthApplicationNative(int dataType, String role, String name, String channelType)2912     native String registerHealthApplicationNative(int dataType, String role, String name,
2913             String channelType);
registerHealthApplicationNative(int dataType, String role, String name)2914     native String registerHealthApplicationNative(int dataType, String role, String name);
unregisterHealthApplicationNative(String path)2915     native boolean unregisterHealthApplicationNative(String path);
createChannelNative(String devicePath, String appPath, String channelType, int code)2916     native boolean createChannelNative(String devicePath, String appPath, String channelType,
2917                                        int code);
destroyChannelNative(String devicePath, String channelpath, int code)2918     native boolean destroyChannelNative(String devicePath, String channelpath, int code);
getMainChannelNative(String path)2919     native String getMainChannelNative(String path);
getChannelApplicationNative(String channelPath)2920     native String getChannelApplicationNative(String channelPath);
getChannelFdNative(String channelPath)2921     native ParcelFileDescriptor getChannelFdNative(String channelPath);
releaseChannelFdNative(String channelPath)2922     native boolean releaseChannelFdNative(String channelPath);
setAuthorizationNative(String address, boolean value, int data)2923     native boolean setAuthorizationNative(String address, boolean value, int data);
2924 }
2925