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