AdapterService.java revision bd704c741b8c523ad747214f6f0520ac3e2caf8f
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.IBluetoothCallback;
18import android.bluetooth.IBluetoothManager;
19import android.bluetooth.IBluetoothManagerCallback;
20import android.content.BroadcastReceiver;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.os.Binder;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Message;
30import android.os.ParcelFileDescriptor;
31import android.os.ParcelUuid;
32import android.os.Process;
33import android.os.RemoteCallbackList;
34import android.os.RemoteException;
35import android.provider.Settings;
36import android.util.Log;
37import android.util.Pair;
38import com.android.bluetooth.a2dp.A2dpService;
39import com.android.bluetooth.hid.HidService;
40import com.android.bluetooth.hfp.HeadsetService;
41import com.android.bluetooth.hdp.HealthService;
42import com.android.bluetooth.pan.PanService;
43import com.android.bluetooth.R;
44import com.android.bluetooth.Utils;
45import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
46import java.io.FileDescriptor;
47import java.io.IOException;
48import java.util.ArrayList;
49import java.util.HashMap;
50import java.util.Set;
51import java.util.Map;
52import java.util.Iterator;
53import java.util.Map.Entry;
54import java.util.List;
55import android.content.pm.PackageManager;
56import android.os.ServiceManager;
57
58public class AdapterService extends Service {
59    private static final String TAG = "BluetoothAdapterService";
60    private static final boolean DBG = false;
61    private static final boolean TRACE_REF = true;
62    //For Debugging only
63    private static int sRefCount=0;
64
65    public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
66    public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
67    public static final String EXTRA_ACTION="action";
68    public static final int PROFILE_CONN_CONNECTED  = 1;
69    public static final int PROFILE_CONN_REJECTED  = 2;
70
71    static final String BLUETOOTH_ADMIN_PERM =
72        android.Manifest.permission.BLUETOOTH_ADMIN;
73    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
74
75    private static final int ADAPTER_SERVICE_TYPE=Service.START_STICKY;
76
77    static {
78        classInitNative();
79    }
80
81    private static AdapterService sAdapterService;
82    public static synchronized AdapterService getAdapterService(){
83        if (sAdapterService != null && !sAdapterService.mCleaningUp) {
84            if (DBG) Log.d(TAG, "getAdapterService(): returning " + sAdapterService);
85            return sAdapterService;
86        }
87        if (DBG)  {
88            if (sAdapterService == null) {
89                Log.d(TAG, "getAdapterService(): service not available");
90            } else if (sAdapterService.mCleaningUp) {
91                Log.d(TAG,"getAdapterService(): service is cleaning up");
92            }
93        }
94        return null;
95    }
96
97    private static synchronized void setAdapterService(AdapterService instance) {
98        if (instance != null && !instance.mCleaningUp) {
99            if (DBG) Log.d(TAG, "setAdapterService(): set to: " + sAdapterService);
100            sAdapterService = instance;
101        } else {
102            if (DBG)  {
103                if (sAdapterService == null) {
104                    Log.d(TAG, "setAdapterService(): service not available");
105                } else if (sAdapterService.mCleaningUp) {
106                    Log.d(TAG,"setAdapterService(): service is cleaning up");
107                }
108            }
109        }
110    }
111
112    private static synchronized void clearAdapterService() {
113        sAdapterService = null;
114    }
115
116    private AdapterProperties mAdapterProperties;
117    private AdapterState mAdapterStateMachine;
118    private BondStateMachine mBondStateMachine;
119    private JniCallbacks mJniCallbacks;
120    private RemoteDevices mRemoteDevices;
121    private boolean mProfilesStarted;
122    private boolean mNativeAvailable;
123    private boolean mCleaningUp;
124    private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>();
125    private RemoteCallbackList<IBluetoothCallback> mCallbacks;//Only BluetoothManagerService should be registered
126    private int mCurrentRequestId;
127    private boolean mQuietmode = false;
128
129    public AdapterService() {
130        super();
131        if (TRACE_REF) {
132            synchronized (AdapterService.class) {
133                sRefCount++;
134                Log.d(TAG, "REFCOUNT: CREATED. INSTANCE_COUNT" + sRefCount);
135            }
136        }
137    }
138
139    public void onProfileConnectionStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
140        Message m = mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED);
141        m.obj = device;
142        m.arg1 = profileId;
143        m.arg2 = newState;
144        Bundle b = new Bundle(1);
145        b.putInt("prevState", prevState);
146        m.setData(b);
147        mHandler.sendMessage(m);
148    }
149
150    private void processProfileStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
151        if (((profileId == BluetoothProfile.A2DP) ||(profileId == BluetoothProfile.HEADSET)) &&
152            (newState == BluetoothProfile.STATE_CONNECTED)){
153            if (DBG) debugLog( "Profile connected. Schedule missing profile connection if any");
154            connectOtherProfile(device, PROFILE_CONN_CONNECTED);
155            setProfileAutoConnectionPriority(device, profileId);
156        }
157        IBluetooth.Stub binder = mBinder;
158        if (binder != null) {
159            try {
160                binder.sendConnectionStateChange(device, profileId, newState,prevState);
161            } catch (RemoteException re) {
162                Log.e(TAG, "",re);
163            }
164        }
165    }
166
167    public void onProfileServiceStateChanged(String serviceName, int state) {
168        Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
169        m.obj=serviceName;
170        m.arg1 = state;
171        mHandler.sendMessage(m);
172    }
173
174    private void processProfileServiceStateChanged(String serviceName, int state) {
175        boolean doUpdate=false;
176        boolean isTurningOn;
177        boolean isTurningOff;
178
179        synchronized (mProfileServicesState) {
180            Integer prevState = mProfileServicesState.get(serviceName);
181            if (prevState != null && prevState != state) {
182                mProfileServicesState.put(serviceName,state);
183                doUpdate=true;
184            }
185        }
186        if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state +", doUpdate = " + doUpdate);
187
188        if (!doUpdate) {
189            return;
190        }
191
192        synchronized (mAdapterStateMachine) {
193            isTurningOff = mAdapterStateMachine.isTurningOff();
194            isTurningOn = mAdapterStateMachine.isTurningOn();
195        }
196
197        if (isTurningOff) {
198            //Process stop or disable pending
199            //Check if all services are stopped if so, do cleanup
200            //if (DBG) Log.d(TAG,"Checking if all profiles are stopped...");
201            synchronized (mProfileServicesState) {
202                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
203                while (i.hasNext()) {
204                    Map.Entry<String,Integer> entry = i.next();
205                    if (BluetoothAdapter.STATE_OFF != entry.getValue()) {
206                        Log.d(TAG, "Profile still running: " + entry.getKey());
207                        return;
208                    }
209                }
210            }
211            if (DBG) Log.d(TAG, "All profile services stopped...");
212            //Send message to state machine
213            mProfilesStarted=false;
214            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STOPPED));
215        } else if (isTurningOn) {
216            //Process start pending
217            //Check if all services are started if so, update state
218            //if (DBG) Log.d(TAG,"Checking if all profiles are running...");
219            synchronized (mProfileServicesState) {
220                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
221                while (i.hasNext()) {
222                    Map.Entry<String,Integer> entry = i.next();
223                    if (BluetoothAdapter.STATE_ON != entry.getValue()) {
224                        Log.d(TAG, "Profile still not running:" + entry.getKey());
225                        return;
226                    }
227                }
228            }
229            if (DBG) Log.d(TAG, "All profile services started.");
230            mProfilesStarted=true;
231            //Send message to state machine
232            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
233        }
234    }
235
236    @Override
237    public void onCreate() {
238        super.onCreate();
239        if (DBG) debugLog("onCreate");
240        mBinder = new AdapterServiceBinder(this);
241        mAdapterProperties = new AdapterProperties(this);
242        mAdapterStateMachine =  AdapterState.make(this, mAdapterProperties);
243        mJniCallbacks =  new JniCallbacks(mAdapterStateMachine, mAdapterProperties);
244        initNative();
245        mNativeAvailable=true;
246        mCallbacks = new RemoteCallbackList<IBluetoothCallback>();
247        //Load the name and address
248        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR);
249        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME);
250
251    }
252
253    @Override
254    public IBinder onBind(Intent intent) {
255        if (DBG) debugLog("onBind");
256        return mBinder;
257    }
258    public boolean onUnbind(Intent intent) {
259        if (DBG) debugLog("onUnbind, calling cleanup");
260        cleanup();
261        return super.onUnbind(intent);
262    }
263
264    public void onDestroy() {
265        debugLog("****onDestroy()********");
266    }
267
268    void processStart() {
269        if (DBG) debugLog("processStart()");
270        Class[] supportedProfileServices = Config.getSupportedProfiles();
271        //Initialize data objects
272        for (int i=0; i < supportedProfileServices.length;i++) {
273            mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);
274        }
275        mRemoteDevices = new RemoteDevices(this);
276        mAdapterProperties.init(mRemoteDevices);
277
278        if (DBG) {debugLog("processStart(): Make Bond State Machine");}
279        mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);
280
281        mJniCallbacks.init(mBondStateMachine,mRemoteDevices);
282
283        //FIXME: Set static instance here???
284        setAdapterService(this);
285
286        //Start profile services
287        if (!mProfilesStarted && supportedProfileServices.length >0) {
288            //Startup all profile services
289            setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
290        }else {
291            if (DBG) {debugLog("processStart(): Profile Services alreay started");}
292            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
293        }
294    }
295
296    void startBluetoothDisable() {
297        mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE));
298    }
299
300    boolean stopProfileServices() {
301        Class[] supportedProfileServices = Config.getSupportedProfiles();
302        if (mProfilesStarted && supportedProfileServices.length>0) {
303            setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_OFF);
304            return true;
305        } else {
306            if (DBG) {debugLog("stopProfileServices(): No profiles services to stop or already stopped.");}
307            return false;
308        }
309    }
310
311     void updateAdapterState(int prevState, int newState){
312        if (mCallbacks !=null) {
313            int n=mCallbacks.beginBroadcast();
314            Log.d(TAG,"Broadcasting updateAdapterState() to " + n + " receivers.");
315            for (int i=0; i <n;i++) {
316                try {
317                    mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState);
318                }  catch (RemoteException e) {
319                    Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
320                }
321            }
322            mCallbacks.finishBroadcast();
323        }
324    }
325
326    void cleanup () {
327        if (DBG)debugLog("cleanup()");
328        if (mCleaningUp) {
329            Log.w(TAG,"*************service already starting to cleanup... Ignoring cleanup request.........");
330            return;
331        }
332
333        mCleaningUp = true;
334
335        if (mAdapterStateMachine != null) {
336            mAdapterStateMachine.doQuit();
337            mAdapterStateMachine.cleanup();
338        }
339
340        if (mBondStateMachine != null) {
341            mBondStateMachine.doQuit();
342            mBondStateMachine.cleanup();
343        }
344
345        if (mRemoteDevices != null) {
346            mRemoteDevices.cleanup();
347        }
348
349        if (mNativeAvailable) {
350            Log.d(TAG, "Cleaning up adapter native....");
351            cleanupNative();
352            Log.d(TAG, "Done cleaning up adapter native....");
353            mNativeAvailable=false;
354        }
355
356        if (mAdapterProperties != null) {
357            mAdapterProperties.cleanup();
358        }
359
360        if (mJniCallbacks != null) {
361            mJniCallbacks.cleanup();
362        }
363
364        if (mProfileServicesState != null) {
365            mProfileServicesState.clear();
366        }
367
368        clearAdapterService();
369
370        if (mBinder != null) {
371            mBinder.cleanup();
372            mBinder = null;  //Do not remove. Otherwise Binder leak!
373        }
374
375        if (mCallbacks !=null) {
376            mCallbacks.kill();
377        }
378
379        if (DBG)debugLog("cleanup() done");
380    }
381
382    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
383    private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
384    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 30;
385    private static final int CONNECT_OTHER_PROFILES_TIMEOUT= 6000;
386
387    private final Handler mHandler = new Handler() {
388        @Override
389        public void handleMessage(Message msg) {
390            if (DBG) debugLog("Message: " + msg.what);
391
392            switch (msg.what) {
393                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
394                    if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
395                    processProfileServiceStateChanged((String) msg.obj, msg.arg1);
396                }
397                    break;
398                case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: {
399                    if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
400                    processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
401                }
402                    break;
403                case MESSAGE_CONNECT_OTHER_PROFILES: {
404                    if (DBG) debugLog( "MESSAGE_CONNECT_OTHER_PROFILES");
405                    processConnectOtherProfiles((BluetoothDevice) msg.obj,msg.arg1);
406                }
407                    break;
408            }
409        }
410    };
411
412    @SuppressWarnings("rawtypes")
413    private void setProfileServiceState(Class[] services, int state) {
414        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
415            Log.w(TAG,"setProfileServiceState(): invalid state...Leaving...");
416            return;
417        }
418
419        int expectedCurrentState= BluetoothAdapter.STATE_OFF;
420        int pendingState = BluetoothAdapter.STATE_TURNING_ON;
421        if (state == BluetoothAdapter.STATE_OFF) {
422            expectedCurrentState= BluetoothAdapter.STATE_ON;
423            pendingState = BluetoothAdapter.STATE_TURNING_OFF;
424        }
425
426        for (int i=0; i <services.length;i++) {
427            String serviceName = services[i].getName();
428            Integer serviceState = mProfileServicesState.get(serviceName);
429            if(serviceState != null && serviceState != expectedCurrentState) {
430                Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " +
431                        serviceName+". Invalid state: " + serviceState);
432                continue;
433            }
434
435            if (DBG) {
436                Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
437                        serviceName);
438            }
439
440            mProfileServicesState.put(serviceName,pendingState);
441            Intent intent = new Intent(this,services[i]);
442            intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
443            intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
444            startService(intent);
445        }
446    }
447
448    private boolean isAvailable() {
449        return !mCleaningUp;
450    }
451
452    /**
453     * Handlers for incoming service calls
454     */
455    private AdapterServiceBinder mBinder;
456
457    /**
458     * The Binder implementation must be declared to be a static class, with
459     * the AdapterService instance passed in the constructor. Furthermore,
460     * when the AdapterService shuts down, the reference to the AdapterService
461     * must be explicitly removed.
462     *
463     * Otherwise, a memory leak can occur from repeated starting/stopping the
464     * service...Please refer to android.os.Binder for further details on
465     * why an inner instance class should be avoided.
466     *
467     */
468    private static class AdapterServiceBinder extends IBluetooth.Stub {
469        private AdapterService mService;
470
471        public AdapterServiceBinder(AdapterService svc) {
472            mService = svc;
473        }
474        public boolean cleanup() {
475            mService = null;
476            return true;
477        }
478
479        public AdapterService getService() {
480            if (mService  != null && mService.isAvailable()) {
481                return mService;
482            }
483            return null;
484        }
485        public boolean isEnabled() {
486            // don't check caller, may be called from system UI
487            AdapterService service = getService();
488            if (service == null) return false;
489            return service.isEnabled();
490        }
491
492        public int getState() {
493            // don't check caller, may be called from system UI
494            AdapterService service = getService();
495            if (service == null) return  BluetoothAdapter.STATE_OFF;
496            return service.getState();
497        }
498
499        public boolean enable() {
500            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
501                (!Utils.checkCaller())) {
502                Log.w(TAG,"enable(): not allowed for non-active user and non system user");
503                return false;
504	    }
505
506            AdapterService service = getService();
507            if (service == null) return false;
508            return service.enable();
509        }
510
511        public boolean enableNoAutoConnect() {
512            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
513                (!Utils.checkCaller())) {
514                Log.w(TAG,"enableNoAuto(): not allowed for non-active user and non system user");
515                return false;
516	    }
517
518            AdapterService service = getService();
519            if (service == null) return false;
520            return service.enableNoAutoConnect();
521        }
522
523        public boolean disable() {
524            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
525                (!Utils.checkCaller())) {
526                Log.w(TAG,"disable(): not allowed for non-active user and non system user");
527                return false;
528	    }
529
530            AdapterService service = getService();
531            if (service == null) return false;
532            return service.disable();
533        }
534
535        public String getAddress() {
536            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
537                (!Utils.checkCaller())) {
538                Log.w(TAG,"getAddress(): not allowed for non-active user and non system user");
539                return null;
540	    }
541
542            AdapterService service = getService();
543            if (service == null) return null;
544            return service.getAddress();
545        }
546
547        public ParcelUuid[] getUuids() {
548            if (!Utils.checkCaller()) {
549                Log.w(TAG,"getUuids(): not allowed for non-active user");
550                return new ParcelUuid[0];
551            }
552
553            AdapterService service = getService();
554            if (service == null) return new ParcelUuid[0];
555            return service.getUuids();
556        }
557
558        public String getName() {
559            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
560                (!Utils.checkCaller())) {
561                Log.w(TAG,"getName(): not allowed for non-active user and non system user");
562                return null;
563	    }
564
565            AdapterService service = getService();
566            if (service == null) return null;
567            return service.getName();
568        }
569
570        public boolean setName(String name) {
571            if (!Utils.checkCaller()) {
572                Log.w(TAG,"setName(): not allowed for non-active user");
573                return false;
574            }
575
576            AdapterService service = getService();
577            if (service == null) return false;
578            return service.setName(name);
579        }
580
581        public int getScanMode() {
582            if (!Utils.checkCaller()) {
583                Log.w(TAG,"getScanMode(): not allowed for non-active user");
584                return BluetoothAdapter.SCAN_MODE_NONE;
585            }
586
587            AdapterService service = getService();
588            if (service == null) return BluetoothAdapter.SCAN_MODE_NONE;
589            return service.getScanMode();
590        }
591
592        public boolean setScanMode(int mode, int duration) {
593            if (!Utils.checkCaller()) {
594                Log.w(TAG,"setScanMode(): not allowed for non-active user");
595                return false;
596            }
597
598            AdapterService service = getService();
599            if (service == null) return false;
600            return service.setScanMode(mode,duration);
601        }
602
603        public int getDiscoverableTimeout() {
604            if (!Utils.checkCaller()) {
605                Log.w(TAG,"getDiscoverableTimeout(): not allowed for non-active user");
606                return 0;
607            }
608
609            AdapterService service = getService();
610            if (service == null) return 0;
611            return service.getDiscoverableTimeout();
612        }
613
614        public boolean setDiscoverableTimeout(int timeout) {
615            if (!Utils.checkCaller()) {
616                Log.w(TAG,"setDiscoverableTimeout(): not allowed for non-active user");
617                return false;
618            }
619
620            AdapterService service = getService();
621            if (service == null) return false;
622            return service.setDiscoverableTimeout(timeout);
623        }
624
625        public boolean startDiscovery() {
626            if (!Utils.checkCaller()) {
627                Log.w(TAG,"startDiscovery(): not allowed for non-active user");
628                return false;
629            }
630
631            AdapterService service = getService();
632            if (service == null) return false;
633            return service.startDiscovery();
634        }
635
636        public boolean cancelDiscovery() {
637            if (!Utils.checkCaller()) {
638                Log.w(TAG,"cancelDiscovery(): not allowed for non-active user");
639                return false;
640            }
641
642            AdapterService service = getService();
643            if (service == null) return false;
644            return service.cancelDiscovery();
645        }
646        public boolean isDiscovering() {
647            if (!Utils.checkCaller()) {
648                Log.w(TAG,"isDiscovering(): not allowed for non-active user");
649                return false;
650            }
651
652            AdapterService service = getService();
653            if (service == null) return false;
654            return service.isDiscovering();
655        }
656
657        public BluetoothDevice[] getBondedDevices() {
658            // don't check caller, may be called from system UI
659            AdapterService service = getService();
660            if (service == null) return new BluetoothDevice[0];
661            return service.getBondedDevices();
662        }
663
664        public int getAdapterConnectionState() {
665            // don't check caller, may be called from system UI
666            AdapterService service = getService();
667            if (service == null) return BluetoothAdapter.STATE_DISCONNECTED;
668            return service.getAdapterConnectionState();
669        }
670
671        public int getProfileConnectionState(int profile) {
672            if (!Utils.checkCaller()) {
673                Log.w(TAG,"getProfileConnectionState: not allowed for non-active user");
674                return BluetoothProfile.STATE_DISCONNECTED;
675            }
676
677            AdapterService service = getService();
678            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
679            return service.getProfileConnectionState(profile);
680        }
681
682        public boolean createBond(BluetoothDevice device) {
683            if (!Utils.checkCaller()) {
684                Log.w(TAG,"createBond(): not allowed for non-active user");
685                return false;
686            }
687
688            AdapterService service = getService();
689            if (service == null) return false;
690            return service.createBond(device);
691        }
692
693        public boolean cancelBondProcess(BluetoothDevice device) {
694            if (!Utils.checkCaller()) {
695                Log.w(TAG,"cancelBondProcess(): not allowed for non-active user");
696                return false;
697            }
698
699            AdapterService service = getService();
700            if (service == null) return false;
701            return service.cancelBondProcess(device);
702        }
703
704        public boolean removeBond(BluetoothDevice device) {
705            if (!Utils.checkCaller()) {
706                Log.w(TAG,"removeBond(): not allowed for non-active user");
707                return false;
708            }
709
710            AdapterService service = getService();
711            if (service == null) return false;
712            return service.removeBond(device);
713        }
714
715        public int getBondState(BluetoothDevice device) {
716            // don't check caller, may be called from system UI
717            AdapterService service = getService();
718            if (service == null) return BluetoothDevice.BOND_NONE;
719            return service.getBondState(device);
720        }
721
722        public String getRemoteName(BluetoothDevice device) {
723            if (!Utils.checkCaller()) {
724                Log.w(TAG,"getRemoteName(): not allowed for non-active user");
725                return null;
726            }
727
728            AdapterService service = getService();
729            if (service == null) return null;
730            return service.getRemoteName(device);
731        }
732
733        public String getRemoteAlias(BluetoothDevice device) {
734            if (!Utils.checkCaller()) {
735                Log.w(TAG,"getRemoteAlias(): not allowed for non-active user");
736                return null;
737            }
738
739            AdapterService service = getService();
740            if (service == null) return null;
741            return service.getRemoteAlias(device);
742        }
743
744        public boolean setRemoteAlias(BluetoothDevice device, String name) {
745            if (!Utils.checkCaller()) {
746                Log.w(TAG,"setRemoteAlias(): not allowed for non-active user");
747                return false;
748            }
749
750            AdapterService service = getService();
751            if (service == null) return false;
752            return service.setRemoteAlias(device, name);
753        }
754
755        public int getRemoteClass(BluetoothDevice device) {
756            if (!Utils.checkCaller()) {
757                Log.w(TAG,"getRemoteClass(): not allowed for non-active user");
758                return 0;
759            }
760
761            AdapterService service = getService();
762            if (service == null) return 0;
763            return service.getRemoteClass(device);
764        }
765
766        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
767            if (!Utils.checkCaller()) {
768                Log.w(TAG,"getRemoteUuids(): not allowed for non-active user");
769                return new ParcelUuid[0];
770            }
771
772            AdapterService service = getService();
773            if (service == null) return new ParcelUuid[0];
774            return service.getRemoteUuids(device);
775        }
776
777        public boolean fetchRemoteUuids(BluetoothDevice device) {
778            if (!Utils.checkCaller()) {
779                Log.w(TAG,"fetchRemoteUuids(): not allowed for non-active user");
780                return false;
781            }
782
783            AdapterService service = getService();
784            if (service == null) return false;
785            return service.fetchRemoteUuids(device);
786        }
787
788        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
789            if (!Utils.checkCaller()) {
790                Log.w(TAG,"setPin(): not allowed for non-active user");
791                return false;
792            }
793
794            AdapterService service = getService();
795            if (service == null) return false;
796            return service.setPin(device, accept, len, pinCode);
797        }
798
799        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
800            if (!Utils.checkCaller()) {
801                Log.w(TAG,"setPasskey(): not allowed for non-active user");
802                return false;
803            }
804
805            AdapterService service = getService();
806            if (service == null) return false;
807            return service.setPasskey(device, accept, len, passkey);
808        }
809
810        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
811            if (!Utils.checkCaller()) {
812                Log.w(TAG,"setPairingConfirmation(): not allowed for non-active user");
813                return false;
814            }
815
816            AdapterService service = getService();
817            if (service == null) return false;
818            return service.setPairingConfirmation(device, accept);
819        }
820
821        public void sendConnectionStateChange(BluetoothDevice
822                device, int profile, int state, int prevState) {
823            AdapterService service = getService();
824            if (service == null) return;
825            service.sendConnectionStateChange(device, profile, state, prevState);
826        }
827
828        public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
829                                                  ParcelUuid uuid, int port, int flag) {
830            if (!Utils.checkCaller()) {
831                Log.w(TAG,"connectSocket(): not allowed for non-active user");
832                return null;
833            }
834
835            AdapterService service = getService();
836            if (service == null) return null;
837            return service.connectSocket(device, type, uuid, port, flag);
838        }
839
840        public ParcelFileDescriptor createSocketChannel(int type, String serviceName,
841                                                        ParcelUuid uuid, int port, int flag) {
842            if (!Utils.checkCaller()) {
843                Log.w(TAG,"createSocketChannel(): not allowed for non-active user");
844                return null;
845            }
846
847            AdapterService service = getService();
848            if (service == null) return null;
849            return service.createSocketChannel(type, serviceName, uuid, port, flag);
850        }
851
852        public void registerCallback(IBluetoothCallback cb) {
853            AdapterService service = getService();
854            if (service == null) return ;
855            service.registerCallback(cb);
856         }
857
858         public void unregisterCallback(IBluetoothCallback cb) {
859             AdapterService service = getService();
860             if (service == null) return ;
861             service.unregisterCallback(cb);
862         }
863    };
864
865
866    //----API Methods--------
867     boolean isEnabled() {
868        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
869
870        return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
871    }
872
873     int getState() {
874        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
875
876        if (mAdapterProperties == null){
877            return  BluetoothAdapter.STATE_OFF;
878        }
879        else {
880            debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
881            return mAdapterProperties.getState();
882        }
883    }
884
885     boolean enable() {
886        return enable (false);
887    }
888
889      public boolean enableNoAutoConnect() {
890         return enable (true);
891     }
892
893     public synchronized boolean enable(boolean quietMode) {
894         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
895                 "Need BLUETOOTH ADMIN permission");
896         if (DBG)debugLog("Enable called with quiet mode status =  " + mQuietmode);
897         mQuietmode  = quietMode;
898         Message m =
899                 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
900         mAdapterStateMachine.sendMessage(m);
901         return true;
902     }
903
904     boolean disable() {
905        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
906                "Need BLUETOOTH ADMIN permission");
907
908        if (DBG) debugLog("disable() called...");
909        Message m =
910                mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
911        mAdapterStateMachine.sendMessage(m);
912        return true;
913    }
914
915     String getAddress() {
916        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
917
918        String addrString = null;
919        byte[] address = mAdapterProperties.getAddress();
920        return Utils.getAddressStringFromByte(address);
921    }
922
923     ParcelUuid[] getUuids() {
924        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
925
926        return mAdapterProperties.getUuids();
927    }
928
929     String getName() {
930        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
931                "Need BLUETOOTH permission");
932
933        try {
934            return mAdapterProperties.getName();
935        } catch (Throwable t) {
936            Log.d(TAG, "Unexpected exception while calling getName()",t);
937        }
938        return null;
939    }
940
941     boolean setName(String name) {
942        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
943                "Need BLUETOOTH ADMIN permission");
944
945        return mAdapterProperties.setName(name);
946    }
947
948     int getScanMode() {
949        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
950
951        return mAdapterProperties.getScanMode();
952    }
953
954     boolean setScanMode(int mode, int duration) {
955        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
956
957        setDiscoverableTimeout(duration);
958
959        int newMode = convertScanModeToHal(mode);
960        return mAdapterProperties.setScanMode(newMode);
961    }
962
963     int getDiscoverableTimeout() {
964        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
965
966        return mAdapterProperties.getDiscoverableTimeout();
967    }
968
969     boolean setDiscoverableTimeout(int timeout) {
970        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
971
972        return mAdapterProperties.setDiscoverableTimeout(timeout);
973    }
974
975     boolean startDiscovery() {
976        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
977                "Need BLUETOOTH ADMIN permission");
978
979        return startDiscoveryNative();
980    }
981
982     boolean cancelDiscovery() {
983        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
984                "Need BLUETOOTH ADMIN permission");
985
986        return cancelDiscoveryNative();
987    }
988
989     boolean isDiscovering() {
990        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
991
992        return mAdapterProperties.isDiscovering();
993    }
994
995     BluetoothDevice[] getBondedDevices() {
996        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
997        debugLog("Get Bonded Devices being called");
998        return mAdapterProperties.getBondedDevices();
999    }
1000
1001     int getAdapterConnectionState() {
1002        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1003
1004        return mAdapterProperties.getConnectionState();
1005    }
1006
1007     int getProfileConnectionState(int profile) {
1008        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1009
1010        return mAdapterProperties.getProfileConnectionState(profile);
1011    }
1012
1013     boolean createBond(BluetoothDevice device) {
1014        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1015            "Need BLUETOOTH ADMIN permission");
1016        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1017        if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
1018            return false;
1019        }
1020
1021        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
1022        msg.obj = device;
1023        mBondStateMachine.sendMessage(msg);
1024        return true;
1025    }
1026
1027      public boolean isQuietModeEnabled() {
1028          if (DBG) debugLog("Quiet mode Enabled = " + mQuietmode);
1029          return mQuietmode;
1030     }
1031
1032     public void autoConnect(){
1033        if (getState() != BluetoothAdapter.STATE_ON){
1034             errorLog("BT is not ON. Exiting autoConnect");
1035             return;
1036         }
1037         if (isQuietModeEnabled() == false) {
1038            if (DBG) debugLog( "Initiate auto connection on BT on...");
1039             autoConnectHeadset();
1040             autoConnectA2dp();
1041         }
1042         else {
1043             if (DBG) debugLog( "BT is in Quiet mode. Not initiating  auto connections");
1044         }
1045    }
1046
1047     private void autoConnectHeadset(){
1048        HeadsetService  hsService = HeadsetService.getHeadsetService();
1049
1050        BluetoothDevice bondedDevices[] = getBondedDevices();
1051        if ((bondedDevices == null) ||(hsService == null)) {
1052            return;
1053        }
1054        for (BluetoothDevice device : bondedDevices) {
1055            if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
1056                Log.d(TAG,"Auto Connecting Headset Profile with device " + device.toString());
1057                hsService.connect(device);
1058                }
1059        }
1060    }
1061
1062     private void autoConnectA2dp(){
1063        A2dpService a2dpSservice = A2dpService.getA2dpService();
1064        BluetoothDevice bondedDevices[] = getBondedDevices();
1065        if ((bondedDevices == null) ||(a2dpSservice == null)) {
1066            return;
1067        }
1068        for (BluetoothDevice device : bondedDevices) {
1069            if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
1070                Log.d(TAG,"Auto Connecting A2DP Profile with device " + device.toString());
1071                a2dpSservice.connect(device);
1072                }
1073        }
1074    }
1075
1076     public void connectOtherProfile(BluetoothDevice device, int firstProfileStatus){
1077        if ((mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES) == false) &&
1078            (isQuietModeEnabled()== false)){
1079            Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES);
1080            m.obj = device;
1081            m.arg1 = (int)firstProfileStatus;
1082            mHandler.sendMessageDelayed(m,CONNECT_OTHER_PROFILES_TIMEOUT);
1083        }
1084    }
1085
1086     private void processConnectOtherProfiles (BluetoothDevice device, int firstProfileStatus){
1087        if (getState()!= BluetoothAdapter.STATE_ON){
1088            return;
1089        }
1090        HeadsetService  hsService = HeadsetService.getHeadsetService();
1091        A2dpService a2dpService = A2dpService.getA2dpService();
1092        // if any of the profile service is  null, second profile connection not required
1093        if ((hsService == null) ||(a2dpService == null )){
1094            return;
1095        }
1096        List<BluetoothDevice> a2dpConnDevList= a2dpService.getConnectedDevices();
1097        List<BluetoothDevice> hfConnDevList= hsService.getConnectedDevices();
1098        // Check if the device is in disconnected state and if so return
1099        // We ned to connect other profile only if one of the profile is still in connected state
1100        // This is required to avoide a race condition in which profiles would
1101        // automaticlly connect if the disconnection is initiated within 6 seconds of connection
1102        //First profile connection being rejected is an exception
1103        if((hfConnDevList.isEmpty() && a2dpConnDevList.isEmpty())&&
1104            (PROFILE_CONN_CONNECTED  == firstProfileStatus)){
1105            return;
1106        }
1107        if((hfConnDevList.isEmpty()) &&
1108            (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
1109            hsService.connect(device);
1110        }
1111        else if((a2dpConnDevList.isEmpty()) &&
1112            (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
1113            a2dpService.connect(device);
1114        }
1115    }
1116
1117     private void adjustOtherHeadsetPriorities(HeadsetService  hsService,
1118                                                    BluetoothDevice connectedDevice) {
1119        for (BluetoothDevice device : getBondedDevices()) {
1120           if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT &&
1121               !device.equals(connectedDevice)) {
1122               hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
1123           }
1124        }
1125     }
1126
1127     private void adjustOtherSinkPriorities(A2dpService a2dpService,
1128                                                BluetoothDevice connectedDevice) {
1129         for (BluetoothDevice device : getBondedDevices()) {
1130             if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT &&
1131                 !device.equals(connectedDevice)) {
1132                 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
1133             }
1134         }
1135     }
1136
1137     void setProfileAutoConnectionPriority (BluetoothDevice device, int profileId){
1138         if (profileId == BluetoothProfile.HEADSET) {
1139             HeadsetService  hsService = HeadsetService.getHeadsetService();
1140             if ((hsService != null) &&
1141                (BluetoothProfile.PRIORITY_AUTO_CONNECT != hsService.getPriority(device))){
1142                 adjustOtherHeadsetPriorities(hsService, device);
1143                 hsService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
1144             }
1145         }
1146         else if (profileId ==  BluetoothProfile.A2DP) {
1147             A2dpService a2dpService = A2dpService.getA2dpService();
1148             if ((a2dpService != null) &&
1149                (BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){
1150                 adjustOtherSinkPriorities(a2dpService, device);
1151                 a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
1152             }
1153         }
1154    }
1155
1156     boolean cancelBondProcess(BluetoothDevice device) {
1157        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
1158        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1159        return cancelBondNative(addr);
1160    }
1161
1162     boolean removeBond(BluetoothDevice device) {
1163        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
1164        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1165        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
1166            return false;
1167        }
1168        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
1169        msg.obj = device;
1170        mBondStateMachine.sendMessage(msg);
1171        return true;
1172    }
1173
1174     int getBondState(BluetoothDevice device) {
1175        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1176        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1177        if (deviceProp == null) {
1178            return BluetoothDevice.BOND_NONE;
1179        }
1180        return deviceProp.getBondState();
1181    }
1182
1183     String getRemoteName(BluetoothDevice device) {
1184        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1185        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1186        if (deviceProp == null) return null;
1187        return deviceProp.getName();
1188    }
1189
1190     String getRemoteAlias(BluetoothDevice device) {
1191        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1192        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1193        if (deviceProp == null) return null;
1194        return deviceProp.getAlias();
1195    }
1196
1197     boolean setRemoteAlias(BluetoothDevice device, String name) {
1198        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1199        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1200        if (deviceProp == null) return false;
1201        deviceProp.setAlias(name);
1202        return true;
1203    }
1204
1205     int getRemoteClass(BluetoothDevice device) {
1206        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1207        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1208        if (deviceProp == null) return 0;
1209
1210        return deviceProp.getBluetoothClass();
1211    }
1212
1213     ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
1214        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1215        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1216        if (deviceProp == null) return null;
1217        return deviceProp.getUuids();
1218    }
1219
1220     boolean fetchRemoteUuids(BluetoothDevice device) {
1221        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1222        mRemoteDevices.fetchUuids(device);
1223        return true;
1224    }
1225
1226     boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
1227        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1228        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1229        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1230            return false;
1231        }
1232
1233        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1234        return pinReplyNative(addr, accept, len, pinCode);
1235    }
1236
1237     boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
1238        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1239        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1240        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1241            return false;
1242        }
1243
1244        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1245        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
1246                Utils.byteArrayToInt(passkey));
1247    }
1248
1249     boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
1250        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1251        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1252        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1253            return false;
1254        }
1255
1256        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1257        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
1258                accept, 0);
1259    }
1260
1261     void sendConnectionStateChange(BluetoothDevice
1262            device, int profile, int state, int prevState) {
1263        // TODO(BT) permission check?
1264        // Since this is a binder call check if Bluetooth is on still
1265        if (getState() == BluetoothAdapter.STATE_OFF) return;
1266
1267        mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
1268
1269    }
1270
1271     ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
1272                                              ParcelUuid uuid, int port, int flag) {
1273        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1274        int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()),
1275                   type, Utils.uuidToByteArray(uuid), port, flag);
1276        if (fd < 0) {
1277            errorLog("Failed to connect socket");
1278            return null;
1279        }
1280        return ParcelFileDescriptor.adoptFd(fd);
1281    }
1282
1283     ParcelFileDescriptor createSocketChannel(int type, String serviceName,
1284                                                    ParcelUuid uuid, int port, int flag) {
1285        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1286        int fd =  createSocketChannelNative(type, serviceName,
1287                                 Utils.uuidToByteArray(uuid), port, flag);
1288        if (fd < 0) {
1289            errorLog("Failed to create socket channel");
1290            return null;
1291        }
1292        return ParcelFileDescriptor.adoptFd(fd);
1293    }
1294
1295     void registerCallback(IBluetoothCallback cb) {
1296         mCallbacks.register(cb);
1297      }
1298
1299      void unregisterCallback(IBluetoothCallback cb) {
1300         mCallbacks.unregister(cb);
1301      }
1302
1303    private static int convertScanModeToHal(int mode) {
1304        switch (mode) {
1305            case BluetoothAdapter.SCAN_MODE_NONE:
1306                return AbstractionLayer.BT_SCAN_MODE_NONE;
1307            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
1308                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
1309            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1310                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1311        }
1312       // errorLog("Incorrect scan mode in convertScanModeToHal");
1313        return -1;
1314    }
1315
1316    static int convertScanModeFromHal(int mode) {
1317        switch (mode) {
1318            case AbstractionLayer.BT_SCAN_MODE_NONE:
1319                return BluetoothAdapter.SCAN_MODE_NONE;
1320            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
1321                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1322            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1323                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1324        }
1325        //errorLog("Incorrect scan mode in convertScanModeFromHal");
1326        return -1;
1327    }
1328
1329    private void debugLog(String msg) {
1330        Log.d(TAG +"(" +hashCode()+")", msg);
1331    }
1332
1333    private void errorLog(String msg) {
1334        Log.e(TAG +"(" +hashCode()+")", msg);
1335    }
1336
1337    private native static void classInitNative();
1338    private native boolean initNative();
1339    private native void cleanupNative();
1340    /*package*/ native boolean enableNative();
1341    /*package*/ native boolean disableNative();
1342    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
1343    /*package*/ native boolean getAdapterPropertiesNative();
1344    /*package*/ native boolean getAdapterPropertyNative(int type);
1345    /*package*/ native boolean setAdapterPropertyNative(int type);
1346    /*package*/ native boolean
1347        setDevicePropertyNative(byte[] address, int type, byte[] val);
1348    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
1349
1350    /*package*/ native boolean createBondNative(byte[] address);
1351    /*package*/ native boolean removeBondNative(byte[] address);
1352    /*package*/ native boolean cancelBondNative(byte[] address);
1353
1354    private native boolean startDiscoveryNative();
1355    private native boolean cancelDiscoveryNative();
1356
1357    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
1358    private native boolean sspReplyNative(byte[] address, int type, boolean
1359            accept, int passkey);
1360
1361    /*package*/ native boolean getRemoteServicesNative(byte[] address);
1362
1363    // TODO(BT) move this to ../btsock dir
1364    private native int connectSocketNative(byte[] address, int type,
1365                                           byte[] uuid, int port, int flag);
1366    private native int createSocketChannelNative(int type, String serviceName,
1367                                                 byte[] uuid, int port, int flag);
1368
1369    protected void finalize() {
1370        cleanup();
1371        if (TRACE_REF) {
1372            synchronized (AdapterService.class) {
1373                sRefCount--;
1374                Log.d(TAG, "REFCOUNT: FINALIZED. INSTANCE_COUNT= " + sRefCount);
1375            }
1376        }
1377    }
1378}
1379