BluetoothManagerService.java revision fca9d63635d9603c318a089397b23c17682453e3
1/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5package com.android.server;
6
7import android.bluetooth.BluetoothAdapter;
8import android.bluetooth.IBluetooth;
9import android.bluetooth.IBluetoothCallback;
10import android.bluetooth.IBluetoothManager;
11import android.bluetooth.IBluetoothManagerCallback;
12import android.bluetooth.IBluetoothStateChangeCallback;
13import android.content.BroadcastReceiver;
14import android.content.ComponentName;
15import android.content.ContentResolver;
16import android.content.Context;
17import android.content.Intent;
18import android.content.IntentFilter;
19import android.content.ServiceConnection;
20import android.os.Handler;
21import android.os.IBinder;
22import android.os.Message;
23import android.os.RemoteCallbackList;
24import android.os.RemoteException;
25import android.os.Binder;
26import android.os.UserHandle;
27import android.provider.Settings;
28import android.util.Log;
29import java.util.List;
30import java.util.ArrayList;
31class BluetoothManagerService extends IBluetoothManager.Stub {
32    private static final String TAG = "BluetoothManagerService";
33    private static final boolean DBG = true;
34
35    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
36    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
37    private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
38    private static final String EXTRA_ACTION="action";
39    private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
40    private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
41    private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
42    private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
43    //Maximum msec to wait for service restart
44    private static final int SERVICE_RESTART_TIME_MS = 200;
45
46    private static final int MESSAGE_ENABLE = 1;
47    private static final int MESSAGE_DISABLE = 2;
48    private static final int MESSAGE_REGISTER_ADAPTER = 20;
49    private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
50    private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
51    private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
52    private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
53    private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
54    private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
55    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
56    private static final int MESSAGE_TIMEOUT_BIND =100;
57    private static final int MESSAGE_TIMEOUT_UNBIND =101;
58    private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
59    private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
60    private static final int MAX_SAVE_RETRIES=3;
61
62    private final Context mContext;
63
64    // Locks are not provided for mName and mAddress.
65    // They are accessed in handler or broadcast receiver, same thread context.
66    private String mAddress;
67    private String mName;
68    private final ContentResolver mContentResolver;
69    private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
70    private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
71    private IBluetooth mBluetooth;
72    private boolean mBinding;
73    private boolean mUnbinding;
74    private boolean mQuietEnable = false;
75
76    private void registerForAirplaneMode(IntentFilter filter) {
77        final ContentResolver resolver = mContext.getContentResolver();
78        final String airplaneModeRadios = Settings.Global.getString(resolver,
79                Settings.Global.AIRPLANE_MODE_RADIOS);
80        final String toggleableRadios = Settings.Global.getString(resolver,
81                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
82        boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
83                airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
84        if (mIsAirplaneSensitive) {
85            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
86        }
87    }
88
89    private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
90        @Override
91        public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
92            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
93            mHandler.sendMessage(msg);
94        }
95    };
96
97    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
98        @Override
99        public void onReceive(Context context, Intent intent) {
100            String action = intent.getAction();
101            if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
102                String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
103                if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
104                if (newName != null) {
105                    storeNameAndAddress(newName, null);
106                }
107            } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
108                if (isAirplaneModeOn()) {
109                        // disable without persisting the setting
110                        handleDisable(false);
111                } else {
112                    if (isBluetoothPersistedStateOn()) {
113                        // enable without persisting the setting
114                        handleEnable(false, false);
115                    }
116                }
117            }
118        }
119    };
120
121    BluetoothManagerService(Context context) {
122        mContext = context;
123        mBluetooth = null;
124        mBinding = false;
125        mUnbinding = false;
126        mAddress = null;
127        mName = null;
128        mContentResolver = context.getContentResolver();
129        mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
130        mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
131        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
132        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
133        registerForAirplaneMode(filter);
134        mContext.registerReceiver(mReceiver, filter);
135        boolean airplaneModeOn = isAirplaneModeOn();
136        boolean bluetoothOn = isBluetoothPersistedStateOn();
137        loadStoredNameAndAddress();
138        if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
139        if (bluetoothOn) {
140            //Enable
141            if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
142            enable();
143        } else if (!isNameAndAddressSet()) {
144            //Sync the Bluetooth name and address from the Bluetooth Adapter
145            if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
146            getNameAndAddress();
147        }
148    }
149
150    /**
151     *  Returns true if airplane mode is currently on
152     */
153    private final boolean isAirplaneModeOn() {
154        return Settings.Global.getInt(mContext.getContentResolver(),
155                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
156    }
157
158    /**
159     *  Returns true if the Bluetooth saved state is "on"
160     */
161    private final boolean isBluetoothPersistedStateOn() {
162        return Settings.Global.getInt(mContentResolver,
163                Settings.Global.BLUETOOTH_ON, 0) ==1;
164    }
165
166    /**
167     *  Save the Bluetooth on/off state
168     *
169     */
170    private void persistBluetoothSetting(boolean setOn) {
171        Settings.Global.putInt(mContext.getContentResolver(),
172                               Settings.Global.BLUETOOTH_ON,
173                               setOn ? 1 : 0);
174    }
175
176    /**
177     * Returns true if the Bluetooth Adapter's name and address is
178     * locally cached
179     * @return
180     */
181    private boolean isNameAndAddressSet() {
182        return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
183    }
184
185    /**
186     * Retrieve the Bluetooth Adapter's name and address and save it in
187     * in the local cache
188     */
189    private void loadStoredNameAndAddress() {
190        if (DBG) Log.d(TAG, "Loading stored name and address");
191        mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
192        mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
193        if (mName == null || mAddress == null) {
194            if (DBG) Log.d(TAG, "Name or address not cached...");
195        }
196    }
197
198    /**
199     * Save the Bluetooth name and address in the persistent store.
200     * Only non-null values will be saved.
201     * @param name
202     * @param address
203     */
204    private void storeNameAndAddress(String name, String address) {
205        if (name != null) {
206            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
207            mName = name;
208            if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
209                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
210        }
211
212        if (address != null) {
213            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
214            mAddress=address;
215            if (DBG)  Log.d(TAG,"Stored Bluetoothaddress: " +
216                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
217        }
218    }
219
220    public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
221        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
222        msg.obj = callback;
223        mHandler.sendMessage(msg);
224        synchronized(mConnection) {
225            return mBluetooth;
226        }
227    }
228
229    public void unregisterAdapter(IBluetoothManagerCallback callback) {
230        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
231                                                "Need BLUETOOTH permission");
232        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
233        msg.obj = callback;
234        mHandler.sendMessage(msg);
235    }
236
237    public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
238        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
239                                                "Need BLUETOOTH permission");
240        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
241        msg.obj = callback;
242        mHandler.sendMessage(msg);
243    }
244
245    public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
246        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
247                                                "Need BLUETOOTH permission");
248        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
249        msg.obj = callback;
250        mHandler.sendMessage(msg);
251    }
252
253    public boolean isEnabled() {
254        synchronized(mConnection) {
255            try {
256                return (mBluetooth != null && mBluetooth.isEnabled());
257            } catch (RemoteException e) {
258                Log.e(TAG, "isEnabled()", e);
259            }
260        }
261        return false;
262    }
263
264    public void getNameAndAddress() {
265        if (DBG) {
266            Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
267                  " mBinding = " + mBinding);
268        }
269        synchronized(mConnection) {
270            if (mBinding) return;
271            if (mConnection == null) mBinding = true;
272        }
273        Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
274        mHandler.sendMessage(msg);
275    }
276    public boolean enableNoAutoConnect()
277    {
278        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
279                                                "Need BLUETOOTH ADMIN permission");
280        if (DBG) {
281            Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
282                    " mBinding = " + mBinding);
283        }
284        if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
285            throw new SecurityException("no permission to enable Bluetooth quietly");
286        }
287        synchronized(mConnection) {
288            if (mBinding) {
289                Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
290                return true;
291            }
292            if (mConnection == null) mBinding = true;
293        }
294
295        Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
296        msg.arg1=0; //No persist
297        msg.arg2=1; //Quiet mode
298        mHandler.sendMessage(msg);
299        return true;
300
301    }
302    public boolean enable() {
303        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
304                                                "Need BLUETOOTH ADMIN permission");
305        if (DBG) {
306            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
307                    " mBinding = " + mBinding);
308        }
309
310        synchronized(mConnection) {
311            if (mBinding) {
312                Log.w(TAG,"enable(): binding in progress. Returning..");
313                return true;
314            }
315            if (mConnection == null) mBinding = true;
316        }
317
318        Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
319        msg.arg1=1; //persist
320        msg.arg2=0; //No Quiet Mode
321        mHandler.sendMessage(msg);
322        return true;
323    }
324
325    public boolean disable(boolean persist) {
326        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
327                                                "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
328        if (DBG) {
329            Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
330                " mBinding = " + mBinding);
331        }
332
333        synchronized(mConnection) {
334             if (mBluetooth == null) return false;
335        }
336        Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
337        msg.arg1=(persist?1:0);
338        mHandler.sendMessage(msg);
339        return true;
340    }
341
342    public void unbindAndFinish() {
343        if (DBG) {
344            Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
345                " mBinding = " + mBinding);
346        }
347
348        synchronized (mConnection) {
349            if (mUnbinding) return;
350            mUnbinding = true;
351            if (mConnection != null) {
352                if (!mConnection.isGetNameAddressOnly()) {
353                    //Unregister callback object
354                    try {
355                        mBluetooth.unregisterCallback(mBluetoothCallback);
356                    } catch (RemoteException re) {
357                        Log.e(TAG, "Unable to register BluetoothCallback",re);
358                    }
359                }
360                if (DBG) Log.d(TAG, "Sending unbind request.");
361                mBluetooth = null;
362                //Unbind
363                mContext.unbindService(mConnection);
364                mUnbinding = false;
365            } else {
366                mUnbinding=false;
367            }
368        }
369    }
370
371    private void sendBluetoothStateCallback(boolean isUp) {
372        int n = mStateChangeCallbacks.beginBroadcast();
373        if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
374        for (int i=0; i <n;i++) {
375            try {
376                mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
377            } catch (RemoteException e) {
378                Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
379            }
380        }
381        mStateChangeCallbacks.finishBroadcast();
382    }
383
384    /**
385     * Inform BluetoothAdapter instances that Adapter service is down
386     */
387    private void sendBluetoothServiceDownCallback() {
388        if (!mConnection.isGetNameAddressOnly()) {
389            if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
390            int n = mCallbacks.beginBroadcast();
391            Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
392            for (int i=0; i <n;i++) {
393                try {
394                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
395                }  catch (RemoteException e) {
396                    Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
397                }
398            }
399            mCallbacks.finishBroadcast();
400        }
401    }
402    public String getAddress() {
403        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
404                                                "Need BLUETOOTH ADMIN permission");
405        synchronized(mConnection) {
406            if (mBluetooth != null) {
407                try {
408                    return mBluetooth.getAddress();
409                } catch (RemoteException e) {
410                    Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
411                }
412            }
413        }
414        // mAddress is accessed from outside.
415        // It is alright without a lock. Here, bluetooth is off, no other thread is
416        // changing mAddress
417        return mAddress;
418    }
419
420    public String getName() {
421        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
422                                                "Need BLUETOOTH ADMIN permission");
423        synchronized(mConnection) {
424            if (mBluetooth != null) {
425                try {
426                    return mBluetooth.getName();
427                } catch (RemoteException e) {
428                    Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
429                }
430            }
431        }
432        // mName is accessed from outside.
433        // It alright without a lock. Here, bluetooth is off, no other thread is
434        // changing mName
435        return mName;
436    }
437
438    private class BluetoothServiceConnection implements ServiceConnection {
439
440        private boolean mGetNameAddressOnly;
441
442        public void setGetNameAddressOnly(boolean getOnly) {
443            mGetNameAddressOnly = getOnly;
444        }
445
446        public boolean isGetNameAddressOnly() {
447            return mGetNameAddressOnly;
448        }
449
450        public void onServiceConnected(ComponentName className, IBinder service) {
451            if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
452            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
453            msg.obj = service;
454            mHandler.sendMessage(msg);
455        }
456
457        public void onServiceDisconnected(ComponentName className) {
458            // Called if we unexpected disconnected.
459            if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
460            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
461            mHandler.sendMessage(msg);
462        }
463    }
464
465    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
466
467    private final Handler mHandler = new Handler() {
468        @Override
469        public void handleMessage(Message msg) {
470            if (DBG) Log.d (TAG, "Message: " + msg.what);
471            switch (msg.what) {
472                case MESSAGE_GET_NAME_AND_ADDRESS: {
473                    if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
474                    synchronized(mConnection) {
475                        //Start bind request
476                        if (mBluetooth == null) {
477                            if (DBG) Log.d(TAG, "Binding to service to get name and address");
478                            mConnection.setGetNameAddressOnly(true);
479                            //Start bind timeout and bind
480                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
481                            mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
482                            Intent i = new Intent(IBluetooth.class.getName());
483                            if (!mContext.bindService(i, mConnection,
484                                  Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
485                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
486                                Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
487                            }
488                        }
489                        else {
490                            Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
491                            mHandler.sendMessage(saveMsg);
492                        }
493                    }
494                    break;
495                }
496                case MESSAGE_SAVE_NAME_AND_ADDRESS: {
497                    if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
498                    synchronized(mConnection) {
499                        if (mBluetooth != null) {
500                            String name =  null;
501                            String address = null;
502                            try {
503                                name =  mBluetooth.getName();
504                                address = mBluetooth.getAddress();
505                            } catch (RemoteException re) {
506                                Log.e(TAG,"",re);
507                            }
508
509                            if (name != null && address != null) {
510                                storeNameAndAddress(name,address);
511                                sendBluetoothServiceDownCallback();
512                                unbindAndFinish();
513                            } else {
514                                if (msg.arg1 < MAX_SAVE_RETRIES) {
515                                    Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
516                                    retryMsg.arg1= 1+msg.arg1;
517                                    if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
518                                    mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
519                                } else {
520                                    Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
521                                    sendBluetoothServiceDownCallback();
522                                    unbindAndFinish();
523                                }
524                            }
525                        }
526                    }
527                    break;
528                }
529                case MESSAGE_ENABLE:
530                    if (DBG) {
531                        Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
532                    }
533
534                    handleEnable(msg.arg1 == 1, msg.arg2 ==1);
535                    break;
536
537                case MESSAGE_DISABLE:
538                    handleDisable(msg.arg1 == 1);
539                    break;
540
541                case MESSAGE_REGISTER_ADAPTER:
542                {
543                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
544                    boolean added = mCallbacks.register(callback);
545                    Log.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
546                }
547                    break;
548                case MESSAGE_UNREGISTER_ADAPTER:
549                {
550                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
551                    boolean removed = mCallbacks.unregister(callback);
552                    Log.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
553                    break;
554                }
555                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
556                {
557                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
558                    mStateChangeCallbacks.register(callback);
559                    break;
560                }
561                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
562                {
563                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
564                    mStateChangeCallbacks.unregister(callback);
565                    break;
566                }
567                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
568                {
569                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
570
571                    //Remove timeout
572                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
573
574                    IBinder service = (IBinder) msg.obj;
575                    synchronized(mConnection) {
576                        mBinding = false;
577                        mBluetooth = IBluetooth.Stub.asInterface(service);
578
579                        if (mConnection.isGetNameAddressOnly()) {
580                            //Request GET NAME AND ADDRESS
581                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
582                            mHandler.sendMessage(getMsg);
583                            return;
584                        }
585
586                        //Register callback object
587                        try {
588                            mBluetooth.registerCallback(mBluetoothCallback);
589                        } catch (RemoteException re) {
590                            Log.e(TAG, "Unable to register BluetoothCallback",re);
591                        }
592
593                        //Inform BluetoothAdapter instances that service is up
594                        int n = mCallbacks.beginBroadcast();
595                        Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
596                        for (int i=0; i <n;i++) {
597                            try {
598                                mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
599                            } catch (RemoteException e) {
600                                Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
601                            }
602                        }
603                        mCallbacks.finishBroadcast();
604
605                        //Do enable request
606                        try {
607                            if (mQuietEnable == false) {
608                                if(!mBluetooth.enable()) {
609                                    Log.e(TAG,"IBluetooth.enable() returned false");
610                                }
611                            }
612                            else
613                            {
614                                if(!mBluetooth.enableNoAutoConnect()) {
615                                    Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
616                                }
617                            }
618                        } catch (RemoteException e) {
619                            Log.e(TAG,"Unable to call enable()",e);
620                        }
621                    }
622                    break;
623                }
624                case MESSAGE_TIMEOUT_BIND: {
625                    Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
626                    synchronized(mConnection) {
627                        mBinding = false;
628                    }
629                    break;
630                }
631                case MESSAGE_BLUETOOTH_STATE_CHANGE:
632                {
633                    int prevState = msg.arg1;
634                    int newState = msg.arg2;
635                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
636                    if (prevState != newState) {
637                        //Notify all proxy objects first of adapter state change
638                        if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
639                            boolean isUp = (newState==BluetoothAdapter.STATE_ON);
640                            sendBluetoothStateCallback(isUp);
641
642                            //If Bluetooth is off, send service down event to proxy objects, and unbind
643                            if (!isUp) {
644                                sendBluetoothServiceDownCallback();
645                                unbindAndFinish();
646                            }
647                        }
648
649                        //Send broadcast message to everyone else
650                        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
651                        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
652                        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
653                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
654                        if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
655                        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
656                                BLUETOOTH_PERM);
657                    }
658                    break;
659                }
660                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
661                {
662                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
663                    sendBluetoothServiceDownCallback();
664
665                    // Send BT state broadcast to update
666                    // the BT icon correctly
667                    Message stateChangeMsg = mHandler.obtainMessage(
668                        MESSAGE_BLUETOOTH_STATE_CHANGE);
669                    stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON;
670                    stateChangeMsg.arg2 =
671                        BluetoothAdapter.STATE_TURNING_OFF;
672                    mHandler.sendMessage(stateChangeMsg);
673                    synchronized(mConnection) {
674                        mBluetooth = null;
675                    }
676                    // Send a Bluetooth Restart message
677                    Message restartMsg = mHandler.obtainMessage(
678                        MESSAGE_RESTART_BLUETOOTH_SERVICE);
679                    mHandler.sendMessageDelayed(restartMsg,
680                        SERVICE_RESTART_TIME_MS);
681                    break;
682                }
683                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
684                {
685                    Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
686                        +" Restart IBluetooth service");
687                    /* Enable without persisting the setting as
688                     it doesnt change when IBluetooth
689                     service restarts */
690                    handleEnable(false, mQuietEnable);
691                    break;
692                }
693
694                case MESSAGE_TIMEOUT_UNBIND:
695                {
696                    Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
697                    synchronized(mConnection) {
698                        mUnbinding = false;
699                    }
700                    break;
701                }
702            }
703        }
704    };
705
706    private void handleEnable(boolean persist, boolean quietMode) {
707        if (persist) {
708            persistBluetoothSetting(true);
709        }
710
711        mQuietEnable = quietMode;
712
713        synchronized(mConnection) {
714            if (mBluetooth == null) {
715                //Start bind timeout and bind
716                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
717                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
718                mConnection.setGetNameAddressOnly(false);
719                Intent i = new Intent(IBluetooth.class.getName());
720                if (!mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE,
721                                          UserHandle.USER_CURRENT)) {
722                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
723                    Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
724                }
725            } else {
726                //Check if name and address is loaded if not get it first.
727                if (!isNameAndAddressSet()) {
728                    try {
729                        if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
730                        storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
731                    } catch (RemoteException e) {Log.e(TAG, "", e);};
732                }
733
734                //Enable bluetooth
735                try {
736                    if (!mQuietEnable) {
737                        if(!mBluetooth.enable()) {
738                            Log.e(TAG,"IBluetooth.enable() returned false");
739                        }
740                    }
741                    else {
742                        if(!mBluetooth.enableNoAutoConnect()) {
743                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
744                        }
745                    }
746                } catch (RemoteException e) {
747                    Log.e(TAG,"Unable to call enable()",e);
748                }
749            }
750        }
751    }
752
753    private void handleDisable(boolean persist) {
754        synchronized(mConnection) {
755            if (mBluetooth != null ) {
756                if (persist) {
757                    persistBluetoothSetting(false);
758                }
759                mConnection.setGetNameAddressOnly(false);
760                if (DBG) Log.d(TAG,"Sending off request.");
761
762                try {
763                    if(!mBluetooth.disable()) {
764                        Log.e(TAG,"IBluetooth.disable() returned false");
765                    }
766                } catch (RemoteException e) {
767                    Log.e(TAG,"Unable to call disable()",e);
768                }
769            }
770        }
771    }
772}
773