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