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