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