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