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