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