AdapterService.java revision 6654f5c903de510a70f9e72cd5ad7837b615d93f
1/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5/**
6 * @hide
7 */
8
9package com.android.bluetooth.btservice;
10
11import android.app.Application;
12import android.app.Service;
13import android.bluetooth.BluetoothAdapter;
14import android.bluetooth.BluetoothDevice;
15import android.bluetooth.BluetoothProfile;
16import android.bluetooth.IBluetooth;
17import android.content.BroadcastReceiver;
18import android.content.ContentResolver;
19import android.content.Context;
20import android.content.Intent;
21import android.content.IntentFilter;
22import android.os.Binder;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.Message;
26import android.os.ParcelFileDescriptor;
27import android.os.ParcelUuid;
28import android.os.RemoteException;
29import android.provider.Settings;
30import android.util.Log;
31import android.util.Pair;
32
33import com.android.bluetooth.a2dp.A2dpService;
34import com.android.bluetooth.hid.HidService;
35import com.android.bluetooth.hfp.HeadsetService;
36import com.android.bluetooth.hdp.HealthService;
37import com.android.bluetooth.pan.PanService;
38import com.android.bluetooth.Utils;
39import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
40
41import java.io.FileDescriptor;
42import java.io.IOException;
43import java.util.HashMap;
44import java.util.Set;
45import java.util.Map;
46import java.util.Iterator;
47import java.util.Map.Entry;
48import android.content.pm.PackageManager;
49
50
51public class AdapterService extends Service {
52    private static final String TAG = "BluetoothAdapterService";
53    private static final boolean DBG = true;
54
55    /**
56     * List of profile services to support.Comment out to disable a profile
57     * Profiles started in order of appearance
58     */
59    @SuppressWarnings("rawtypes")
60    private static final Class[] SUPPORTED_PROFILE_SERVICES = {
61        HeadsetService.class,
62        A2dpService.class,
63        HidService.class,
64        HealthService.class,
65        PanService.class
66    };
67
68    public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
69    public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
70    public static final String EXTRA_ACTION="action";
71
72    static final String BLUETOOTH_ADMIN_PERM =
73        android.Manifest.permission.BLUETOOTH_ADMIN;
74    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
75
76    private AdapterProperties mAdapterProperties;
77    private int mAdapterState;
78    private Context mContext;
79    private boolean mIsAirplaneSensitive;
80    private boolean mIsAirplaneToggleable;
81    private static AdapterService sAdapterService;
82
83    private AdapterState mAdapterStateMachine;
84    private BondStateMachine mBondStateMachine;
85    private JniCallbacks mJniCallbacks;
86    private RemoteDevices mRemoteDevices;
87    private boolean mStopPending;
88    private boolean mStartPending;
89    private boolean mProfilesStarted;
90    private boolean mNativeAvailable;
91    private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>();
92
93    //In case Bluetooth app crashes, we need to reinit JNI
94    private static boolean mIsJniInited;
95    private static synchronized void initJni() {
96        if (!mIsJniInited) {
97            if (DBG) Log.d(TAG,"Initializing JNI Library");
98            System.loadLibrary("bluetooth_jni");
99            classInitNative();
100            mIsJniInited=true;
101        }
102    }
103
104    public static AdapterService getAdapterService(){
105        return sAdapterService;
106    }
107
108    public void onProfileServiceStateChanged(String serviceName, int state) {
109        if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state);
110        boolean doUpdate=false;
111        synchronized (mProfileServicesState) {
112            Integer prevState = mProfileServicesState.get(serviceName);
113            if (prevState != null && prevState != state) {
114                mProfileServicesState.put(serviceName,state);
115                doUpdate=true;
116            }
117        }
118        if (!doUpdate) {
119            return;
120        }
121        if (mStopPending) {
122            //Process stop or disable pending
123            //Check if all services are stopped if so, do cleanup
124            if (DBG) Log.d(TAG,"Checking if all profiles are stopped...");
125            synchronized (mProfileServicesState) {
126                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
127                while (i.hasNext()) {
128                    Map.Entry<String,Integer> entry = i.next();
129                    if (BluetoothAdapter.STATE_OFF != entry.getValue()) {
130                        //Log.d(TAG, "Profile still running: " entry.getKey());
131                        return;
132                    }
133                }
134            }
135            if (DBG) Log.d(TAG, "All profile services stopped...");
136            Message m = mHandler.obtainMessage(MESSAGE_ONSTOPPED_STOPPENDING);
137            mHandler.sendMessage(m);
138        } else if (mStartPending) {
139            //Process start pending
140            //Check if all services are started if so, update state
141            if (DBG) Log.d(TAG,"Checking if all profiles are running...");
142            synchronized (mProfileServicesState) {
143                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
144                while (i.hasNext()) {
145                    Map.Entry<String,Integer> entry = i.next();
146                    if (BluetoothAdapter.STATE_ON != entry.getValue()) {
147                        //Log.d(TAG, "Profile still not running:" + entry.getKey());
148                        return;
149                    }
150                }
151            }
152            if (DBG) Log.d(TAG, "All profile services started.");
153            Message m = mHandler.obtainMessage(MESSAGE_ONSTARTED);
154            mHandler.sendMessage(m);
155        }
156    }
157
158    @Override
159    public void onCreate() {
160        super.onCreate();
161        if (DBG) Log.d(TAG, "onCreate");
162        mContext = this;
163        sAdapterService = this;
164        initJni(); //We always check and init JNI in case we crashed and restarted
165        mRemoteDevices = RemoteDevices.getInstance(this, mContext);
166        mRemoteDevices.init();
167        mAdapterProperties = AdapterProperties.getInstance(this, mContext);
168        mAdapterProperties.init();
169        mAdapterStateMachine =  new AdapterState(this, mContext, mAdapterProperties);
170        mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties);
171        mJniCallbacks = JniCallbacks.getInstance(mRemoteDevices, mAdapterProperties,
172                                                 mAdapterStateMachine, mBondStateMachine);
173        initNative();
174        mNativeAvailable=true;
175
176        //Load the name and address
177        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR);
178        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME);
179    }
180
181    @Override
182    public IBinder onBind(Intent intent) {
183        if (DBG) Log.d(TAG, "onBind");
184        return mBinder;
185    }
186    public boolean onUnbind(Intent intent) {
187        if (DBG) Log.d(TAG,"onUnbind");
188        return super.onUnbind(intent);
189    }
190
191    public void onDestroy() {
192        if (DBG) Log.d(TAG, "onDestroy()");
193        super.onDestroy();
194        if (mBondStateMachine != null) {
195            mBondStateMachine.cleanup();
196            mBondStateMachine = null;
197        }
198        if (mAdapterStateMachine != null) {
199            mAdapterStateMachine.cleanup();
200            mAdapterStateMachine = null;
201        }
202        if (mNativeAvailable) {
203            Log.d(TAG, "Cleaning up adapter native....");
204            cleanupNative();
205            Log.d(TAG, "Done cleaning up adapter native....");
206            mNativeAvailable=false;
207        }
208    }
209
210    public int onStartCommand(Intent intent ,int flags, int startId) {
211        if (DBG) Log.d(TAG, "onStartCommand");
212        if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
213            Log.e(TAG, "Permission denied!");
214            return START_STICKY;
215        }
216
217        String action  = intent.getStringExtra(EXTRA_ACTION);
218        if (DBG) Log.d(TAG,"onStartCommand(): action = " + action);
219        if (ACTION_SERVICE_STATE_CHANGED.equals(action)) {
220            int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR);
221            if (DBG) Log.d(TAG,"onStartCommand(): state = " + Utils.debugGetAdapterStateString(state));
222            if (state == BluetoothAdapter.STATE_OFF) {
223                stop();
224            } else if (state == BluetoothAdapter.STATE_ON) {
225                start();
226            }
227        }
228        return START_STICKY;
229    }
230
231    private void start() {
232        if (DBG) Log.d(TAG,"start() called");
233        if (mProfilesStarted || mStartPending) return;
234        if (DBG) Log.d(TAG,"starting bluetooth state machine and profiles..");
235        mStartPending=true;
236        mAdapterStateMachine.start();
237        mBondStateMachine.start();
238        //Start profile services
239        for (int i=0; i <SUPPORTED_PROFILE_SERVICES.length;i++) {
240            startProfileService(SUPPORTED_PROFILE_SERVICES[i]);
241        }
242    }
243
244    //Called as part of disable or independently (when just getting address)
245    private void stop() {
246        Log.d(TAG,"stop() called");
247        if (mStopPending) return;
248        mStopPending=true;
249        if (mProfilesStarted) {
250            //TODO: Start timeout
251            mProfilesStarted = false;
252
253            for (int i=SUPPORTED_PROFILE_SERVICES.length-1; i >=0;i--) {
254                stopProfileService(SUPPORTED_PROFILE_SERVICES[i]);
255            }
256        } else {
257            mStopPending=false;
258            finish();
259        }
260    }
261
262    private static final int MESSAGE_ONSTARTED=1;
263    private static final int MESSAGE_ONSTOPPED_STOPPENDING =2;
264    private final Handler mHandler = new Handler() {
265        @Override
266        public void handleMessage(Message msg) {
267            if (DBG) Log.d (TAG, "Message: " + msg.what);
268
269            switch (msg.what) {
270                case MESSAGE_ONSTARTED: {
271                    Log.d(TAG, "onStarted()");
272                    IntentFilter filter = new IntentFilter();
273                    filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
274                    registerForAirplaneMode(filter);
275                    registerReceiver(mReceiver, filter);
276                    mProfilesStarted = true;
277                    mStartPending = false;
278                }
279                break;
280
281                case MESSAGE_ONSTOPPED_STOPPENDING: {
282                    Log.d(TAG, "onStopped_StopPending() called");
283                    mStopPending=false;
284                    mBondStateMachine.quit();
285                    mAdapterStateMachine.quit();
286                    finish();
287                }
288                break;
289            }
290        }
291    };
292
293    /**
294     * Last step in the disable->stop->cleanup sequence
295     */
296    private void finish() {
297        stopSelf();
298    }
299
300    @SuppressWarnings("rawtypes")
301    private void startProfileService(Class service) {
302        String serviceName = service.getName();
303        Integer serviceState = mProfileServicesState.get(serviceName);
304        if(serviceState != null && serviceState != BluetoothAdapter.STATE_OFF) {
305            Log.w(TAG, "Unable to start service "+serviceName+". Invalid state: " + serviceState);
306            return;
307        }
308
309        mProfileServicesState.put(serviceName,BluetoothAdapter.STATE_TURNING_ON);
310        Intent i = new Intent(this,service);
311        i.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
312        i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
313        if (DBG) Log.d(TAG, "Starting profile service "+serviceName);
314        startService(i);
315    }
316
317    @SuppressWarnings("rawtypes")
318    private void stopProfileService(Class service) {
319        String serviceName = service.getName();
320        Integer serviceState = mProfileServicesState.get(service.getName());
321        if(serviceState == null || serviceState != BluetoothAdapter.STATE_ON) {
322            Log.w(TAG, "Unable to stop service " + serviceName + ". Invalid state: " + serviceState);
323            return;
324        }
325        mProfileServicesState.put(serviceName, BluetoothAdapter.STATE_TURNING_OFF);
326        Intent i = new Intent(this, service);
327        i.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
328        i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
329        if (DBG) Log.d(TAG, "Stopping profile service "+serviceName);
330        startService(i);
331    }
332
333    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
334        @Override
335        public void onReceive(Context context, Intent intent) {
336            if (intent == null) return;
337
338            String action = intent.getAction();
339            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
340                ContentResolver resolver = context.getContentResolver();
341                // Query the airplane mode from Settings.System just to make sure that
342                // some random app is not sending this intent and disabling bluetooth
343                if (isAirplaneModeOn()) {
344                    mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_ON);
345                } else {
346                    mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_OFF);
347                }
348            }
349        }
350    };
351
352    private void registerForAirplaneMode(IntentFilter filter) {
353        final ContentResolver resolver = mContext.getContentResolver();
354        final String airplaneModeRadios = Settings.System.getString(resolver,
355                Settings.System.AIRPLANE_MODE_RADIOS);
356        final String toggleableRadios = Settings.System.getString(resolver,
357                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
358
359        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
360                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
361        mIsAirplaneToggleable = toggleableRadios == null ? false :
362                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
363
364        if (mIsAirplaneSensitive) {
365            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
366        }
367    }
368
369    /* Returns true if airplane mode is currently on */
370    private final boolean isAirplaneModeOn() {
371        return Settings.System.getInt(mContext.getContentResolver(),
372                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
373    }
374    private boolean mPersistDisable;
375
376    /**
377     * Handlers for incoming service calls
378     */
379    private final IBluetooth.Stub mBinder = new IBluetooth.Stub() {
380        public boolean isEnabled() {
381            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
382            return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
383        }
384
385        public int getState() {
386            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
387            return mAdapterProperties.getState();
388        }
389
390        public boolean enable() {
391            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
392                    "Need BLUETOOTH ADMIN permission");
393            Log.d(TAG,"enable() called...");
394            Message m =
395                    mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
396            m.arg1 = 1; //persist state
397            mAdapterStateMachine.sendMessage(m);
398            return true;
399        }
400
401        public boolean disable(boolean persist) {
402            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
403                    "Need BLUETOOTH ADMIN permission");
404            unregisterReceiver(mReceiver);
405            int val = (persist ? 1 : 0);
406            Message m =
407                    mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
408            m.arg1 = val;
409            mAdapterStateMachine.sendMessage(m);
410            return true;
411        }
412
413        public String getAddress() {
414            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
415            String addrString = null;
416            byte[] address = mAdapterProperties.getAddress();
417            return Utils.getAddressStringFromByte(address);
418        }
419
420        public ParcelUuid[] getUuids() {
421            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
422            return mAdapterProperties.getUuids();
423        }
424
425        public String getName() {
426            enforceCallingOrSelfPermission(BLUETOOTH_PERM,
427                    "Need BLUETOOTH permission");
428            return mAdapterProperties.getName();
429        }
430
431        public boolean setName(String name) {
432            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
433                    "Need BLUETOOTH ADMIN permission");
434            return mAdapterProperties.setName(name);
435        }
436
437        public int getScanMode() {
438            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
439            return mAdapterProperties.getScanMode();
440        }
441
442        public boolean setScanMode(int mode, int duration) {
443            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
444            setDiscoverableTimeout(duration);
445
446            int newMode = convertScanModeToHal(mode);
447            return mAdapterProperties.setScanMode(newMode);
448        }
449
450        public int getDiscoverableTimeout() {
451            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
452            return mAdapterProperties.getDiscoverableTimeout();
453        }
454
455        public boolean setDiscoverableTimeout(int timeout) {
456            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
457            return mAdapterProperties.setDiscoverableTimeout(timeout);
458        }
459
460        public boolean startDiscovery() {
461            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
462                    "Need BLUETOOTH ADMIN permission");
463            return startDiscoveryNative();
464        }
465
466        public boolean cancelDiscovery() {
467            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
468                    "Need BLUETOOTH ADMIN permission");
469            return cancelDiscoveryNative();
470        }
471
472        public boolean isDiscovering() {
473            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
474            return mAdapterProperties.isDiscovering();
475        }
476
477        public BluetoothDevice[] getBondedDevices() {
478            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
479            debugLog("Get Bonded Devices being called");
480            return mAdapterProperties.getBondedDevices();
481        }
482
483        public int getAdapterConnectionState() {
484            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
485            return mAdapterProperties.getConnectionState();
486        }
487
488        public int getProfileConnectionState(int profile) {
489            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
490            return mAdapterProperties.getProfileConnectionState(profile);
491        }
492
493        public boolean createBond(BluetoothDevice device) {
494            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
495                "Need BLUETOOTH ADMIN permission");
496            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
497            if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
498                return false;
499            }
500
501            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
502            msg.obj = device;
503            mBondStateMachine.sendMessage(msg);
504            return true;
505        }
506
507        public boolean cancelBondProcess(BluetoothDevice device) {
508            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
509            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
510            return cancelBondNative(addr);
511        }
512
513        public boolean removeBond(BluetoothDevice device) {
514            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
515                "Need BLUETOOTH ADMIN permission");
516            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
517            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
518                return false;
519            }
520            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
521            msg.obj = device;
522            mBondStateMachine.sendMessage(msg);
523            return true;
524        }
525
526        public int getBondState(BluetoothDevice device) {
527            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
528            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
529            if (deviceProp == null) {
530                return BluetoothDevice.BOND_NONE;
531            }
532            return deviceProp.getBondState();
533        }
534
535        public String getRemoteName(BluetoothDevice device) {
536            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
537            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
538            if (deviceProp == null) return null;
539            return deviceProp.getName();
540        }
541
542        public String getRemoteAlias(BluetoothDevice device) {
543            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
544            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
545            if (deviceProp == null) return null;
546            return deviceProp.getAlias();
547        }
548
549        public boolean setRemoteAlias(BluetoothDevice device, String name) {
550            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
551            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
552            if (deviceProp == null) return false;
553            deviceProp.setAlias(name);
554            return true;
555        }
556
557        public int getRemoteClass(BluetoothDevice device) {
558            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
559            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
560            if (deviceProp == null) return 0;
561
562            return deviceProp.getBluetoothClass();
563        }
564
565        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
566            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
567            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
568            if (deviceProp == null) return null;
569            return deviceProp.getUuids();
570        }
571
572        public boolean fetchRemoteUuids(BluetoothDevice device) {
573            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
574            mRemoteDevices.fetchUuids(device);
575            return true;
576        }
577
578        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
579            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
580            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
581            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
582                return false;
583            }
584
585            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
586            return pinReplyNative(addr, accept, len, pinCode);
587        }
588
589        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
590            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
591            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
592            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
593                return false;
594            }
595
596            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
597            return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
598                    Utils.byteArrayToInt(passkey));
599        }
600
601        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
602            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
603            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
604            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
605                return false;
606            }
607
608            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
609            return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
610                    accept, 0);
611        }
612
613        public void sendConnectionStateChange(BluetoothDevice
614                device, int profile, int state, int prevState) {
615            // TODO(BT) permission check?
616            // Since this is a binder call check if Bluetooth is on still
617            if (getState() == BluetoothAdapter.STATE_OFF) return;
618
619            mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
620
621        }
622
623        public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
624                                                  ParcelUuid uuid, int port, int flag) {
625            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
626            int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()),
627                       type, Utils.uuidToByteArray(uuid), port, flag);
628            if (fd < 0) {
629                errorLog("Failed to connect socket");
630                return null;
631            }
632            return ParcelFileDescriptor.adoptFd(fd);
633        }
634
635        public ParcelFileDescriptor createSocketChannel(int type, String serviceName,
636                                                        ParcelUuid uuid, int port, int flag) {
637            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
638            int fd =  createSocketChannelNative(type, serviceName,
639                                     Utils.uuidToByteArray(uuid), port, flag);
640            if (fd < 0) {
641                errorLog("Failed to create socket channel");
642                return null;
643            }
644            return ParcelFileDescriptor.adoptFd(fd);
645        }
646    };
647
648    private int convertScanModeToHal(int mode) {
649        switch (mode) {
650            case BluetoothAdapter.SCAN_MODE_NONE:
651                return AbstractionLayer.BT_SCAN_MODE_NONE;
652            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
653                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
654            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
655                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
656        }
657        errorLog("Incorrect scan mode in convertScanModeToHal");
658        return -1;
659    }
660
661    int convertScanModeFromHal(int mode) {
662        switch (mode) {
663            case AbstractionLayer.BT_SCAN_MODE_NONE:
664                return BluetoothAdapter.SCAN_MODE_NONE;
665            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
666                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
667            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
668                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
669        }
670        errorLog("Incorrect scan mode in convertScanModeFromHal");
671        return -1;
672    }
673
674    private static void debugLog(String msg) {
675        Log.d(TAG, msg);
676    }
677
678    private static void errorLog(String msg) {
679        Log.e(TAG, msg);
680    }
681
682    void persistBluetoothSetting(boolean setOn) {
683        long origCallerIdentityToken = Binder.clearCallingIdentity();
684        Settings.Secure.putInt(mContext.getContentResolver(),
685                               Settings.Secure.BLUETOOTH_ON,
686                               setOn ? 1 : 0);
687        Binder.restoreCallingIdentity(origCallerIdentityToken);
688    }
689
690    boolean getBluetoothPersistedSetting() {
691        ContentResolver contentResolver = mContext.getContentResolver();
692        return (Settings.Secure.getInt(contentResolver,
693                                       Settings.Secure.BLUETOOTH_ON, 0) > 0);
694    }
695
696    private native static void classInitNative();
697    private native boolean initNative();
698    private native void cleanupNative();
699    /*package*/ native boolean enableNative();
700    /*package*/ native boolean disableNative();
701    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
702    /*package*/ native boolean getAdapterPropertiesNative();
703    /*package*/ native boolean getAdapterPropertyNative(int type);
704    /*package*/ native boolean setAdapterPropertyNative(int type);
705    /*package*/ native boolean
706        setDevicePropertyNative(byte[] address, int type, byte[] val);
707    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
708
709    /*package*/ native boolean createBondNative(byte[] address);
710    /*package*/ native boolean removeBondNative(byte[] address);
711    /*package*/ native boolean cancelBondNative(byte[] address);
712
713    private native boolean startDiscoveryNative();
714    private native boolean cancelDiscoveryNative();
715
716    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
717    private native boolean sspReplyNative(byte[] address, int type, boolean
718            accept, int passkey);
719
720    /*package*/ native boolean getRemoteServicesNative(byte[] address);
721
722    // TODO(BT) move this to ../btsock dir
723    private native int connectSocketNative(byte[] address, int type,
724                                           byte[] uuid, int port, int flag);
725    private native int createSocketChannelNative(int type, String serviceName,
726                                                 byte[] uuid, int port, int flag);
727}
728