AdapterService.java revision 69d4ca45a25e86823fbdb754ca6a3995f8131d59
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
396    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
397    private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
398    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 30;
399    private static final int CONNECT_OTHER_PROFILES_TIMEOUT= 6000;
400
401    private final Handler mHandler = new Handler() {
402        @Override
403        public void handleMessage(Message msg) {
404            if (DBG) debugLog("Message: " + msg.what);
405
406            switch (msg.what) {
407                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
408                    if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
409                    processProfileServiceStateChanged((String) msg.obj, msg.arg1);
410                }
411                    break;
412                case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: {
413                    if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
414                    processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
415                }
416                    break;
417                case MESSAGE_CONNECT_OTHER_PROFILES: {
418                    if (DBG) debugLog( "MESSAGE_CONNECT_OTHER_PROFILES");
419                    processConnectOtherProfiles((BluetoothDevice) msg.obj,msg.arg1);
420                }
421                    break;
422            }
423        }
424    };
425
426    @SuppressWarnings("rawtypes")
427    private void setProfileServiceState(Class[] services, int state) {
428        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
429            Log.w(TAG,"setProfileServiceState(): invalid state...Leaving...");
430            return;
431        }
432
433        int expectedCurrentState= BluetoothAdapter.STATE_OFF;
434        int pendingState = BluetoothAdapter.STATE_TURNING_ON;
435        if (state == BluetoothAdapter.STATE_OFF) {
436            expectedCurrentState= BluetoothAdapter.STATE_ON;
437            pendingState = BluetoothAdapter.STATE_TURNING_OFF;
438        }
439
440        for (int i=0; i <services.length;i++) {
441            String serviceName = services[i].getName();
442            Integer serviceState = mProfileServicesState.get(serviceName);
443            if(serviceState != null && serviceState != expectedCurrentState) {
444                Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " +
445                        serviceName+". Invalid state: " + serviceState);
446                continue;
447            }
448
449            if (DBG) {
450                Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
451                        serviceName);
452            }
453
454            mProfileServicesState.put(serviceName,pendingState);
455            Intent intent = new Intent(this,services[i]);
456            intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
457            intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
458            startService(intent);
459        }
460    }
461
462    private boolean isAvailable() {
463        return !mCleaningUp;
464    }
465
466    /**
467     * Handlers for incoming service calls
468     */
469    private AdapterServiceBinder mBinder;
470
471    /**
472     * The Binder implementation must be declared to be a static class, with
473     * the AdapterService instance passed in the constructor. Furthermore,
474     * when the AdapterService shuts down, the reference to the AdapterService
475     * must be explicitly removed.
476     *
477     * Otherwise, a memory leak can occur from repeated starting/stopping the
478     * service...Please refer to android.os.Binder for further details on
479     * why an inner instance class should be avoided.
480     *
481     */
482    private static class AdapterServiceBinder extends IBluetooth.Stub {
483        private AdapterService mService;
484
485        public AdapterServiceBinder(AdapterService svc) {
486            mService = svc;
487        }
488        public boolean cleanup() {
489            mService = null;
490            return true;
491        }
492
493        public AdapterService getService() {
494            if (mService  != null && mService.isAvailable()) {
495                return mService;
496            }
497            return null;
498        }
499        public boolean isEnabled() {
500            // don't check caller, may be called from system UI
501            AdapterService service = getService();
502            if (service == null) return false;
503            return service.isEnabled();
504        }
505
506        public int getState() {
507            // don't check caller, may be called from system UI
508            AdapterService service = getService();
509            if (service == null) return  BluetoothAdapter.STATE_OFF;
510            return service.getState();
511        }
512
513        public boolean enable() {
514            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
515                (!Utils.checkCaller())) {
516                Log.w(TAG,"enable(): not allowed for non-active user and non system user");
517                return false;
518	    }
519
520            AdapterService service = getService();
521            if (service == null) return false;
522            return service.enable();
523        }
524
525        public boolean enableNoAutoConnect() {
526            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
527                (!Utils.checkCaller())) {
528                Log.w(TAG,"enableNoAuto(): not allowed for non-active user and non system user");
529                return false;
530	    }
531
532            AdapterService service = getService();
533            if (service == null) return false;
534            return service.enableNoAutoConnect();
535        }
536
537        public boolean disable() {
538            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
539                (!Utils.checkCaller())) {
540                Log.w(TAG,"disable(): not allowed for non-active user and non system user");
541                return false;
542	    }
543
544            AdapterService service = getService();
545            if (service == null) return false;
546            return service.disable();
547        }
548
549        public String getAddress() {
550            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
551                (!Utils.checkCaller())) {
552                Log.w(TAG,"getAddress(): not allowed for non-active user and non system user");
553                return null;
554	    }
555
556            AdapterService service = getService();
557            if (service == null) return null;
558            return service.getAddress();
559        }
560
561        public ParcelUuid[] getUuids() {
562            if (!Utils.checkCaller()) {
563                Log.w(TAG,"getUuids(): not allowed for non-active user");
564                return new ParcelUuid[0];
565            }
566
567            AdapterService service = getService();
568            if (service == null) return new ParcelUuid[0];
569            return service.getUuids();
570        }
571
572        public String getName() {
573            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
574                (!Utils.checkCaller())) {
575                Log.w(TAG,"getName(): not allowed for non-active user and non system user");
576                return null;
577	    }
578
579            AdapterService service = getService();
580            if (service == null) return null;
581            return service.getName();
582        }
583
584        public boolean setName(String name) {
585            if (!Utils.checkCaller()) {
586                Log.w(TAG,"setName(): not allowed for non-active user");
587                return false;
588            }
589
590            AdapterService service = getService();
591            if (service == null) return false;
592            return service.setName(name);
593        }
594
595        public int getScanMode() {
596            if (!Utils.checkCaller()) {
597                Log.w(TAG,"getScanMode(): not allowed for non-active user");
598                return BluetoothAdapter.SCAN_MODE_NONE;
599            }
600
601            AdapterService service = getService();
602            if (service == null) return BluetoothAdapter.SCAN_MODE_NONE;
603            return service.getScanMode();
604        }
605
606        public boolean setScanMode(int mode, int duration) {
607            if (!Utils.checkCaller()) {
608                Log.w(TAG,"setScanMode(): not allowed for non-active user");
609                return false;
610            }
611
612            AdapterService service = getService();
613            if (service == null) return false;
614            return service.setScanMode(mode,duration);
615        }
616
617        public int getDiscoverableTimeout() {
618            if (!Utils.checkCaller()) {
619                Log.w(TAG,"getDiscoverableTimeout(): not allowed for non-active user");
620                return 0;
621            }
622
623            AdapterService service = getService();
624            if (service == null) return 0;
625            return service.getDiscoverableTimeout();
626        }
627
628        public boolean setDiscoverableTimeout(int timeout) {
629            if (!Utils.checkCaller()) {
630                Log.w(TAG,"setDiscoverableTimeout(): not allowed for non-active user");
631                return false;
632            }
633
634            AdapterService service = getService();
635            if (service == null) return false;
636            return service.setDiscoverableTimeout(timeout);
637        }
638
639        public boolean startDiscovery() {
640            if (!Utils.checkCaller()) {
641                Log.w(TAG,"startDiscovery(): not allowed for non-active user");
642                return false;
643            }
644
645            AdapterService service = getService();
646            if (service == null) return false;
647            return service.startDiscovery();
648        }
649
650        public boolean cancelDiscovery() {
651            if (!Utils.checkCaller()) {
652                Log.w(TAG,"cancelDiscovery(): not allowed for non-active user");
653                return false;
654            }
655
656            AdapterService service = getService();
657            if (service == null) return false;
658            return service.cancelDiscovery();
659        }
660        public boolean isDiscovering() {
661            if (!Utils.checkCaller()) {
662                Log.w(TAG,"isDiscovering(): not allowed for non-active user");
663                return false;
664            }
665
666            AdapterService service = getService();
667            if (service == null) return false;
668            return service.isDiscovering();
669        }
670
671        public BluetoothDevice[] getBondedDevices() {
672            // don't check caller, may be called from system UI
673            AdapterService service = getService();
674            if (service == null) return new BluetoothDevice[0];
675            return service.getBondedDevices();
676        }
677
678        public int getAdapterConnectionState() {
679            // don't check caller, may be called from system UI
680            AdapterService service = getService();
681            if (service == null) return BluetoothAdapter.STATE_DISCONNECTED;
682            return service.getAdapterConnectionState();
683        }
684
685        public int getProfileConnectionState(int profile) {
686            if (!Utils.checkCaller()) {
687                Log.w(TAG,"getProfileConnectionState: not allowed for non-active user");
688                return BluetoothProfile.STATE_DISCONNECTED;
689            }
690
691            AdapterService service = getService();
692            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
693            return service.getProfileConnectionState(profile);
694        }
695
696        public boolean createBond(BluetoothDevice device) {
697            if (!Utils.checkCaller()) {
698                Log.w(TAG,"createBond(): not allowed for non-active user");
699                return false;
700            }
701
702            AdapterService service = getService();
703            if (service == null) return false;
704            return service.createBond(device);
705        }
706
707        public boolean cancelBondProcess(BluetoothDevice device) {
708            if (!Utils.checkCaller()) {
709                Log.w(TAG,"cancelBondProcess(): not allowed for non-active user");
710                return false;
711            }
712
713            AdapterService service = getService();
714            if (service == null) return false;
715            return service.cancelBondProcess(device);
716        }
717
718        public boolean removeBond(BluetoothDevice device) {
719            if (!Utils.checkCaller()) {
720                Log.w(TAG,"removeBond(): not allowed for non-active user");
721                return false;
722            }
723
724            AdapterService service = getService();
725            if (service == null) return false;
726            return service.removeBond(device);
727        }
728
729        public int getBondState(BluetoothDevice device) {
730            // don't check caller, may be called from system UI
731            AdapterService service = getService();
732            if (service == null) return BluetoothDevice.BOND_NONE;
733            return service.getBondState(device);
734        }
735
736        public String getRemoteName(BluetoothDevice device) {
737            if (!Utils.checkCaller()) {
738                Log.w(TAG,"getRemoteName(): not allowed for non-active user");
739                return null;
740            }
741
742            AdapterService service = getService();
743            if (service == null) return null;
744            return service.getRemoteName(device);
745        }
746
747        public int getRemoteType(BluetoothDevice device) {
748            if (!Utils.checkCaller()) {
749                Log.w(TAG,"getRemoteType(): not allowed for non-active user");
750                return BluetoothDevice.DEVICE_TYPE_UNKNOWN;
751            }
752
753            AdapterService service = getService();
754            if (service == null) return BluetoothDevice.DEVICE_TYPE_UNKNOWN;
755            return service.getRemoteType(device);
756        }
757
758        public String getRemoteAlias(BluetoothDevice device) {
759            if (!Utils.checkCaller()) {
760                Log.w(TAG,"getRemoteAlias(): not allowed for non-active user");
761                return null;
762            }
763
764            AdapterService service = getService();
765            if (service == null) return null;
766            return service.getRemoteAlias(device);
767        }
768
769        public boolean setRemoteAlias(BluetoothDevice device, String name) {
770            if (!Utils.checkCaller()) {
771                Log.w(TAG,"setRemoteAlias(): not allowed for non-active user");
772                return false;
773            }
774
775            AdapterService service = getService();
776            if (service == null) return false;
777            return service.setRemoteAlias(device, name);
778        }
779
780        public int getRemoteClass(BluetoothDevice device) {
781            if (!Utils.checkCaller()) {
782                Log.w(TAG,"getRemoteClass(): not allowed for non-active user");
783                return 0;
784            }
785
786            AdapterService service = getService();
787            if (service == null) return 0;
788            return service.getRemoteClass(device);
789        }
790
791        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
792            if (!Utils.checkCaller()) {
793                Log.w(TAG,"getRemoteUuids(): not allowed for non-active user");
794                return new ParcelUuid[0];
795            }
796
797            AdapterService service = getService();
798            if (service == null) return new ParcelUuid[0];
799            return service.getRemoteUuids(device);
800        }
801
802        public boolean fetchRemoteUuids(BluetoothDevice device) {
803            if (!Utils.checkCaller()) {
804                Log.w(TAG,"fetchRemoteUuids(): not allowed for non-active user");
805                return false;
806            }
807
808            AdapterService service = getService();
809            if (service == null) return false;
810            return service.fetchRemoteUuids(device);
811        }
812
813        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
814            if (!Utils.checkCaller()) {
815                Log.w(TAG,"setPin(): not allowed for non-active user");
816                return false;
817            }
818
819            AdapterService service = getService();
820            if (service == null) return false;
821            return service.setPin(device, accept, len, pinCode);
822        }
823
824        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
825            if (!Utils.checkCaller()) {
826                Log.w(TAG,"setPasskey(): not allowed for non-active user");
827                return false;
828            }
829
830            AdapterService service = getService();
831            if (service == null) return false;
832            return service.setPasskey(device, accept, len, passkey);
833        }
834
835        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
836            if (!Utils.checkCaller()) {
837                Log.w(TAG,"setPairingConfirmation(): not allowed for non-active user");
838                return false;
839            }
840
841            AdapterService service = getService();
842            if (service == null) return false;
843            return service.setPairingConfirmation(device, accept);
844        }
845
846        public void sendConnectionStateChange(BluetoothDevice
847                device, int profile, int state, int prevState) {
848            AdapterService service = getService();
849            if (service == null) return;
850            service.sendConnectionStateChange(device, profile, state, prevState);
851        }
852
853        public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
854                                                  ParcelUuid uuid, int port, int flag) {
855            if (!Utils.checkCaller()) {
856                Log.w(TAG,"connectSocket(): not allowed for non-active user");
857                return null;
858            }
859
860            AdapterService service = getService();
861            if (service == null) return null;
862            return service.connectSocket(device, type, uuid, port, flag);
863        }
864
865        public ParcelFileDescriptor createSocketChannel(int type, String serviceName,
866                                                        ParcelUuid uuid, int port, int flag) {
867            if (!Utils.checkCaller()) {
868                Log.w(TAG,"createSocketChannel(): not allowed for non-active user");
869                return null;
870            }
871
872            AdapterService service = getService();
873            if (service == null) return null;
874            return service.createSocketChannel(type, serviceName, uuid, port, flag);
875        }
876
877        public boolean configHciSnoopLog(boolean enable) {
878            if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
879                (!Utils.checkCaller())) {
880                Log.w(TAG,"configHciSnoopLog(): not allowed for non-active user");
881                return false;
882            }
883
884            AdapterService service = getService();
885            if (service == null) return false;
886            return service.configHciSnoopLog(enable);
887        }
888
889        public void registerCallback(IBluetoothCallback cb) {
890            AdapterService service = getService();
891            if (service == null) return ;
892            service.registerCallback(cb);
893         }
894
895         public void unregisterCallback(IBluetoothCallback cb) {
896             AdapterService service = getService();
897             if (service == null) return ;
898             service.unregisterCallback(cb);
899         }
900    };
901
902
903    //----API Methods--------
904     boolean isEnabled() {
905        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
906
907        return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
908    }
909
910     int getState() {
911        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
912
913        if (mAdapterProperties == null){
914            return  BluetoothAdapter.STATE_OFF;
915        }
916        else {
917            if (DBG) debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
918            return mAdapterProperties.getState();
919        }
920    }
921
922     boolean enable() {
923        return enable (false);
924    }
925
926      public boolean enableNoAutoConnect() {
927         return enable (true);
928     }
929
930     public synchronized boolean enable(boolean quietMode) {
931         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
932                                        "Need BLUETOOTH ADMIN permission");
933         if (DBG)debugLog("Enable called with quiet mode status =  " + mQuietmode);
934         mQuietmode  = quietMode;
935         Message m =
936                 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
937         mAdapterStateMachine.sendMessage(m);
938         return true;
939     }
940
941     boolean disable() {
942        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
943                                       "Need BLUETOOTH ADMIN permission");
944
945        if (DBG) debugLog("disable() called...");
946        Message m =
947                mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
948        mAdapterStateMachine.sendMessage(m);
949        return true;
950    }
951
952     String getAddress() {
953        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
954
955        String addrString = null;
956        byte[] address = mAdapterProperties.getAddress();
957        return Utils.getAddressStringFromByte(address);
958    }
959
960     ParcelUuid[] getUuids() {
961        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
962
963        return mAdapterProperties.getUuids();
964    }
965
966     String getName() {
967        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
968                                       "Need BLUETOOTH permission");
969
970        try {
971            return mAdapterProperties.getName();
972        } catch (Throwable t) {
973            Log.d(TAG, "Unexpected exception while calling getName()",t);
974        }
975        return null;
976    }
977
978     boolean setName(String name) {
979        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
980                                       "Need BLUETOOTH ADMIN permission");
981
982        return mAdapterProperties.setName(name);
983    }
984
985     int getScanMode() {
986        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
987
988        return mAdapterProperties.getScanMode();
989    }
990
991     boolean setScanMode(int mode, int duration) {
992        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
993
994        setDiscoverableTimeout(duration);
995
996        int newMode = convertScanModeToHal(mode);
997        return mAdapterProperties.setScanMode(newMode);
998    }
999
1000     int getDiscoverableTimeout() {
1001        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1002
1003        return mAdapterProperties.getDiscoverableTimeout();
1004    }
1005
1006     boolean setDiscoverableTimeout(int timeout) {
1007        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1008
1009        return mAdapterProperties.setDiscoverableTimeout(timeout);
1010    }
1011
1012     boolean startDiscovery() {
1013        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1014                                       "Need BLUETOOTH ADMIN permission");
1015
1016        return startDiscoveryNative();
1017    }
1018
1019     boolean cancelDiscovery() {
1020        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1021                                       "Need BLUETOOTH ADMIN permission");
1022
1023        return cancelDiscoveryNative();
1024    }
1025
1026     boolean isDiscovering() {
1027        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1028
1029        return mAdapterProperties.isDiscovering();
1030    }
1031
1032     BluetoothDevice[] getBondedDevices() {
1033        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1034        debugLog("Get Bonded Devices being called");
1035        return mAdapterProperties.getBondedDevices();
1036    }
1037
1038     int getAdapterConnectionState() {
1039        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1040
1041        return mAdapterProperties.getConnectionState();
1042    }
1043
1044     int getProfileConnectionState(int profile) {
1045        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1046
1047        return mAdapterProperties.getProfileConnectionState(profile);
1048    }
1049
1050     boolean createBond(BluetoothDevice device) {
1051        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1052            "Need BLUETOOTH ADMIN permission");
1053        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1054        if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
1055            return false;
1056        }
1057
1058        // Pairing is unreliable while scanning, so cancel discovery
1059        // Note, remove this when native stack improves
1060        cancelDiscoveryNative();
1061
1062        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
1063        msg.obj = device;
1064        mBondStateMachine.sendMessage(msg);
1065        return true;
1066    }
1067
1068      public boolean isQuietModeEnabled() {
1069          if (DBG) debugLog("Quiet mode Enabled = " + mQuietmode);
1070          return mQuietmode;
1071     }
1072
1073     public void autoConnect(){
1074        if (getState() != BluetoothAdapter.STATE_ON){
1075             errorLog("BT is not ON. Exiting autoConnect");
1076             return;
1077         }
1078         if (isQuietModeEnabled() == false) {
1079            if (DBG) debugLog( "Initiate auto connection on BT on...");
1080             autoConnectHeadset();
1081             autoConnectA2dp();
1082         }
1083         else {
1084             if (DBG) debugLog( "BT is in Quiet mode. Not initiating  auto connections");
1085         }
1086    }
1087
1088     private void autoConnectHeadset(){
1089        HeadsetService  hsService = HeadsetService.getHeadsetService();
1090
1091        BluetoothDevice bondedDevices[] = getBondedDevices();
1092        if ((bondedDevices == null) ||(hsService == null)) {
1093            return;
1094        }
1095        for (BluetoothDevice device : bondedDevices) {
1096            if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
1097                Log.d(TAG,"Auto Connecting Headset Profile with device " + device.toString());
1098                hsService.connect(device);
1099                }
1100        }
1101    }
1102
1103     private void autoConnectA2dp(){
1104        A2dpService a2dpSservice = A2dpService.getA2dpService();
1105        BluetoothDevice bondedDevices[] = getBondedDevices();
1106        if ((bondedDevices == null) ||(a2dpSservice == null)) {
1107            return;
1108        }
1109        for (BluetoothDevice device : bondedDevices) {
1110            if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
1111                Log.d(TAG,"Auto Connecting A2DP Profile with device " + device.toString());
1112                a2dpSservice.connect(device);
1113                }
1114        }
1115    }
1116
1117     public void connectOtherProfile(BluetoothDevice device, int firstProfileStatus){
1118        if ((mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES) == false) &&
1119            (isQuietModeEnabled()== false)){
1120            Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES);
1121            m.obj = device;
1122            m.arg1 = (int)firstProfileStatus;
1123            mHandler.sendMessageDelayed(m,CONNECT_OTHER_PROFILES_TIMEOUT);
1124        }
1125    }
1126
1127     private void processConnectOtherProfiles (BluetoothDevice device, int firstProfileStatus){
1128        if (getState()!= BluetoothAdapter.STATE_ON){
1129            return;
1130        }
1131        HeadsetService  hsService = HeadsetService.getHeadsetService();
1132        A2dpService a2dpService = A2dpService.getA2dpService();
1133        // if any of the profile service is  null, second profile connection not required
1134        if ((hsService == null) ||(a2dpService == null )){
1135            return;
1136        }
1137        List<BluetoothDevice> a2dpConnDevList= a2dpService.getConnectedDevices();
1138        List<BluetoothDevice> hfConnDevList= hsService.getConnectedDevices();
1139        // Check if the device is in disconnected state and if so return
1140        // We ned to connect other profile only if one of the profile is still in connected state
1141        // This is required to avoide a race condition in which profiles would
1142        // automaticlly connect if the disconnection is initiated within 6 seconds of connection
1143        //First profile connection being rejected is an exception
1144        if((hfConnDevList.isEmpty() && a2dpConnDevList.isEmpty())&&
1145            (PROFILE_CONN_CONNECTED  == firstProfileStatus)){
1146            return;
1147        }
1148        if((hfConnDevList.isEmpty()) &&
1149            (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
1150            hsService.connect(device);
1151        }
1152        else if((a2dpConnDevList.isEmpty()) &&
1153            (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
1154            a2dpService.connect(device);
1155        }
1156    }
1157
1158     private void adjustOtherHeadsetPriorities(HeadsetService  hsService,
1159                                                    List<BluetoothDevice> connectedDeviceList) {
1160        for (BluetoothDevice device : getBondedDevices()) {
1161           if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT &&
1162               !connectedDeviceList.contains(device)) {
1163               hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
1164           }
1165        }
1166     }
1167
1168     private void adjustOtherSinkPriorities(A2dpService a2dpService,
1169                                                BluetoothDevice connectedDevice) {
1170         for (BluetoothDevice device : getBondedDevices()) {
1171             if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT &&
1172                 !device.equals(connectedDevice)) {
1173                 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
1174             }
1175         }
1176     }
1177
1178     void setProfileAutoConnectionPriority (BluetoothDevice device, int profileId){
1179         if (profileId == BluetoothProfile.HEADSET) {
1180             HeadsetService  hsService = HeadsetService.getHeadsetService();
1181             List<BluetoothDevice> deviceList = hsService.getConnectedDevices();
1182             if ((hsService != null) &&
1183                (BluetoothProfile.PRIORITY_AUTO_CONNECT != hsService.getPriority(device))){
1184                 adjustOtherHeadsetPriorities(hsService, deviceList);
1185                 hsService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
1186             }
1187         }
1188         else if (profileId ==  BluetoothProfile.A2DP) {
1189             A2dpService a2dpService = A2dpService.getA2dpService();
1190             if ((a2dpService != null) &&
1191                (BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){
1192                 adjustOtherSinkPriorities(a2dpService, device);
1193                 a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
1194             }
1195         }
1196    }
1197
1198     boolean cancelBondProcess(BluetoothDevice device) {
1199        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
1200        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1201        return cancelBondNative(addr);
1202    }
1203
1204     boolean removeBond(BluetoothDevice device) {
1205        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
1206        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1207        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
1208            return false;
1209        }
1210        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
1211        msg.obj = device;
1212        mBondStateMachine.sendMessage(msg);
1213        return true;
1214    }
1215
1216     int getBondState(BluetoothDevice device) {
1217        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1218        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1219        if (deviceProp == null) {
1220            return BluetoothDevice.BOND_NONE;
1221        }
1222        return deviceProp.getBondState();
1223    }
1224
1225     String getRemoteName(BluetoothDevice device) {
1226        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1227        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1228        if (deviceProp == null) return null;
1229        return deviceProp.getName();
1230    }
1231
1232     int getRemoteType(BluetoothDevice device) {
1233        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1234        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1235        if (deviceProp == null) return BluetoothDevice.DEVICE_TYPE_UNKNOWN;
1236        return deviceProp.getDeviceType();
1237    }
1238
1239     String getRemoteAlias(BluetoothDevice device) {
1240        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1241        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1242        if (deviceProp == null) return null;
1243        return deviceProp.getAlias();
1244    }
1245
1246     boolean setRemoteAlias(BluetoothDevice device, String name) {
1247        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1248        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1249        if (deviceProp == null) return false;
1250        deviceProp.setAlias(name);
1251        return true;
1252    }
1253
1254     int getRemoteClass(BluetoothDevice device) {
1255        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1256        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1257        if (deviceProp == null) return 0;
1258
1259        return deviceProp.getBluetoothClass();
1260    }
1261
1262     ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
1263        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1264        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1265        if (deviceProp == null) return null;
1266        return deviceProp.getUuids();
1267    }
1268
1269     boolean fetchRemoteUuids(BluetoothDevice device) {
1270        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1271        mRemoteDevices.fetchUuids(device);
1272        return true;
1273    }
1274
1275     boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
1276        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1277                                       "Need BLUETOOTH ADMIN permission");
1278        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1279        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1280            return false;
1281        }
1282
1283        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1284        return pinReplyNative(addr, accept, len, pinCode);
1285    }
1286
1287     boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
1288        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1289        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1290        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1291            return false;
1292        }
1293
1294        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1295        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
1296                Utils.byteArrayToInt(passkey));
1297    }
1298
1299     boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
1300        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1301                                       "Need BLUETOOTH ADMIN permission");
1302        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1303        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1304            return false;
1305        }
1306
1307        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1308        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
1309                accept, 0);
1310    }
1311
1312     void sendConnectionStateChange(BluetoothDevice
1313            device, int profile, int state, int prevState) {
1314        // TODO(BT) permission check?
1315        // Since this is a binder call check if Bluetooth is on still
1316        if (getState() == BluetoothAdapter.STATE_OFF) return;
1317
1318        mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
1319
1320    }
1321
1322     ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
1323                                              ParcelUuid uuid, int port, int flag) {
1324        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1325        int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()),
1326                   type, Utils.uuidToByteArray(uuid), port, flag);
1327        if (fd < 0) {
1328            errorLog("Failed to connect socket");
1329            return null;
1330        }
1331        return ParcelFileDescriptor.adoptFd(fd);
1332    }
1333
1334     ParcelFileDescriptor createSocketChannel(int type, String serviceName,
1335                                                    ParcelUuid uuid, int port, int flag) {
1336        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1337        int fd =  createSocketChannelNative(type, serviceName,
1338                                 Utils.uuidToByteArray(uuid), port, flag);
1339        if (fd < 0) {
1340            errorLog("Failed to create socket channel");
1341            return null;
1342        }
1343        return ParcelFileDescriptor.adoptFd(fd);
1344    }
1345
1346    boolean configHciSnoopLog(boolean enable) {
1347        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1348        return configHciSnoopLogNative(enable);
1349    }
1350
1351     void registerCallback(IBluetoothCallback cb) {
1352         mCallbacks.register(cb);
1353      }
1354
1355      void unregisterCallback(IBluetoothCallback cb) {
1356         mCallbacks.unregister(cb);
1357      }
1358
1359    private static int convertScanModeToHal(int mode) {
1360        switch (mode) {
1361            case BluetoothAdapter.SCAN_MODE_NONE:
1362                return AbstractionLayer.BT_SCAN_MODE_NONE;
1363            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
1364                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
1365            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1366                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1367        }
1368       // errorLog("Incorrect scan mode in convertScanModeToHal");
1369        return -1;
1370    }
1371
1372    static int convertScanModeFromHal(int mode) {
1373        switch (mode) {
1374            case AbstractionLayer.BT_SCAN_MODE_NONE:
1375                return BluetoothAdapter.SCAN_MODE_NONE;
1376            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
1377                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1378            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1379                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1380        }
1381        //errorLog("Incorrect scan mode in convertScanModeFromHal");
1382        return -1;
1383    }
1384
1385    private void debugLog(String msg) {
1386        Log.d(TAG +"(" +hashCode()+")", msg);
1387    }
1388
1389    private void errorLog(String msg) {
1390        Log.e(TAG +"(" +hashCode()+")", msg);
1391    }
1392
1393    private native static void classInitNative();
1394    private native boolean initNative();
1395    private native void cleanupNative();
1396    /*package*/ native boolean enableNative();
1397    /*package*/ native boolean disableNative();
1398    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
1399    /*package*/ native boolean getAdapterPropertiesNative();
1400    /*package*/ native boolean getAdapterPropertyNative(int type);
1401    /*package*/ native boolean setAdapterPropertyNative(int type);
1402    /*package*/ native boolean
1403        setDevicePropertyNative(byte[] address, int type, byte[] val);
1404    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
1405
1406    /*package*/ native boolean createBondNative(byte[] address);
1407    /*package*/ native boolean removeBondNative(byte[] address);
1408    /*package*/ native boolean cancelBondNative(byte[] address);
1409
1410    private native boolean startDiscoveryNative();
1411    private native boolean cancelDiscoveryNative();
1412
1413    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
1414    private native boolean sspReplyNative(byte[] address, int type, boolean
1415            accept, int passkey);
1416
1417    /*package*/ native boolean getRemoteServicesNative(byte[] address);
1418
1419    // TODO(BT) move this to ../btsock dir
1420    private native int connectSocketNative(byte[] address, int type,
1421                                           byte[] uuid, int port, int flag);
1422    private native int createSocketChannelNative(int type, String serviceName,
1423                                                 byte[] uuid, int port, int flag);
1424
1425    /*package*/ native boolean configHciSnoopLogNative(boolean enable);
1426
1427    protected void finalize() {
1428        cleanup();
1429        if (TRACE_REF) {
1430            synchronized (AdapterService.class) {
1431                sRefCount--;
1432                Log.d(TAG, "REFCOUNT: FINALIZED. INSTANCE_COUNT= " + sRefCount);
1433            }
1434        }
1435    }
1436}