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