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