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