Home | History | Annotate | Download | only in server
      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 package com.android.server;
     18 
     19 import android.app.ActivityManager;
     20 import android.bluetooth.BluetoothAdapter;
     21 import android.bluetooth.IBluetooth;
     22 import android.bluetooth.IBluetoothCallback;
     23 import android.bluetooth.IBluetoothManager;
     24 import android.bluetooth.IBluetoothManagerCallback;
     25 import android.bluetooth.IBluetoothStateChangeCallback;
     26 import android.content.BroadcastReceiver;
     27 import android.content.ComponentName;
     28 import android.content.ContentResolver;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.content.IntentFilter;
     32 import android.content.ServiceConnection;
     33 import android.os.Binder;
     34 import android.os.Handler;
     35 import android.os.HandlerThread;
     36 import android.os.IBinder;
     37 import android.os.Looper;
     38 import android.os.Message;
     39 import android.os.Process;
     40 import android.os.RemoteCallbackList;
     41 import android.os.RemoteException;
     42 import android.os.SystemClock;
     43 import android.os.UserHandle;
     44 import android.provider.Settings;
     45 import android.util.Log;
     46 import java.util.ArrayList;
     47 import java.util.List;
     48 class BluetoothManagerService extends IBluetoothManager.Stub {
     49     private static final String TAG = "BluetoothManagerService";
     50     private static final boolean DBG = true;
     51 
     52     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     53     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
     54     private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
     55     private static final String EXTRA_ACTION="action";
     56     private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
     57     private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
     58     private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
     59     private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
     60     private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
     61     //Maximum msec to wait for service restart
     62     private static final int SERVICE_RESTART_TIME_MS = 200;
     63     //Maximum msec to delay MESSAGE_USER_SWITCHED
     64     private static final int USER_SWITCHED_TIME_MS = 200;
     65 
     66     private static final int MESSAGE_ENABLE = 1;
     67     private static final int MESSAGE_DISABLE = 2;
     68     private static final int MESSAGE_REGISTER_ADAPTER = 20;
     69     private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
     70     private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
     71     private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
     72     private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
     73     private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
     74     private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
     75     private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
     76     private static final int MESSAGE_TIMEOUT_BIND =100;
     77     private static final int MESSAGE_TIMEOUT_UNBIND =101;
     78     private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
     79     private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
     80     private static final int MESSAGE_USER_SWITCHED = 300;
     81     private static final int MAX_SAVE_RETRIES=3;
     82 
     83     private final Context mContext;
     84 
     85     // Locks are not provided for mName and mAddress.
     86     // They are accessed in handler or broadcast receiver, same thread context.
     87     private String mAddress;
     88     private String mName;
     89     private final ContentResolver mContentResolver;
     90     private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
     91     private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
     92     private IBluetooth mBluetooth;
     93     private boolean mBinding;
     94     private boolean mUnbinding;
     95     private boolean mQuietEnable = false;
     96     private boolean mEnable;
     97     private int mState;
     98     private HandlerThread mThread;
     99     private final BluetoothHandler mHandler;
    100 
    101     private void registerForAirplaneMode(IntentFilter filter) {
    102         final ContentResolver resolver = mContext.getContentResolver();
    103         final String airplaneModeRadios = Settings.Global.getString(resolver,
    104                 Settings.Global.AIRPLANE_MODE_RADIOS);
    105         final String toggleableRadios = Settings.Global.getString(resolver,
    106                 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
    107         boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
    108                 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
    109         if (mIsAirplaneSensitive) {
    110             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    111         }
    112     }
    113 
    114     private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
    115         @Override
    116         public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
    117             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
    118             mHandler.sendMessage(msg);
    119         }
    120     };
    121 
    122     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    123         @Override
    124         public void onReceive(Context context, Intent intent) {
    125             String action = intent.getAction();
    126             if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
    127                 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
    128                 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
    129                 if (newName != null) {
    130                     storeNameAndAddress(newName, null);
    131                 }
    132             } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
    133                 if (isAirplaneModeOn()) {
    134                     // disable without persisting the setting
    135                     mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE,
    136                            0, 0));
    137                 } else if (isBluetoothPersistedStateOn()) {
    138                     // enable without persisting the setting
    139                     mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
    140                            0, 0));
    141                 }
    142             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
    143                 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
    144                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
    145             }
    146         }
    147     };
    148 
    149     BluetoothManagerService(Context context) {
    150         mThread = new HandlerThread("BluetoothManager");
    151         mThread.start();
    152         mHandler = new BluetoothHandler(mThread.getLooper());
    153 
    154         mContext = context;
    155         mBluetooth = null;
    156         mBinding = false;
    157         mUnbinding = false;
    158         mEnable = false;
    159         mState = BluetoothAdapter.STATE_OFF;
    160         mAddress = null;
    161         mName = null;
    162         mContentResolver = context.getContentResolver();
    163         mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
    164         mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
    165         IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
    166         filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
    167         filter.addAction(Intent.ACTION_USER_SWITCHED);
    168         registerForAirplaneMode(filter);
    169         mContext.registerReceiver(mReceiver, filter);
    170         boolean airplaneModeOn = isAirplaneModeOn();
    171         boolean bluetoothOn = isBluetoothPersistedStateOn();
    172         loadStoredNameAndAddress();
    173         if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
    174         if (bluetoothOn) {
    175             //Enable
    176             if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
    177             enableHelper();
    178         }
    179 
    180         if (!isNameAndAddressSet()) {
    181             //Sync the Bluetooth name and address from the Bluetooth Adapter
    182             if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
    183             getNameAndAddress();
    184         }
    185     }
    186 
    187     /**
    188      *  Returns true if airplane mode is currently on
    189      */
    190     private final boolean isAirplaneModeOn() {
    191         return Settings.Global.getInt(mContext.getContentResolver(),
    192                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
    193     }
    194 
    195     /**
    196      *  Returns true if the Bluetooth saved state is "on"
    197      */
    198     private final boolean isBluetoothPersistedStateOn() {
    199         return Settings.Global.getInt(mContentResolver,
    200                 Settings.Global.BLUETOOTH_ON, 0) ==1;
    201     }
    202 
    203     /**
    204      *  Save the Bluetooth on/off state
    205      *
    206      */
    207     private void persistBluetoothSetting(boolean setOn) {
    208         Settings.Global.putInt(mContext.getContentResolver(),
    209                                Settings.Global.BLUETOOTH_ON,
    210                                setOn ? 1 : 0);
    211     }
    212 
    213     /**
    214      * Returns true if the Bluetooth Adapter's name and address is
    215      * locally cached
    216      * @return
    217      */
    218     private boolean isNameAndAddressSet() {
    219         return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
    220     }
    221 
    222     /**
    223      * Retrieve the Bluetooth Adapter's name and address and save it in
    224      * in the local cache
    225      */
    226     private void loadStoredNameAndAddress() {
    227         if (DBG) Log.d(TAG, "Loading stored name and address");
    228         if (mContext.getResources().getBoolean
    229             (com.android.internal.R.bool.config_bluetooth_address_validation) &&
    230              Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
    231             // if the valid flag is not set, don't load the address and name
    232             if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
    233             return;
    234         }
    235         mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
    236         mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
    237         if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
    238     }
    239 
    240     /**
    241      * Save the Bluetooth name and address in the persistent store.
    242      * Only non-null values will be saved.
    243      * @param name
    244      * @param address
    245      */
    246     private void storeNameAndAddress(String name, String address) {
    247         if (name != null) {
    248             Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
    249             mName = name;
    250             if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
    251                 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
    252         }
    253 
    254         if (address != null) {
    255             Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
    256             mAddress=address;
    257             if (DBG)  Log.d(TAG,"Stored Bluetoothaddress: " +
    258                 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
    259         }
    260 
    261         if ((name != null) && (address != null)) {
    262             Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
    263         }
    264     }
    265 
    266     public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
    267         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
    268         msg.obj = callback;
    269         mHandler.sendMessage(msg);
    270         synchronized(mConnection) {
    271             return mBluetooth;
    272         }
    273     }
    274 
    275     public void unregisterAdapter(IBluetoothManagerCallback callback) {
    276         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
    277                                                 "Need BLUETOOTH permission");
    278         Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
    279         msg.obj = callback;
    280         mHandler.sendMessage(msg);
    281     }
    282 
    283     public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
    284         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
    285                                                 "Need BLUETOOTH permission");
    286         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
    287         msg.obj = callback;
    288         mHandler.sendMessage(msg);
    289     }
    290 
    291     public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
    292         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
    293                                                 "Need BLUETOOTH permission");
    294         Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
    295         msg.obj = callback;
    296         mHandler.sendMessage(msg);
    297     }
    298 
    299     public boolean isEnabled() {
    300         if (!checkIfCallerIsForegroundUser()) {
    301             Log.w(TAG,"isEnabled(): not allowed for non-active user");
    302             return false;
    303         }
    304 
    305         synchronized(mConnection) {
    306             try {
    307                 return (mBluetooth != null && mBluetooth.isEnabled());
    308             } catch (RemoteException e) {
    309                 Log.e(TAG, "isEnabled()", e);
    310             }
    311         }
    312         return false;
    313     }
    314 
    315     public void getNameAndAddress() {
    316         if (DBG) {
    317             Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
    318                   " mBinding = " + mBinding);
    319         }
    320         Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
    321         mHandler.sendMessage(msg);
    322     }
    323     public boolean enableNoAutoConnect()
    324     {
    325         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    326                                                 "Need BLUETOOTH ADMIN permission");
    327 
    328         if (!checkIfCallerIsForegroundUser()) {
    329             Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user");
    330             return false;
    331         }
    332 
    333         if (DBG) {
    334             Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
    335                     " mBinding = " + mBinding);
    336         }
    337         if (Binder.getCallingUid() != Process.NFC_UID) {
    338             throw new SecurityException("no permission to enable Bluetooth quietly");
    339         }
    340         Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
    341         msg.arg1=0; //No persist
    342         msg.arg2=1; //Quiet mode
    343         mHandler.sendMessage(msg);
    344         return true;
    345 
    346     }
    347     public boolean enable() {
    348         if (!checkIfCallerIsForegroundUser()) {
    349             Log.w(TAG,"enable(): not allowed for non-active user");
    350             return false;
    351         }
    352 
    353         return enableHelper();
    354     }
    355 
    356     public boolean disable(boolean persist) {
    357         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    358                                                 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
    359 
    360         if (!checkIfCallerIsForegroundUser()) {
    361             Log.w(TAG,"disable(): not allowed for non-active user");
    362             return false;
    363         }
    364 
    365         if (DBG) {
    366             Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
    367                 " mBinding = " + mBinding);
    368         }
    369 
    370         Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
    371         msg.arg1=(persist?1:0);
    372         mHandler.sendMessage(msg);
    373         return true;
    374     }
    375 
    376     public void unbindAndFinish() {
    377         if (DBG) {
    378             Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
    379                 " mBinding = " + mBinding);
    380         }
    381 
    382         synchronized (mConnection) {
    383             if (mUnbinding) return;
    384             mUnbinding = true;
    385             if (mBluetooth != null) {
    386                 if (!mConnection.isGetNameAddressOnly()) {
    387                     //Unregister callback object
    388                     try {
    389                         mBluetooth.unregisterCallback(mBluetoothCallback);
    390                     } catch (RemoteException re) {
    391                         Log.e(TAG, "Unable to unregister BluetoothCallback",re);
    392                     }
    393                 }
    394                 if (DBG) Log.d(TAG, "Sending unbind request.");
    395                 mBluetooth = null;
    396                 //Unbind
    397                 mContext.unbindService(mConnection);
    398                 mUnbinding = false;
    399                 mBinding = false;
    400             } else {
    401                 mUnbinding=false;
    402             }
    403         }
    404     }
    405 
    406     private void sendBluetoothStateCallback(boolean isUp) {
    407         int n = mStateChangeCallbacks.beginBroadcast();
    408         if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
    409         for (int i=0; i <n;i++) {
    410             try {
    411                 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
    412             } catch (RemoteException e) {
    413                 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
    414             }
    415         }
    416         mStateChangeCallbacks.finishBroadcast();
    417     }
    418 
    419     /**
    420      * Inform BluetoothAdapter instances that Adapter service is up
    421      */
    422     private void sendBluetoothServiceUpCallback() {
    423         if (!mConnection.isGetNameAddressOnly()) {
    424             if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
    425             int n = mCallbacks.beginBroadcast();
    426             Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
    427             for (int i=0; i <n;i++) {
    428                 try {
    429                     mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
    430                 }  catch (RemoteException e) {
    431                     Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
    432                 }
    433             }
    434             mCallbacks.finishBroadcast();
    435         }
    436     }
    437     /**
    438      * Inform BluetoothAdapter instances that Adapter service is down
    439      */
    440     private void sendBluetoothServiceDownCallback() {
    441         if (!mConnection.isGetNameAddressOnly()) {
    442             if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
    443             int n = mCallbacks.beginBroadcast();
    444             Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
    445             for (int i=0; i <n;i++) {
    446                 try {
    447                     mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
    448                 }  catch (RemoteException e) {
    449                     Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
    450                 }
    451             }
    452             mCallbacks.finishBroadcast();
    453         }
    454     }
    455     public String getAddress() {
    456         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    457                                                 "Need BLUETOOTH ADMIN permission");
    458 
    459         if (!checkIfCallerIsForegroundUser()) {
    460             Log.w(TAG,"getAddress(): not allowed for non-active user");
    461             return mAddress;
    462         }
    463 
    464         synchronized(mConnection) {
    465             if (mBluetooth != null) {
    466                 try {
    467                     return mBluetooth.getAddress();
    468                 } catch (RemoteException e) {
    469                     Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
    470                 }
    471             }
    472         }
    473         // mAddress is accessed from outside.
    474         // It is alright without a lock. Here, bluetooth is off, no other thread is
    475         // changing mAddress
    476         return mAddress;
    477     }
    478 
    479     public String getName() {
    480         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    481                                                 "Need BLUETOOTH ADMIN permission");
    482 
    483         if (!checkIfCallerIsForegroundUser()) {
    484             Log.w(TAG,"getName(): not allowed for non-active user");
    485             return mName;
    486         }
    487 
    488         synchronized(mConnection) {
    489             if (mBluetooth != null) {
    490                 try {
    491                     return mBluetooth.getName();
    492                 } catch (RemoteException e) {
    493                     Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
    494                 }
    495             }
    496         }
    497         // mName is accessed from outside.
    498         // It alright without a lock. Here, bluetooth is off, no other thread is
    499         // changing mName
    500         return mName;
    501     }
    502 
    503     private class BluetoothServiceConnection implements ServiceConnection {
    504 
    505         private boolean mGetNameAddressOnly;
    506 
    507         public void setGetNameAddressOnly(boolean getOnly) {
    508             mGetNameAddressOnly = getOnly;
    509         }
    510 
    511         public boolean isGetNameAddressOnly() {
    512             return mGetNameAddressOnly;
    513         }
    514 
    515         public void onServiceConnected(ComponentName className, IBinder service) {
    516             if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
    517             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
    518             msg.obj = service;
    519             mHandler.sendMessage(msg);
    520         }
    521 
    522         public void onServiceDisconnected(ComponentName className) {
    523             // Called if we unexpected disconnected.
    524             if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
    525             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
    526             mHandler.sendMessage(msg);
    527         }
    528     }
    529 
    530     private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
    531 
    532     private class BluetoothHandler extends Handler {
    533         public BluetoothHandler(Looper looper) {
    534             super(looper);
    535         }
    536 
    537         @Override
    538         public void handleMessage(Message msg) {
    539             if (DBG) Log.d (TAG, "Message: " + msg.what);
    540             switch (msg.what) {
    541                 case MESSAGE_GET_NAME_AND_ADDRESS: {
    542                     if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
    543                     synchronized(mConnection) {
    544                         //Start bind request
    545                         if ((mBluetooth == null) && (!mBinding)) {
    546                             if (DBG) Log.d(TAG, "Binding to service to get name and address");
    547                             mConnection.setGetNameAddressOnly(true);
    548                             //Start bind timeout and bind
    549                             Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
    550                             mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
    551                             Intent i = new Intent(IBluetooth.class.getName());
    552                             if (!mContext.bindService(i, mConnection,
    553                                   Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
    554                                 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
    555                                 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
    556                             } else {
    557                                 mBinding = true;
    558                             }
    559                         }
    560                         else {
    561                             Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
    562                             saveMsg.arg1 = 0;
    563                             if (mBluetooth != null) {
    564                                 mHandler.sendMessage(saveMsg);
    565                             } else {
    566                                 // if enable is also called to bind the service
    567                                 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
    568                                 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
    569                             }
    570                         }
    571                     }
    572                     break;
    573                 }
    574                 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
    575                     boolean unbind = false;
    576                     if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
    577                     synchronized(mConnection) {
    578                         if (!mEnable && mBluetooth != null) {
    579                             try {
    580                                 mBluetooth.enable();
    581                             } catch (RemoteException e) {
    582                                 Log.e(TAG,"Unable to call enable()",e);
    583                             }
    584                         }
    585                     }
    586                     if (mBluetooth != null) waitForOnOff(true, false);
    587                     synchronized(mConnection) {
    588                         if (mBluetooth != null) {
    589                             String name =  null;
    590                             String address = null;
    591                             try {
    592                                 name =  mBluetooth.getName();
    593                                 address = mBluetooth.getAddress();
    594                             } catch (RemoteException re) {
    595                                 Log.e(TAG,"",re);
    596                             }
    597 
    598                             if (name != null && address != null) {
    599                                 storeNameAndAddress(name,address);
    600                                 if (mConnection.isGetNameAddressOnly()) {
    601                                     unbind = true;
    602                                 }
    603                             } else {
    604                                 if (msg.arg1 < MAX_SAVE_RETRIES) {
    605                                     Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
    606                                     retryMsg.arg1= 1+msg.arg1;
    607                                     if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
    608                                     mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
    609                                 } else {
    610                                     Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
    611                                     if (mConnection.isGetNameAddressOnly()) {
    612                                         unbind = true;
    613                                     }
    614                                 }
    615                             }
    616                             if (!mEnable) {
    617                                 try {
    618                                     mBluetooth.disable();
    619                                 } catch (RemoteException e) {
    620                                     Log.e(TAG,"Unable to call disable()",e);
    621                                 }
    622                             }
    623                         } else {
    624                             // rebind service by Request GET NAME AND ADDRESS
    625                             // if service is unbinded by disable or
    626                             // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
    627                             Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
    628                             mHandler.sendMessage(getMsg);
    629                         }
    630                     }
    631                     if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
    632                     if (unbind) {
    633                         unbindAndFinish();
    634                     }
    635                     break;
    636                 }
    637                 case MESSAGE_ENABLE:
    638                     if (DBG) {
    639                         Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
    640                     }
    641                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
    642                     mEnable = true;
    643                     handleEnable(msg.arg1 == 1, msg.arg2 ==1);
    644                     break;
    645 
    646                 case MESSAGE_DISABLE:
    647                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
    648                     if (mEnable && mBluetooth != null) {
    649                         waitForOnOff(true, false);
    650                         mEnable = false;
    651                         handleDisable(msg.arg1 == 1);
    652                         waitForOnOff(false, false);
    653                     } else {
    654                         mEnable = false;
    655                         handleDisable(msg.arg1 == 1);
    656                     }
    657                     break;
    658 
    659                 case MESSAGE_REGISTER_ADAPTER:
    660                 {
    661                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
    662                     boolean added = mCallbacks.register(callback);
    663                     Log.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
    664                 }
    665                     break;
    666                 case MESSAGE_UNREGISTER_ADAPTER:
    667                 {
    668                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
    669                     boolean removed = mCallbacks.unregister(callback);
    670                     Log.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
    671                     break;
    672                 }
    673                 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
    674                 {
    675                     IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
    676                     mStateChangeCallbacks.register(callback);
    677                     break;
    678                 }
    679                 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
    680                 {
    681                     IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
    682                     mStateChangeCallbacks.unregister(callback);
    683                     break;
    684                 }
    685                 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
    686                 {
    687                     if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
    688 
    689                     //Remove timeout
    690                     mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
    691 
    692                     IBinder service = (IBinder) msg.obj;
    693                     synchronized(mConnection) {
    694                         mBinding = false;
    695                         mBluetooth = IBluetooth.Stub.asInterface(service);
    696 
    697                         if (mConnection.isGetNameAddressOnly()) {
    698                             //Request GET NAME AND ADDRESS
    699                             Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
    700                             mHandler.sendMessage(getMsg);
    701                             if (!mEnable) return;
    702                         }
    703 
    704                         mConnection.setGetNameAddressOnly(false);
    705                         //Register callback object
    706                         try {
    707                             mBluetooth.registerCallback(mBluetoothCallback);
    708                         } catch (RemoteException re) {
    709                             Log.e(TAG, "Unable to register BluetoothCallback",re);
    710                         }
    711                         //Inform BluetoothAdapter instances that service is up
    712                         sendBluetoothServiceUpCallback();
    713 
    714                         //Do enable request
    715                         try {
    716                             if (mQuietEnable == false) {
    717                                 if(!mBluetooth.enable()) {
    718                                     Log.e(TAG,"IBluetooth.enable() returned false");
    719                                 }
    720                             }
    721                             else
    722                             {
    723                                 if(!mBluetooth.enableNoAutoConnect()) {
    724                                     Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
    725                                 }
    726                             }
    727                         } catch (RemoteException e) {
    728                             Log.e(TAG,"Unable to call enable()",e);
    729                         }
    730                     }
    731 
    732                     if (!mEnable) {
    733                         waitForOnOff(true, false);
    734                         handleDisable(false);
    735                         waitForOnOff(false, false);
    736                     }
    737                     break;
    738                 }
    739                 case MESSAGE_TIMEOUT_BIND: {
    740                     Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
    741                     synchronized(mConnection) {
    742                         mBinding = false;
    743                     }
    744                     break;
    745                 }
    746                 case MESSAGE_BLUETOOTH_STATE_CHANGE:
    747                 {
    748                     int prevState = msg.arg1;
    749                     int newState = msg.arg2;
    750                     if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
    751                     mState = newState;
    752                     bluetoothStateChangeHandler(prevState, newState);
    753                     break;
    754                 }
    755                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
    756                 {
    757                     Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
    758                     synchronized(mConnection) {
    759                         // if service is unbinded already, do nothing and return
    760                         if (mBluetooth == null) return;
    761                         mBluetooth = null;
    762                     }
    763 
    764                     if (mEnable) {
    765                         mEnable = false;
    766                         // Send a Bluetooth Restart message
    767                         Message restartMsg = mHandler.obtainMessage(
    768                             MESSAGE_RESTART_BLUETOOTH_SERVICE);
    769                         mHandler.sendMessageDelayed(restartMsg,
    770                             SERVICE_RESTART_TIME_MS);
    771                     }
    772 
    773                     if (!mConnection.isGetNameAddressOnly()) {
    774                         sendBluetoothServiceDownCallback();
    775 
    776                         // Send BT state broadcast to update
    777                         // the BT icon correctly
    778                         bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
    779                                                     BluetoothAdapter.STATE_TURNING_OFF);
    780                         mState = BluetoothAdapter.STATE_OFF;
    781                     }
    782                     break;
    783                 }
    784                 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
    785                 {
    786                     Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
    787                         +" Restart IBluetooth service");
    788                     /* Enable without persisting the setting as
    789                      it doesnt change when IBluetooth
    790                      service restarts */
    791                     mEnable = true;
    792                     handleEnable(false, mQuietEnable);
    793                     break;
    794                 }
    795 
    796                 case MESSAGE_TIMEOUT_UNBIND:
    797                 {
    798                     Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
    799                     synchronized(mConnection) {
    800                         mUnbinding = false;
    801                     }
    802                     break;
    803                 }
    804 
    805                 case MESSAGE_USER_SWITCHED:
    806                 {
    807                     if (DBG) {
    808                         Log.d(TAG, "MESSAGE_USER_SWITCHED");
    809                     }
    810                     mHandler.removeMessages(MESSAGE_USER_SWITCHED);
    811                     /* disable and enable BT when detect a user switch */
    812                     if (mEnable && mBluetooth != null) {
    813                         synchronized (mConnection) {
    814                             if (mBluetooth != null) {
    815                                 //Unregister callback object
    816                                 try {
    817                                     mBluetooth.unregisterCallback(mBluetoothCallback);
    818                                 } catch (RemoteException re) {
    819                                     Log.e(TAG, "Unable to unregister",re);
    820                                 }
    821                             }
    822                         }
    823                         mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
    824 
    825                         waitForOnOff(true, false);
    826 
    827                         bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
    828 
    829                         // disable
    830                         handleDisable(false);
    831 
    832                         waitForOnOff(false, true);
    833 
    834                         bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
    835                                                     BluetoothAdapter.STATE_OFF);
    836                         mState = BluetoothAdapter.STATE_OFF;
    837                         sendBluetoothServiceDownCallback();
    838                         synchronized (mConnection) {
    839                             if (mBluetooth != null) {
    840                                 mBluetooth = null;
    841                                 //Unbind
    842                                 mContext.unbindService(mConnection);
    843                             }
    844                         }
    845                         SystemClock.sleep(100);
    846 
    847                         // enable
    848                         handleEnable(false, mQuietEnable);
    849 		    } else if (mBinding || mBluetooth != null) {
    850                         Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
    851                         userMsg.arg2 = 1 + msg.arg2;
    852                         // if user is switched when service is being binding
    853                         // delay sending MESSAGE_USER_SWITCHED
    854                         mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
    855                         if (DBG) {
    856                             Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
    857                         }
    858 		    }
    859                     break;
    860                 }
    861             }
    862         }
    863     }
    864 
    865     private void handleEnable(boolean persist, boolean quietMode) {
    866         if (persist) {
    867             persistBluetoothSetting(true);
    868         }
    869 
    870         mQuietEnable = quietMode;
    871 
    872         synchronized(mConnection) {
    873             if ((mBluetooth == null) && (!mBinding)) {
    874                 //Start bind timeout and bind
    875                 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
    876                 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
    877                 mConnection.setGetNameAddressOnly(false);
    878                 Intent i = new Intent(IBluetooth.class.getName());
    879                 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,
    880                                           UserHandle.USER_CURRENT)) {
    881                     mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
    882                     Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
    883                 } else {
    884                     mBinding = true;
    885                 }
    886             } else if (mBluetooth != null) {
    887                 if (mConnection.isGetNameAddressOnly()) {
    888                     // if GetNameAddressOnly is set, we can clear this flag,
    889                     // so the service won't be unbind
    890                     // after name and address are saved
    891                     mConnection.setGetNameAddressOnly(false);
    892                     //Register callback object
    893                     try {
    894                         mBluetooth.registerCallback(mBluetoothCallback);
    895                     } catch (RemoteException re) {
    896                         Log.e(TAG, "Unable to register BluetoothCallback",re);
    897                     }
    898                     //Inform BluetoothAdapter instances that service is up
    899                     sendBluetoothServiceUpCallback();
    900                 }
    901 
    902                 //Enable bluetooth
    903                 try {
    904                     if (!mQuietEnable) {
    905                         if(!mBluetooth.enable()) {
    906                             Log.e(TAG,"IBluetooth.enable() returned false");
    907                         }
    908                     }
    909                     else {
    910                         if(!mBluetooth.enableNoAutoConnect()) {
    911                             Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
    912                         }
    913                     }
    914                 } catch (RemoteException e) {
    915                     Log.e(TAG,"Unable to call enable()",e);
    916                 }
    917             }
    918         }
    919     }
    920 
    921     private void handleDisable(boolean persist) {
    922         if (persist) {
    923             persistBluetoothSetting(false);
    924         }
    925 
    926         synchronized(mConnection) {
    927             // don't need to disable if GetNameAddressOnly is set,
    928             // service will be unbinded after Name and Address are saved
    929             if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
    930                 if (DBG) Log.d(TAG,"Sending off request.");
    931 
    932                 try {
    933                     if(!mBluetooth.disable()) {
    934                         Log.e(TAG,"IBluetooth.disable() returned false");
    935                     }
    936                 } catch (RemoteException e) {
    937                     Log.e(TAG,"Unable to call disable()",e);
    938                 }
    939             }
    940         }
    941     }
    942 
    943     private boolean checkIfCallerIsForegroundUser() {
    944         int foregroundUser;
    945         int callingUser = UserHandle.getCallingUserId();
    946         long callingIdentity = Binder.clearCallingIdentity();
    947         boolean valid = false;
    948         try {
    949             foregroundUser = ActivityManager.getCurrentUser();
    950             valid = (callingUser == foregroundUser);
    951             if (DBG) {
    952                 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
    953                     + " callingUser=" + callingUser
    954                     + " foregroundUser=" + foregroundUser);
    955             }
    956         } finally {
    957             Binder.restoreCallingIdentity(callingIdentity);
    958         }
    959         return valid;
    960     }
    961 
    962     private boolean enableHelper() {
    963         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    964                                                 "Need BLUETOOTH ADMIN permission");
    965         if (DBG) {
    966             Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
    967                     " mBinding = " + mBinding);
    968         }
    969 
    970         Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
    971         msg.arg1=1; //persist
    972         msg.arg2=0; //No Quiet Mode
    973         mHandler.sendMessage(msg);
    974         return true;
    975     }
    976 
    977     private void bluetoothStateChangeHandler(int prevState, int newState) {
    978         if (prevState != newState) {
    979             //Notify all proxy objects first of adapter state change
    980             if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
    981                 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
    982                 sendBluetoothStateCallback(isUp);
    983 
    984                 //If Bluetooth is off, send service down event to proxy objects, and unbind
    985                 if (!isUp) {
    986                     //Only unbind with mEnable flag not set
    987                     //For race condition: disable and enable back-to-back
    988                     //Avoid unbind right after enable due to callback from disable
    989                     if ((!mEnable) && (mBluetooth != null)) {
    990                         sendBluetoothServiceDownCallback();
    991                         unbindAndFinish();
    992                     }
    993                 }
    994             }
    995 
    996             //Send broadcast message to everyone else
    997             Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
    998             intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
    999             intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
   1000             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1001             if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
   1002             mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
   1003                     BLUETOOTH_PERM);
   1004         }
   1005     }
   1006 
   1007     /**
   1008      *  if on is true, wait for state become ON
   1009      *  if off is true, wait for state become OFF
   1010      *  if both on and off are false, wait for state not ON
   1011      */
   1012     private boolean waitForOnOff(boolean on, boolean off) {
   1013         int i = 0;
   1014         while (i < 10) {
   1015             synchronized(mConnection) {
   1016                 try {
   1017                     if (mBluetooth == null) break;
   1018                     if (on) {
   1019                         if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
   1020                     } else if (off) {
   1021                         if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
   1022 		    } else {
   1023                         if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
   1024 		    }
   1025                 } catch (RemoteException e) {
   1026                     Log.e(TAG, "getState()", e);
   1027                     break;
   1028                 }
   1029             }
   1030             if (on || off) {
   1031                 SystemClock.sleep(300);
   1032 	    } else {
   1033                 SystemClock.sleep(50);
   1034 	    }
   1035             i++;
   1036         }
   1037         Log.e(TAG,"waitForOnOff time out");
   1038         return false;
   1039     }
   1040 }
   1041