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