AdapterService.java revision 1c03c84f90991f6c9c740d72d91716d4b6a933e4
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, calling cleanup");
260        cleanup();
261        return super.onUnbind(intent);
262    }
263
264    public void onDestroy() {
265        debugLog("****onDestroy()********");
266    }
267
268    void processStart() {
269        if (DBG) debugLog("processStart()");
270        Class[] supportedProfileServices = Config.getSupportedProfiles();
271        //Initialize data objects
272        for (int i=0; i < supportedProfileServices.length;i++) {
273            mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);
274        }
275        mRemoteDevices = new RemoteDevices(this);
276        mBondStateMachine = new BondStateMachine(this, mAdapterProperties, mRemoteDevices);
277        mAdapterProperties.init(mRemoteDevices);
278        mJniCallbacks.init(mBondStateMachine,mRemoteDevices);
279
280        //Start Bond State Machine
281        if (DBG) {debugLog("processStart(): Starting Bond State Machine");}
282        mBondStateMachine.start();
283
284        //FIXME: Set static instance here???
285        setAdapterService(this);
286
287        //Start profile services
288        if (!mProfilesStarted && supportedProfileServices.length >0) {
289            //Startup all profile services
290            setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
291        }else {
292            if (DBG) {debugLog("processStart(): Profile Services alreay started");}
293            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
294        }
295    }
296
297    void startBluetoothDisable() {
298        mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE));
299    }
300
301    boolean stopProfileServices() {
302        Class[] supportedProfileServices = Config.getSupportedProfiles();
303        if (mProfilesStarted && supportedProfileServices.length>0) {
304            setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_OFF);
305            return true;
306        } else {
307            if (DBG) {debugLog("stopProfileServices(): No profiles services to stop or already stopped.");}
308            return false;
309        }
310    }
311
312     void updateAdapterState(int prevState, int newState){
313        if (mCallbacks !=null) {
314            int n=mCallbacks.beginBroadcast();
315            Log.d(TAG,"Broadcasting updateAdapterState() to " + n + " receivers.");
316            for (int i=0; i <n;i++) {
317                try {
318                    mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState);
319                }  catch (RemoteException e) {
320                    Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
321                }
322            }
323            mCallbacks.finishBroadcast();
324        }
325    }
326
327    void cleanup () {
328        if (DBG)debugLog("cleanup()");
329        if (mCleaningUp) {
330            Log.w(TAG,"*************service already starting to cleanup... Ignoring cleanup request.........");
331            return;
332        }
333
334        mCleaningUp = true;
335
336        if (mAdapterStateMachine != null) {
337            mAdapterStateMachine.doQuit();
338            mAdapterStateMachine.cleanup();
339        }
340
341        if (mBondStateMachine != null) {
342            mBondStateMachine.doQuit();
343            mBondStateMachine.cleanup();
344        }
345
346        if (mRemoteDevices != null) {
347            mRemoteDevices.cleanup();
348        }
349
350        if (mNativeAvailable) {
351            Log.d(TAG, "Cleaning up adapter native....");
352            cleanupNative();
353            Log.d(TAG, "Done cleaning up adapter native....");
354            mNativeAvailable=false;
355        }
356
357        if (mAdapterProperties != null) {
358            mAdapterProperties.cleanup();
359        }
360
361        if (mJniCallbacks != null) {
362            mJniCallbacks.cleanup();
363        }
364
365        if (mProfileServicesState != null) {
366            mProfileServicesState.clear();
367        }
368
369        clearAdapterService();
370
371        if (mBinder != null) {
372            mBinder.cleanup();
373            mBinder = null;  //Do not remove. Otherwise Binder leak!
374        }
375
376        if (mCallbacks !=null) {
377            mCallbacks.kill();
378        }
379
380        if (DBG)debugLog("cleanup() done");
381    }
382
383    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
384    private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
385    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 30;
386    private static final int CONNECT_OTHER_PROFILES_TIMEOUT= 6000;
387
388    private final Handler mHandler = new Handler() {
389        @Override
390        public void handleMessage(Message msg) {
391            if (DBG) debugLog("Message: " + msg.what);
392
393            switch (msg.what) {
394                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
395                    if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
396                    processProfileServiceStateChanged((String) msg.obj, msg.arg1);
397                }
398                    break;
399                case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: {
400                    if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
401                    processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
402                }
403                    break;
404                case MESSAGE_CONNECT_OTHER_PROFILES: {
405                    if (DBG) debugLog( "MESSAGE_CONNECT_OTHER_PROFILES");
406                    processConnectOtherProfiles((BluetoothDevice) msg.obj,msg.arg1);
407                }
408                    break;
409            }
410        }
411    };
412
413    @SuppressWarnings("rawtypes")
414    private void setProfileServiceState(Class[] services, int state) {
415        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
416            Log.w(TAG,"setProfileServiceState(): invalid state...Leaving...");
417            return;
418        }
419
420        int expectedCurrentState= BluetoothAdapter.STATE_OFF;
421        int pendingState = BluetoothAdapter.STATE_TURNING_ON;
422        if (state == BluetoothAdapter.STATE_OFF) {
423            expectedCurrentState= BluetoothAdapter.STATE_ON;
424            pendingState = BluetoothAdapter.STATE_TURNING_OFF;
425        }
426
427        for (int i=0; i <services.length;i++) {
428            String serviceName = services[i].getName();
429            Integer serviceState = mProfileServicesState.get(serviceName);
430            if(serviceState != null && serviceState != expectedCurrentState) {
431                Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " +
432                        serviceName+". Invalid state: " + serviceState);
433                continue;
434            }
435
436            if (DBG) {
437                Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
438                        serviceName);
439            }
440
441            mProfileServicesState.put(serviceName,pendingState);
442            Intent intent = new Intent(this,services[i]);
443            intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
444            intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
445            startService(intent);
446        }
447    }
448
449    private boolean isAvailable() {
450        return !mCleaningUp;
451    }
452
453    /**
454     * Handlers for incoming service calls
455     */
456    private AdapterServiceBinder mBinder;
457
458    /**
459     * The Binder implementation must be declared to be a static class, with
460     * the AdapterService instance passed in the constructor. Furthermore,
461     * when the AdapterService shuts down, the reference to the AdapterService
462     * must be explicitly removed.
463     *
464     * Otherwise, a memory leak can occur from repeated starting/stopping the
465     * service...Please refer to android.os.Binder for further details on
466     * why an inner instance class should be avoided.
467     *
468     */
469    private static class AdapterServiceBinder extends IBluetooth.Stub {
470        private AdapterService mService;
471
472        public AdapterServiceBinder(AdapterService svc) {
473            mService = svc;
474        }
475        public boolean cleanup() {
476            mService = null;
477            return true;
478        }
479
480        public AdapterService getService() {
481            if (mService  != null && mService.isAvailable()) {
482                return mService;
483            }
484            return null;
485        }
486        public boolean isEnabled() {
487            AdapterService service = getService();
488            if (service == null) return false;
489            return service.isEnabled();
490        }
491
492        public int getState() {
493            AdapterService service = getService();
494            if (service == null) return  BluetoothAdapter.STATE_OFF;
495            return service.getState();
496        }
497
498        public boolean enable() {
499            AdapterService service = getService();
500            if (service == null) return false;
501            return service.enable();
502        }
503
504        public boolean enableNoAutoConnect() {
505            AdapterService service = getService();
506            if (service == null) return false;
507            return service.enableNoAutoConnect();
508        }
509
510        public boolean disable() {
511            AdapterService service = getService();
512            if (service == null) return false;
513            return service.disable();
514        }
515
516        public String getAddress() {
517            AdapterService service = getService();
518            if (service == null) return null;
519            return service.getAddress();
520        }
521
522        public ParcelUuid[] getUuids() {
523            AdapterService service = getService();
524            if (service == null) return new ParcelUuid[0];
525            return service.getUuids();
526        }
527
528        public String getName() {
529            AdapterService service = getService();
530            if (service == null) return null;
531            return service.getName();
532        }
533
534        public boolean setName(String name) {
535            AdapterService service = getService();
536            if (service == null) return false;
537            return service.setName(name);
538        }
539
540        public int getScanMode() {
541            AdapterService service = getService();
542            if (service == null) return BluetoothAdapter.SCAN_MODE_NONE;
543            return service.getScanMode();
544        }
545
546        public boolean setScanMode(int mode, int duration) {
547            AdapterService service = getService();
548            if (service == null) return false;
549            return service.setScanMode(mode,duration);
550        }
551
552        public int getDiscoverableTimeout() {
553            AdapterService service = getService();
554            if (service == null) return 0;
555            return service.getDiscoverableTimeout();
556        }
557
558        public boolean setDiscoverableTimeout(int timeout) {
559            AdapterService service = getService();
560            if (service == null) return false;
561            return service.setDiscoverableTimeout(timeout);
562        }
563
564        public boolean startDiscovery() {
565            AdapterService service = getService();
566            if (service == null) return false;
567            return service.startDiscovery();
568        }
569
570        public boolean cancelDiscovery() {
571            AdapterService service = getService();
572            if (service == null) return false;
573            return service.cancelDiscovery();
574        }
575        public boolean isDiscovering() {
576            AdapterService service = getService();
577            if (service == null) return false;
578            return service.isDiscovering();
579        }
580
581        public BluetoothDevice[] getBondedDevices() {
582            AdapterService service = getService();
583            if (service == null) return new BluetoothDevice[0];
584            return service.getBondedDevices();
585        }
586
587        public int getAdapterConnectionState() {
588            AdapterService service = getService();
589            if (service == null) return BluetoothAdapter.STATE_DISCONNECTED;
590            return service.getAdapterConnectionState();
591        }
592
593        public int getProfileConnectionState(int profile) {
594            AdapterService service = getService();
595            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
596            return service.getProfileConnectionState(profile);
597        }
598
599        public boolean createBond(BluetoothDevice device) {
600            AdapterService service = getService();
601            if (service == null) return false;
602            return service.createBond(device);
603        }
604
605        public boolean cancelBondProcess(BluetoothDevice device) {
606            AdapterService service = getService();
607            if (service == null) return false;
608            return service.cancelBondProcess(device);
609        }
610
611        public boolean removeBond(BluetoothDevice device) {
612            AdapterService service = getService();
613            if (service == null) return false;
614            return service.removeBond(device);
615        }
616
617        public int getBondState(BluetoothDevice device) {
618            AdapterService service = getService();
619            if (service == null) return BluetoothDevice.BOND_NONE;
620            return service.getBondState(device);
621        }
622
623        public String getRemoteName(BluetoothDevice device) {
624            AdapterService service = getService();
625            if (service == null) return null;
626            return service.getRemoteName(device);
627        }
628
629        public String getRemoteAlias(BluetoothDevice device) {
630            AdapterService service = getService();
631            if (service == null) return null;
632            return service.getRemoteAlias(device);
633        }
634
635        public boolean setRemoteAlias(BluetoothDevice device, String name) {
636            AdapterService service = getService();
637            if (service == null) return false;
638            return service.setRemoteAlias(device, name);
639        }
640
641        public int getRemoteClass(BluetoothDevice device) {
642            AdapterService service = getService();
643            if (service == null) return 0;
644            return service.getRemoteClass(device);
645        }
646
647        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
648            AdapterService service = getService();
649            if (service == null) return null;
650            return service.getRemoteUuids(device);
651        }
652
653        public boolean fetchRemoteUuids(BluetoothDevice device) {
654            AdapterService service = getService();
655            if (service == null) return false;
656            return service.fetchRemoteUuids(device);
657        }
658
659        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
660            AdapterService service = getService();
661            if (service == null) return false;
662            return service.setPin(device, accept, len, pinCode);
663        }
664
665        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
666            AdapterService service = getService();
667            if (service == null) return false;
668            return service.setPasskey(device, accept, len, passkey);
669        }
670
671        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
672            AdapterService service = getService();
673            if (service == null) return false;
674            return service.setPairingConfirmation(device, accept);
675        }
676
677        public void sendConnectionStateChange(BluetoothDevice
678                device, int profile, int state, int prevState) {
679            AdapterService service = getService();
680            if (service == null) return;
681            service.sendConnectionStateChange(device, profile, state, prevState);
682        }
683
684        public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
685                                                  ParcelUuid uuid, int port, int flag) {
686            AdapterService service = getService();
687            if (service == null) return null;
688            return service.connectSocket(device, type, uuid, port, flag);
689        }
690
691        public ParcelFileDescriptor createSocketChannel(int type, String serviceName,
692                                                        ParcelUuid uuid, int port, int flag) {
693            AdapterService service = getService();
694            if (service == null) return null;
695            return service.createSocketChannel(type, serviceName, uuid, port, flag);
696        }
697
698        public void registerCallback(IBluetoothCallback cb) {
699            AdapterService service = getService();
700            if (service == null) return ;
701            service.registerCallback(cb);
702         }
703
704         public void unregisterCallback(IBluetoothCallback cb) {
705             AdapterService service = getService();
706             if (service == null) return ;
707             service.unregisterCallback(cb);
708         }
709    };
710
711
712    //----API Methods--------
713     boolean isEnabled() {
714        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
715        return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
716    }
717
718     int getState() {
719        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
720        if (mAdapterProperties == null){
721            return  BluetoothAdapter.STATE_OFF;
722        }
723        else {
724            debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
725            return mAdapterProperties.getState();
726        }
727    }
728
729     boolean enable() {
730        return enable (false);
731    }
732
733      public boolean enableNoAutoConnect() {
734         return enable (true);
735     }
736
737     public synchronized boolean enable(boolean quietMode) {
738         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
739                 "Need BLUETOOTH ADMIN permission");
740         if (DBG)debugLog("Enable called with quiet mode status =  " + mQuietmode);
741         mQuietmode  = quietMode;
742         Message m =
743                 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
744         mAdapterStateMachine.sendMessage(m);
745         return true;
746     }
747
748     boolean disable() {
749        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
750                "Need BLUETOOTH ADMIN permission");
751        if (DBG) debugLog("disable() called...");
752        Message m =
753                mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
754        mAdapterStateMachine.sendMessage(m);
755        return true;
756    }
757
758     String getAddress() {
759        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
760        String addrString = null;
761        byte[] address = mAdapterProperties.getAddress();
762        return Utils.getAddressStringFromByte(address);
763    }
764
765     ParcelUuid[] getUuids() {
766        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
767        return mAdapterProperties.getUuids();
768    }
769
770     String getName() {
771        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
772                "Need BLUETOOTH permission");
773        try {
774            return mAdapterProperties.getName();
775        } catch (Throwable t) {
776            Log.d(TAG, "Unexpected exception while calling getName()",t);
777        }
778        return null;
779    }
780
781     boolean setName(String name) {
782        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
783                "Need BLUETOOTH ADMIN permission");
784        return mAdapterProperties.setName(name);
785    }
786
787     int getScanMode() {
788        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
789        return mAdapterProperties.getScanMode();
790    }
791
792     boolean setScanMode(int mode, int duration) {
793        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
794        setDiscoverableTimeout(duration);
795
796        int newMode = convertScanModeToHal(mode);
797        return mAdapterProperties.setScanMode(newMode);
798    }
799
800     int getDiscoverableTimeout() {
801        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
802        return mAdapterProperties.getDiscoverableTimeout();
803    }
804
805     boolean setDiscoverableTimeout(int timeout) {
806        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
807        return mAdapterProperties.setDiscoverableTimeout(timeout);
808    }
809
810     boolean startDiscovery() {
811        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
812                "Need BLUETOOTH ADMIN permission");
813        return startDiscoveryNative();
814    }
815
816     boolean cancelDiscovery() {
817        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
818                "Need BLUETOOTH ADMIN permission");
819        return cancelDiscoveryNative();
820    }
821
822     boolean isDiscovering() {
823        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
824        return mAdapterProperties.isDiscovering();
825    }
826
827     BluetoothDevice[] getBondedDevices() {
828        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
829        debugLog("Get Bonded Devices being called");
830        return mAdapterProperties.getBondedDevices();
831    }
832
833     int getAdapterConnectionState() {
834        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
835        return mAdapterProperties.getConnectionState();
836    }
837
838     int getProfileConnectionState(int profile) {
839        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
840        return mAdapterProperties.getProfileConnectionState(profile);
841    }
842
843     boolean createBond(BluetoothDevice device) {
844        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
845            "Need BLUETOOTH ADMIN permission");
846        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
847        if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
848            return false;
849        }
850
851        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
852        msg.obj = device;
853        mBondStateMachine.sendMessage(msg);
854        return true;
855    }
856
857      public boolean isQuietModeEnabled() {
858          if (DBG) debugLog("Quiet mode Enabled = " + mQuietmode);
859          return mQuietmode;
860     }
861
862     public void autoConnect(){
863        if (getState() != BluetoothAdapter.STATE_ON){
864             errorLog("BT is not ON. Exiting autoConnect");
865             return;
866         }
867         if (isQuietModeEnabled() == false) {
868            if (DBG) debugLog( "Initiate auto connection on BT on...");
869             autoConnectHeadset();
870             autoConnectA2dp();
871         }
872         else {
873             if (DBG) debugLog( "BT is in Quiet mode. Not initiating  auto connections");
874         }
875    }
876
877     private void autoConnectHeadset(){
878        HeadsetService  hsService = HeadsetService.getHeadsetService();
879
880        BluetoothDevice bondedDevices[] = getBondedDevices();
881        if ((bondedDevices == null) ||(hsService == null)) {
882            return;
883        }
884        for (BluetoothDevice device : bondedDevices) {
885            if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
886                Log.d(TAG,"Auto Connecting Headset Profile with device " + device.toString());
887                hsService.connect(device);
888                }
889        }
890    }
891
892     private void autoConnectA2dp(){
893        A2dpService a2dpSservice = A2dpService.getA2dpService();
894        BluetoothDevice bondedDevices[] = getBondedDevices();
895        if ((bondedDevices == null) ||(a2dpSservice == null)) {
896            return;
897        }
898        for (BluetoothDevice device : bondedDevices) {
899            if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){
900                Log.d(TAG,"Auto Connecting A2DP Profile with device " + device.toString());
901                a2dpSservice.connect(device);
902                }
903        }
904    }
905
906     public void connectOtherProfile(BluetoothDevice device, int firstProfileStatus){
907        if ((mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES) == false) &&
908            (isQuietModeEnabled()== false)){
909            Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES);
910            m.obj = device;
911            m.arg1 = (int)firstProfileStatus;
912            mHandler.sendMessageDelayed(m,CONNECT_OTHER_PROFILES_TIMEOUT);
913        }
914    }
915
916     private void processConnectOtherProfiles (BluetoothDevice device, int firstProfileStatus){
917        if (getState()!= BluetoothAdapter.STATE_ON){
918            return;
919        }
920        HeadsetService  hsService = HeadsetService.getHeadsetService();
921        A2dpService a2dpService = A2dpService.getA2dpService();
922        // if any of the profile service is  null, second profile connection not required
923        if ((hsService == null) ||(a2dpService == null )){
924            return;
925        }
926        List<BluetoothDevice> a2dpConnDevList= a2dpService.getConnectedDevices();
927        List<BluetoothDevice> hfConnDevList= hsService.getConnectedDevices();
928        // Check if the device is in disconnected state and if so return
929        // We ned to connect other profile only if one of the profile is still in connected state
930        // This is required to avoide a race condition in which profiles would
931        // automaticlly connect if the disconnection is initiated within 6 seconds of connection
932        //First profile connection being rejected is an exception
933        if((hfConnDevList.isEmpty() && a2dpConnDevList.isEmpty())&&
934            (PROFILE_CONN_CONNECTED  == firstProfileStatus)){
935            return;
936        }
937        if((hfConnDevList.isEmpty()) &&
938            (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
939            hsService.connect(device);
940        }
941        else if((a2dpConnDevList.isEmpty()) &&
942            (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){
943            a2dpService.connect(device);
944        }
945    }
946
947     private void adjustOtherHeadsetPriorities(HeadsetService  hsService,
948                                                    BluetoothDevice connectedDevice) {
949        for (BluetoothDevice device : getBondedDevices()) {
950           if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT &&
951               !device.equals(connectedDevice)) {
952               hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
953           }
954        }
955     }
956
957     private void adjustOtherSinkPriorities(A2dpService a2dpService,
958                                                BluetoothDevice connectedDevice) {
959         for (BluetoothDevice device : getBondedDevices()) {
960             if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT &&
961                 !device.equals(connectedDevice)) {
962                 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
963             }
964         }
965     }
966
967     void setProfileAutoConnectionPriority (BluetoothDevice device, int profileId){
968         if (profileId == BluetoothProfile.HEADSET) {
969             HeadsetService  hsService = HeadsetService.getHeadsetService();
970             if ((hsService != null) &&
971                (BluetoothProfile.PRIORITY_AUTO_CONNECT != hsService.getPriority(device))){
972                 adjustOtherHeadsetPriorities(hsService, device);
973                 hsService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
974             }
975         }
976         else if (profileId ==  BluetoothProfile.A2DP) {
977             A2dpService a2dpService = A2dpService.getA2dpService();
978             if ((a2dpService != null) &&
979                (BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){
980                 adjustOtherSinkPriorities(a2dpService, device);
981                 a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
982             }
983         }
984    }
985
986     boolean cancelBondProcess(BluetoothDevice device) {
987        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
988        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
989        return cancelBondNative(addr);
990    }
991
992     boolean removeBond(BluetoothDevice device) {
993        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
994        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
995        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
996            return false;
997        }
998        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
999        msg.obj = device;
1000        mBondStateMachine.sendMessage(msg);
1001        return true;
1002    }
1003
1004     int getBondState(BluetoothDevice device) {
1005        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1006        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1007        if (deviceProp == null) {
1008            return BluetoothDevice.BOND_NONE;
1009        }
1010        return deviceProp.getBondState();
1011    }
1012
1013     String getRemoteName(BluetoothDevice device) {
1014        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1015        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1016        if (deviceProp == null) return null;
1017        return deviceProp.getName();
1018    }
1019
1020     String getRemoteAlias(BluetoothDevice device) {
1021        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1022        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1023        if (deviceProp == null) return null;
1024        return deviceProp.getAlias();
1025    }
1026
1027     boolean setRemoteAlias(BluetoothDevice device, String name) {
1028        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1029        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1030        if (deviceProp == null) return false;
1031        deviceProp.setAlias(name);
1032        return true;
1033    }
1034
1035     int getRemoteClass(BluetoothDevice device) {
1036        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1037        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1038        if (deviceProp == null) return 0;
1039
1040        return deviceProp.getBluetoothClass();
1041    }
1042
1043     ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
1044        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1045        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1046        if (deviceProp == null) return null;
1047        return deviceProp.getUuids();
1048    }
1049
1050     boolean fetchRemoteUuids(BluetoothDevice device) {
1051        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1052        mRemoteDevices.fetchUuids(device);
1053        return true;
1054    }
1055
1056     boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
1057        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1058        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1059        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1060            return false;
1061        }
1062
1063        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1064        return pinReplyNative(addr, accept, len, pinCode);
1065    }
1066
1067     boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
1068        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1069        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1070        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1071            return false;
1072        }
1073
1074        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1075        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
1076                Utils.byteArrayToInt(passkey));
1077    }
1078
1079     boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
1080        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1081        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
1082        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
1083            return false;
1084        }
1085
1086        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
1087        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
1088                accept, 0);
1089    }
1090
1091     void sendConnectionStateChange(BluetoothDevice
1092            device, int profile, int state, int prevState) {
1093        // TODO(BT) permission check?
1094        // Since this is a binder call check if Bluetooth is on still
1095        if (getState() == BluetoothAdapter.STATE_OFF) return;
1096
1097        mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
1098
1099    }
1100
1101     ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
1102                                              ParcelUuid uuid, int port, int flag) {
1103        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1104        int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()),
1105                   type, Utils.uuidToByteArray(uuid), port, flag);
1106        if (fd < 0) {
1107            errorLog("Failed to connect socket");
1108            return null;
1109        }
1110        return ParcelFileDescriptor.adoptFd(fd);
1111    }
1112
1113     ParcelFileDescriptor createSocketChannel(int type, String serviceName,
1114                                                    ParcelUuid uuid, int port, int flag) {
1115        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1116        int fd =  createSocketChannelNative(type, serviceName,
1117                                 Utils.uuidToByteArray(uuid), port, flag);
1118        if (fd < 0) {
1119            errorLog("Failed to create socket channel");
1120            return null;
1121        }
1122        return ParcelFileDescriptor.adoptFd(fd);
1123    }
1124
1125     void registerCallback(IBluetoothCallback cb) {
1126         mCallbacks.register(cb);
1127      }
1128
1129      void unregisterCallback(IBluetoothCallback cb) {
1130         mCallbacks.unregister(cb);
1131      }
1132
1133    private static int convertScanModeToHal(int mode) {
1134        switch (mode) {
1135            case BluetoothAdapter.SCAN_MODE_NONE:
1136                return AbstractionLayer.BT_SCAN_MODE_NONE;
1137            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
1138                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
1139            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1140                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1141        }
1142       // errorLog("Incorrect scan mode in convertScanModeToHal");
1143        return -1;
1144    }
1145
1146    static int convertScanModeFromHal(int mode) {
1147        switch (mode) {
1148            case AbstractionLayer.BT_SCAN_MODE_NONE:
1149                return BluetoothAdapter.SCAN_MODE_NONE;
1150            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
1151                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1152            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1153                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1154        }
1155        //errorLog("Incorrect scan mode in convertScanModeFromHal");
1156        return -1;
1157    }
1158
1159    private void debugLog(String msg) {
1160        Log.d(TAG +"(" +hashCode()+")", msg);
1161    }
1162
1163    private void errorLog(String msg) {
1164        Log.e(TAG +"(" +hashCode()+")", msg);
1165    }
1166
1167    private native static void classInitNative();
1168    private native boolean initNative();
1169    private native void cleanupNative();
1170    /*package*/ native boolean enableNative();
1171    /*package*/ native boolean disableNative();
1172    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
1173    /*package*/ native boolean getAdapterPropertiesNative();
1174    /*package*/ native boolean getAdapterPropertyNative(int type);
1175    /*package*/ native boolean setAdapterPropertyNative(int type);
1176    /*package*/ native boolean
1177        setDevicePropertyNative(byte[] address, int type, byte[] val);
1178    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
1179
1180    /*package*/ native boolean createBondNative(byte[] address);
1181    /*package*/ native boolean removeBondNative(byte[] address);
1182    /*package*/ native boolean cancelBondNative(byte[] address);
1183
1184    private native boolean startDiscoveryNative();
1185    private native boolean cancelDiscoveryNative();
1186
1187    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
1188    private native boolean sspReplyNative(byte[] address, int type, boolean
1189            accept, int passkey);
1190
1191    /*package*/ native boolean getRemoteServicesNative(byte[] address);
1192
1193    // TODO(BT) move this to ../btsock dir
1194    private native int connectSocketNative(byte[] address, int type,
1195                                           byte[] uuid, int port, int flag);
1196    private native int createSocketChannelNative(int type, String serviceName,
1197                                                 byte[] uuid, int port, int flag);
1198
1199    protected void finalize() {
1200        cleanup();
1201        if (TRACE_REF) {
1202            synchronized (AdapterService.class) {
1203                sRefCount--;
1204                Log.d(TAG, "REFCOUNT: FINALIZED. INSTANCE_COUNT= " + sRefCount);
1205            }
1206        }
1207    }
1208}
1209