AdapterService.java revision 31ba132491053bc86d419a7d51fc04af3299c076
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 static final int ADAPTER_SERVICE_TYPE=Service.START_STICKY;
78
79    static {
80        classInitNative();
81    }
82
83    private static AdapterService sAdapterService;
84    public static AdapterService getAdapterService(){
85        return sAdapterService;
86    }
87
88    private IBluetoothManager mBluetoothManager;
89    private IBluetooth mBluetoothService;
90    private AdapterProperties mAdapterProperties;
91    private int mAdapterState;
92    private Context mContext;
93
94    private AdapterState mAdapterStateMachine;
95    private BondStateMachine mBondStateMachine;
96    private JniCallbacks mJniCallbacks;
97    private RemoteDevices mRemoteDevices;
98    private boolean mProfilesStarted;
99    private boolean mNativeAvailable;
100    private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>();
101    private int mCurrentRequestId;
102
103    public void onProfileConnectionStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
104        Message m = mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED);
105        m.obj = device;
106        m.arg1 = profileId;
107        m.arg2 = newState;
108        Bundle b = new Bundle(1);
109        b.putInt("prevState", prevState);
110        m.setData(b);
111        mHandler.sendMessage(m);
112    }
113
114    private void processProfileStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
115        if (mBluetoothService != null) {
116            try {
117                mBluetoothService.sendConnectionStateChange(device, profileId, newState,
118                prevState);
119            } catch (RemoteException re) {
120                Log.e(TAG, "",re);
121            }
122        }
123    }
124
125    public void onProfileServiceStateChanged(String serviceName, int state) {
126        Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
127        m.obj=serviceName;
128        m.arg1 = state;
129        mHandler.sendMessage(m);
130    }
131
132    private void processProfileServiceStateChanged(String serviceName, int state) {
133        boolean doUpdate=false;
134        boolean isTurningOn;
135        boolean isTurningOff;
136
137        synchronized (mProfileServicesState) {
138            Integer prevState = mProfileServicesState.get(serviceName);
139            if (prevState != null && prevState != state) {
140                mProfileServicesState.put(serviceName,state);
141                doUpdate=true;
142            }
143        }
144        if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state +", doUpdate = " + doUpdate);
145
146        if (!doUpdate) {
147            return;
148        }
149
150        synchronized (mAdapterStateMachine) {
151            isTurningOff = mAdapterStateMachine.isTurningOff();
152            isTurningOn = mAdapterStateMachine.isTurningOn();
153        }
154
155        if (isTurningOff) {
156            //Process stop or disable pending
157            //Check if all services are stopped if so, do cleanup
158            //if (DBG) Log.d(TAG,"Checking if all profiles are stopped...");
159            synchronized (mProfileServicesState) {
160                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
161                while (i.hasNext()) {
162                    Map.Entry<String,Integer> entry = i.next();
163                    if (BluetoothAdapter.STATE_OFF != entry.getValue()) {
164                        Log.d(TAG, "Profile still running: " + entry.getKey());
165                        return;
166                    }
167                }
168            }
169            if (DBG) Log.d(TAG, "All profile services stopped...");
170            onProfilesStopped();
171        } else if (isTurningOn) {
172            //Process start pending
173            //Check if all services are started if so, update state
174            //if (DBG) Log.d(TAG,"Checking if all profiles are running...");
175            synchronized (mProfileServicesState) {
176                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
177                while (i.hasNext()) {
178                    Map.Entry<String,Integer> entry = i.next();
179                    if (BluetoothAdapter.STATE_ON != entry.getValue()) {
180                        Log.d(TAG, "Profile still not running:" + entry.getKey());
181                        return;
182                    }
183                }
184            }
185            if (DBG) Log.d(TAG, "All profile services started.");
186            onProfilesStarted();
187        }
188    }
189
190    @Override
191    public void onCreate() {
192        super.onCreate();
193        if (DBG) debugLog("onCreate");
194        mContext = this;
195        sAdapterService = this;
196        mAdapterProperties = new AdapterProperties(this, mContext);
197        mAdapterStateMachine =  new AdapterState(this, mContext, mAdapterProperties);
198        mJniCallbacks = JniCallbacks.getInstance(null, mAdapterProperties,mAdapterStateMachine,null);
199        initNative();
200        mNativeAvailable=true;
201        mAdapterStateMachine.start();
202
203        //Load the name and address
204        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR);
205        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME);
206    }
207
208    @Override
209    public IBinder onBind(Intent intent) {
210        if (DBG) debugLog("onBind");
211        return mBinder;
212    }
213    public boolean onUnbind(Intent intent) {
214        if (DBG) debugLog("onUnbind");
215        return super.onUnbind(intent);
216    }
217
218    public void onDestroy() {
219        debugLog("****onDestroy()********");
220        mHandler.removeMessages(MESSAGE_SHUTDOWN);
221        cleanup();
222    }
223
224    public int onStartCommand(Intent intent ,int flags, int startId) {
225
226        mCurrentRequestId = startId;
227        if (DBG) debugLog("onStartCommand: flags = " + flags + ", startId = " + startId);
228        if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
229            Log.e(TAG, "Permission denied!");
230            return ADAPTER_SERVICE_TYPE;
231        }
232
233        //Check if we are restarting
234        if (intent == null) {
235            debugLog("Restarting AdapterService");
236            return ADAPTER_SERVICE_TYPE;
237        }
238
239        //Get action and check if valid. If invalid, ignore and return
240        String action  = intent.getStringExtra(EXTRA_ACTION);
241        debugLog("onStartCommand(): action = " + action);
242        if (!ACTION_SERVICE_STATE_CHANGED.equals(action)) {
243            Log.w(TAG,"Unknown action: " + action);
244            return ADAPTER_SERVICE_TYPE;
245        }
246
247        //Check state of request. If invalid, ignore and return
248        int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR);
249        debugLog("onStartCommand(): state = " + Utils.debugGetAdapterStateString(state));
250
251        //Cancel any pending shutdown requests
252        synchronized (mHandler) {
253            mHandler.removeMessages(MESSAGE_SHUTDOWN);
254        }
255
256        if (state == BluetoothAdapter.STATE_OFF) {
257            Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
258            m.arg1= startId;
259            mAdapterStateMachine.sendMessage(m);
260        } else if (state == BluetoothAdapter.STATE_ON) {
261            Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
262            m.arg1= startId;
263            mAdapterStateMachine.sendMessage(m);
264        } else {
265            Log.w(TAG,"Invalid state: " + action);
266            return ADAPTER_SERVICE_TYPE;
267        }
268        return ADAPTER_SERVICE_TYPE;
269    }
270
271    void processStart() {
272        if (DBG) debugLog("processStart()");
273
274        //Initialize data objects
275        for (int i=0; i < SUPPORTED_PROFILE_SERVICES.length;i++) {
276            mProfileServicesState.put(SUPPORTED_PROFILE_SERVICES[i].getName(),BluetoothAdapter.STATE_OFF);
277        }
278
279        mRemoteDevices = new RemoteDevices(this, mContext);
280        mRemoteDevices.init();
281        mAdapterProperties.init(mRemoteDevices);
282        mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties, mRemoteDevices);
283        mJniCallbacks.init(mRemoteDevices, mAdapterProperties,mAdapterStateMachine,mBondStateMachine);
284
285        //Init BluetoothManager
286        if (DBG) {debugLog("processStart(): Initializing Bluetooth Manager");}
287        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
288        if (b != null) {
289            mBluetoothManager = IBluetoothManager.Stub.asInterface(b);
290            if (mBluetoothManager != null) {
291                try {
292                    Log.d(TAG, "FRED: Registering manager callback " + mManagerCallback);
293                    mBluetoothService = mBluetoothManager.registerAdapter(mManagerCallback);
294                } catch (RemoteException re) {
295                    Log.e(TAG, "",re);
296                }
297            }
298        }
299
300        //Start Bond State Machine
301        if (DBG) {debugLog("processStart(): Starting Bond State Machine");}
302        mBondStateMachine.start();
303
304        //Start profile services
305        if (SUPPORTED_PROFILE_SERVICES.length==0 || mProfilesStarted) {
306            //Skip starting profiles and go to next step
307            if (DBG) {debugLog("processStart(): Profile Services started");}
308            Message m = mAdapterStateMachine.obtainMessage(AdapterState.STARTED);
309            mAdapterStateMachine.sendMessage(m);
310        } else {
311            //Startup all profile services
312            setProfileServiceState(SUPPORTED_PROFILE_SERVICES,BluetoothAdapter.STATE_ON);
313        }
314    }
315
316    void startBluetoothDisable() {
317        Log.d(TAG,"startBluetoothDisable()");
318        Message m = mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE);
319        mAdapterStateMachine.sendMessage(m);
320    }
321
322    void onProfilesStarted(){
323        Log.d(TAG,"onProfilesStarted()");
324        mProfilesStarted=true;
325        Message m = mAdapterStateMachine.obtainMessage(AdapterState.STARTED);
326        mAdapterStateMachine.sendMessage(m);
327    }
328
329    void onProfilesStopped() {
330        Log.d(TAG,"onProfilesStopped()");
331        mProfilesStarted=false;
332        //Message m = mAdapterStateMachine.obtainMessage(AdapterState.DISABLE);
333        Message m = mAdapterStateMachine.obtainMessage(AdapterState.STOPPED);
334        mAdapterStateMachine.sendMessage(m);
335    }
336
337
338    boolean stopProfileServices() {
339        if (SUPPORTED_PROFILE_SERVICES.length==0 || !mProfilesStarted) {
340            if (DBG) {debugLog("processDisable(): No profiles services to stop or already stopped.");}
341            return false;
342        }
343        setProfileServiceState(SUPPORTED_PROFILE_SERVICES,BluetoothAdapter.STATE_OFF);
344        return true;
345    }
346
347    void processStopped() {
348        Log.d(TAG, "processStopped()");
349
350        if (mBluetoothManager != null) {
351            try {
352                Log.d(TAG,"FRED: Unregistering manager callback " + mManagerCallback);
353                mBluetoothManager.unregisterAdapter(mManagerCallback);
354            } catch (RemoteException re) {
355                Log.e(TAG, "",re);
356            }
357        }
358        mBondStateMachine.quit();
359        mBondStateMachine.cleanup();
360        mBondStateMachine = null;
361    }
362
363    void startShutdown(int requestId) {
364        debugLog("startShutdown(): requestId = " + requestId + ", currentRequestId=" + mCurrentRequestId);
365        if (requestId <0) {
366            Log.w(TAG, "Ignoring shutdown request. Invalid requestId");
367            return;
368        }
369
370        Message m = mHandler.obtainMessage(MESSAGE_SHUTDOWN);
371        synchronized(mHandler) {
372            mHandler.sendMessageDelayed(m, SHUTDOWN_TIMEOUT);
373        }
374        stopSelfResult(requestId);
375    }
376
377    void cleanup () {
378        if (DBG)debugLog("cleanup()");
379
380        if (mNativeAvailable) {
381            Log.d(TAG, "Cleaning up adapter native....");
382            cleanupNative();
383            Log.d(TAG, "Done cleaning up adapter native....");
384            mNativeAvailable=false;
385        }
386
387        if (mAdapterStateMachine != null) {
388            mAdapterStateMachine.quit();
389            mAdapterStateMachine.cleanup();
390            mAdapterStateMachine = null;
391        }
392
393        if (mRemoteDevices != null) {
394            mRemoteDevices.cleanup();
395            mRemoteDevices = null;
396        }
397
398        if (mAdapterProperties != null) {
399            mAdapterProperties.cleanup();
400            mAdapterProperties = null;
401        }
402
403        mProfileServicesState.clear();
404        if (DBG)debugLog("cleanup() done");
405    }
406
407    final private IBluetoothManagerCallback mManagerCallback =
408            new IBluetoothManagerCallback.Stub() {
409                public void onBluetoothServiceUp(IBluetooth bluetoothService) {
410                    if (DBG) Log.d(TAG, "onBluetoothServiceUp");
411                    synchronized (mManagerCallback) {
412                        mBluetoothService = bluetoothService;
413                    }
414                }
415
416                public void onBluetoothServiceDown() {
417                    if (DBG) Log.d(TAG, "onBluetoothServiceDown " + this);
418                    synchronized (mManagerCallback) {
419                        mBluetoothService = null;
420                    }
421                }
422        };
423
424    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
425    private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
426    private static final int MESSAGE_SHUTDOWN= 100;
427    private static final int SHUTDOWN_TIMEOUT=2000;
428
429    private final Handler mHandler = new Handler() {
430        @Override
431        public void handleMessage(Message msg) {
432            if (DBG) debugLog("Message: " + msg.what);
433
434            switch (msg.what) {
435                case MESSAGE_SHUTDOWN: {
436                    if (DBG) Log.d(TAG,"***SHUTDOWN: TIMEOUT!!! Forcing shutdown...");
437                    stopSelf();
438                }
439                    break;
440                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
441                    if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
442                    processProfileServiceStateChanged((String) msg.obj, msg.arg1);
443                }
444                    break;
445                case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: {
446                    if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
447                    processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
448                }
449                    break;
450            }
451        }
452    };
453
454    @SuppressWarnings("rawtypes")
455    private void setProfileServiceState(Class[] services, int state) {
456        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
457            Log.w(TAG,"setProfileServiceState(): invalid state...Leaving...");
458            return;
459        }
460
461        int expectedCurrentState= BluetoothAdapter.STATE_OFF;
462        int pendingState = BluetoothAdapter.STATE_TURNING_ON;
463        if (state == BluetoothAdapter.STATE_OFF) {
464            expectedCurrentState= BluetoothAdapter.STATE_ON;
465            pendingState = BluetoothAdapter.STATE_TURNING_OFF;
466        }
467
468        for (int i=0; i <services.length;i++) {
469            String serviceName = services[i].getName();
470            Integer serviceState = mProfileServicesState.get(serviceName);
471            if(serviceState != null && serviceState != expectedCurrentState) {
472                Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " +
473                        serviceName+". Invalid state: " + serviceState);
474                continue;
475            }
476
477            if (DBG) {
478                Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
479                        serviceName);
480            }
481
482            mProfileServicesState.put(serviceName,pendingState);
483            Intent intent = new Intent(this,services[i]);
484            intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
485            intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
486            startService(intent);
487        }
488    }
489
490    /**
491     * Handlers for incoming service calls
492     */
493    private final IBluetooth.Stub mBinder = new IBluetooth.Stub() {
494        public boolean isEnabled() {
495            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
496            return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
497        }
498
499        public int getState() {
500            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
501            debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
502            return mAdapterProperties.getState();
503        }
504
505        public boolean enable() {
506            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
507                    "Need BLUETOOTH ADMIN permission");
508            if (DBG) debugLog("enable() called...");
509            Message m =
510                    mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
511            m.arg1 = 1; //persist state
512            mAdapterStateMachine.sendMessage(m);
513            return true;
514        }
515
516        public boolean disable(boolean persist) {
517            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
518                    "Need BLUETOOTH ADMIN permission");
519            if (DBG) debugLog("disable() called...");
520            int val = (persist ? 1 : 0);
521            Message m =
522                    mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
523            m.arg1 = val;
524            mAdapterStateMachine.sendMessage(m);
525            return true;
526        }
527
528        public String getAddress() {
529            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
530            String addrString = null;
531            byte[] address = mAdapterProperties.getAddress();
532            return Utils.getAddressStringFromByte(address);
533        }
534
535        public ParcelUuid[] getUuids() {
536            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
537            return mAdapterProperties.getUuids();
538        }
539
540        public String getName() {
541            enforceCallingOrSelfPermission(BLUETOOTH_PERM,
542                    "Need BLUETOOTH permission");
543            try {
544                return mAdapterProperties.getName();
545            } catch (Throwable t) {
546                Log.d(TAG, "Unexpected exception while calling getName()",t);
547            }
548            return null;
549        }
550
551        public boolean setName(String name) {
552            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
553                    "Need BLUETOOTH ADMIN permission");
554            return mAdapterProperties.setName(name);
555        }
556
557        public int getScanMode() {
558            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
559            return mAdapterProperties.getScanMode();
560        }
561
562        public boolean setScanMode(int mode, int duration) {
563            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
564            setDiscoverableTimeout(duration);
565
566            int newMode = convertScanModeToHal(mode);
567            return mAdapterProperties.setScanMode(newMode);
568        }
569
570        public int getDiscoverableTimeout() {
571            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
572            return mAdapterProperties.getDiscoverableTimeout();
573        }
574
575        public boolean setDiscoverableTimeout(int timeout) {
576            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
577            return mAdapterProperties.setDiscoverableTimeout(timeout);
578        }
579
580        public boolean startDiscovery() {
581            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
582                    "Need BLUETOOTH ADMIN permission");
583            return startDiscoveryNative();
584        }
585
586        public boolean cancelDiscovery() {
587            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
588                    "Need BLUETOOTH ADMIN permission");
589            return cancelDiscoveryNative();
590        }
591
592        public boolean isDiscovering() {
593            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
594            return mAdapterProperties.isDiscovering();
595        }
596
597        public BluetoothDevice[] getBondedDevices() {
598            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
599            debugLog("Get Bonded Devices being called");
600            return mAdapterProperties.getBondedDevices();
601        }
602
603        public int getAdapterConnectionState() {
604            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
605            return mAdapterProperties.getConnectionState();
606        }
607
608        public int getProfileConnectionState(int profile) {
609            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
610            return mAdapterProperties.getProfileConnectionState(profile);
611        }
612
613        public boolean createBond(BluetoothDevice device) {
614            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
615                "Need BLUETOOTH ADMIN permission");
616            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
617            if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
618                return false;
619            }
620
621            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
622            msg.obj = device;
623            mBondStateMachine.sendMessage(msg);
624            return true;
625        }
626
627        public boolean cancelBondProcess(BluetoothDevice device) {
628            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
629            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
630            return cancelBondNative(addr);
631        }
632
633        public boolean removeBond(BluetoothDevice device) {
634            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
635                "Need BLUETOOTH ADMIN permission");
636            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
637            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
638                return false;
639            }
640            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
641            msg.obj = device;
642            mBondStateMachine.sendMessage(msg);
643            return true;
644        }
645
646        public int getBondState(BluetoothDevice device) {
647            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
648            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
649            if (deviceProp == null) {
650                return BluetoothDevice.BOND_NONE;
651            }
652            return deviceProp.getBondState();
653        }
654
655        public String getRemoteName(BluetoothDevice device) {
656            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
657            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
658            if (deviceProp == null) return null;
659            return deviceProp.getName();
660        }
661
662        public String getRemoteAlias(BluetoothDevice device) {
663            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
664            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
665            if (deviceProp == null) return null;
666            return deviceProp.getAlias();
667        }
668
669        public boolean setRemoteAlias(BluetoothDevice device, String name) {
670            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
671            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
672            if (deviceProp == null) return false;
673            deviceProp.setAlias(name);
674            return true;
675        }
676
677        public int getRemoteClass(BluetoothDevice device) {
678            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
679            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
680            if (deviceProp == null) return 0;
681
682            return deviceProp.getBluetoothClass();
683        }
684
685        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
686            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
687            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
688            if (deviceProp == null) return null;
689            return deviceProp.getUuids();
690        }
691
692        public boolean fetchRemoteUuids(BluetoothDevice device) {
693            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
694            mRemoteDevices.fetchUuids(device);
695            return true;
696        }
697
698        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
699            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
700            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
701            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
702                return false;
703            }
704
705            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
706            return pinReplyNative(addr, accept, len, pinCode);
707        }
708
709        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
710            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
711            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
712            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
713                return false;
714            }
715
716            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
717            return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
718                    Utils.byteArrayToInt(passkey));
719        }
720
721        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
722            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
723            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
724            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
725                return false;
726            }
727
728            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
729            return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
730                    accept, 0);
731        }
732
733        public void sendConnectionStateChange(BluetoothDevice
734                device, int profile, int state, int prevState) {
735            // TODO(BT) permission check?
736            // Since this is a binder call check if Bluetooth is on still
737            if (getState() == BluetoothAdapter.STATE_OFF) return;
738
739            mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
740
741        }
742
743        public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
744                                                  ParcelUuid uuid, int port, int flag) {
745            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
746            int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()),
747                       type, Utils.uuidToByteArray(uuid), port, flag);
748            if (fd < 0) {
749                errorLog("Failed to connect socket");
750                return null;
751            }
752            return ParcelFileDescriptor.adoptFd(fd);
753        }
754
755        public ParcelFileDescriptor createSocketChannel(int type, String serviceName,
756                                                        ParcelUuid uuid, int port, int flag) {
757            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
758            int fd =  createSocketChannelNative(type, serviceName,
759                                     Utils.uuidToByteArray(uuid), port, flag);
760            if (fd < 0) {
761                errorLog("Failed to create socket channel");
762                return null;
763            }
764            return ParcelFileDescriptor.adoptFd(fd);
765        }
766    };
767
768    private int convertScanModeToHal(int mode) {
769        switch (mode) {
770            case BluetoothAdapter.SCAN_MODE_NONE:
771                return AbstractionLayer.BT_SCAN_MODE_NONE;
772            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
773                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
774            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
775                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
776        }
777        errorLog("Incorrect scan mode in convertScanModeToHal");
778        return -1;
779    }
780
781    int convertScanModeFromHal(int mode) {
782        switch (mode) {
783            case AbstractionLayer.BT_SCAN_MODE_NONE:
784                return BluetoothAdapter.SCAN_MODE_NONE;
785            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
786                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
787            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
788                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
789        }
790        errorLog("Incorrect scan mode in convertScanModeFromHal");
791        return -1;
792    }
793
794    private void debugLog(String msg) {
795        Log.d(TAG +"(" +hashCode()+")", msg);
796    }
797
798    private void errorLog(String msg) {
799        Log.e(TAG +"(" +hashCode()+")", msg);
800    }
801
802    private native static void classInitNative();
803    private native boolean initNative();
804    private native void cleanupNative();
805    /*package*/ native boolean enableNative();
806    /*package*/ native boolean disableNative();
807    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
808    /*package*/ native boolean getAdapterPropertiesNative();
809    /*package*/ native boolean getAdapterPropertyNative(int type);
810    /*package*/ native boolean setAdapterPropertyNative(int type);
811    /*package*/ native boolean
812        setDevicePropertyNative(byte[] address, int type, byte[] val);
813    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
814
815    /*package*/ native boolean createBondNative(byte[] address);
816    /*package*/ native boolean removeBondNative(byte[] address);
817    /*package*/ native boolean cancelBondNative(byte[] address);
818
819    private native boolean startDiscoveryNative();
820    private native boolean cancelDiscoveryNative();
821
822    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
823    private native boolean sspReplyNative(byte[] address, int type, boolean
824            accept, int passkey);
825
826    /*package*/ native boolean getRemoteServicesNative(byte[] address);
827
828    // TODO(BT) move this to ../btsock dir
829    private native int connectSocketNative(byte[] address, int type,
830                                           byte[] uuid, int port, int flag);
831    private native int createSocketChannelNative(int type, String serviceName,
832                                                 byte[] uuid, int port, int flag);
833}
834