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