BluetoothManagerService.java revision bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324
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        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
222                                                "Need BLUETOOTH permission");
223        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
224        msg.obj = callback;
225        mHandler.sendMessage(msg);
226        synchronized(mConnection) {
227            return mBluetooth;
228        }
229    }
230
231    public void unregisterAdapter(IBluetoothManagerCallback callback) {
232        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
233                                                "Need BLUETOOTH permission");
234        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
235        msg.obj = callback;
236        mHandler.sendMessage(msg);
237    }
238
239    public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
240        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
241                                                "Need BLUETOOTH permission");
242        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
243        msg.obj = callback;
244        mHandler.sendMessage(msg);
245    }
246
247    public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
248        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
249                                                "Need BLUETOOTH permission");
250        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
251        msg.obj = callback;
252        mHandler.sendMessage(msg);
253    }
254
255    public boolean isEnabled() {
256        synchronized(mConnection) {
257            try {
258                return (mBluetooth != null && mBluetooth.isEnabled());
259            } catch (RemoteException e) {
260                Log.e(TAG, "isEnabled()", e);
261            }
262        }
263        return false;
264    }
265
266    public void getNameAndAddress() {
267        if (DBG) {
268            Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
269                  " mBinding = " + mBinding);
270        }
271        synchronized(mConnection) {
272            if (mBinding) return;
273            if (mConnection == null) mBinding = true;
274        }
275        Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
276        mHandler.sendMessage(msg);
277    }
278    public boolean enableNoAutoConnect()
279    {
280        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
281                                                "Need BLUETOOTH ADMIN permission");
282        if (DBG) {
283            Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
284                    " mBinding = " + mBinding);
285        }
286        if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
287            throw new SecurityException("no permission to enable Bluetooth quietly");
288        }
289        synchronized(mConnection) {
290            if (mBinding) {
291                Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
292                return true;
293            }
294            if (mConnection == null) mBinding = true;
295        }
296
297        Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
298        msg.arg1=0; //No persist
299        msg.arg2=1; //Quiet mode
300        mHandler.sendMessage(msg);
301        return true;
302
303    }
304    public boolean enable() {
305        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
306                                                "Need BLUETOOTH ADMIN permission");
307        if (DBG) {
308            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
309                    " mBinding = " + mBinding);
310        }
311
312        synchronized(mConnection) {
313            if (mBinding) {
314                Log.w(TAG,"enable(): binding in progress. Returning..");
315                return true;
316            }
317            if (mConnection == null) mBinding = true;
318        }
319
320        Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
321        msg.arg1=1; //persist
322        msg.arg2=0; //No Quiet Mode
323        mHandler.sendMessage(msg);
324        return true;
325    }
326
327    public boolean disable(boolean persist) {
328        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
329                                                "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
330        if (DBG) {
331            Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
332                " mBinding = " + mBinding);
333        }
334
335        synchronized(mConnection) {
336             if (mBluetooth == null) return false;
337        }
338        Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
339        msg.arg1=(persist?1:0);
340        mHandler.sendMessage(msg);
341        return true;
342    }
343
344    public void unbindAndFinish() {
345        if (DBG) {
346            Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
347                " mBinding = " + mBinding);
348        }
349
350        synchronized (mConnection) {
351            if (mUnbinding) return;
352            mUnbinding = true;
353            if (mConnection != null) {
354                if (!mConnection.isGetNameAddressOnly()) {
355                    //Unregister callback object
356                    try {
357                        mBluetooth.unregisterCallback(mBluetoothCallback);
358                    } catch (RemoteException re) {
359                        Log.e(TAG, "Unable to register BluetoothCallback",re);
360                    }
361                }
362                if (DBG) Log.d(TAG, "Sending unbind request.");
363                mBluetooth = null;
364                //Unbind
365                mContext.unbindService(mConnection);
366                mUnbinding = false;
367            } else {
368                mUnbinding=false;
369            }
370        }
371    }
372
373    private void sendBluetoothStateCallback(boolean isUp) {
374        int n = mStateChangeCallbacks.beginBroadcast();
375        if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
376        for (int i=0; i <n;i++) {
377            try {
378                mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
379            } catch (RemoteException e) {
380                Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
381            }
382        }
383        mStateChangeCallbacks.finishBroadcast();
384    }
385
386    /**
387     * Inform BluetoothAdapter instances that Adapter service is down
388     */
389    private void sendBluetoothServiceDownCallback() {
390        if (!mConnection.isGetNameAddressOnly()) {
391            if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
392            int n = mCallbacks.beginBroadcast();
393            Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
394            for (int i=0; i <n;i++) {
395                try {
396                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
397                }  catch (RemoteException e) {
398                    Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
399                }
400            }
401            mCallbacks.finishBroadcast();
402        }
403    }
404    public String getAddress() {
405        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
406                                                "Need BLUETOOTH ADMIN permission");
407        synchronized(mConnection) {
408            if (mBluetooth != null) {
409                try {
410                    return mBluetooth.getAddress();
411                } catch (RemoteException e) {
412                    Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
413                }
414            }
415        }
416        // mAddress is accessed from outside.
417        // It is alright without a lock. Here, bluetooth is off, no other thread is
418        // changing mAddress
419        return mAddress;
420    }
421
422    public String getName() {
423        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
424                                                "Need BLUETOOTH ADMIN permission");
425        synchronized(mConnection) {
426            if (mBluetooth != null) {
427                try {
428                    return mBluetooth.getName();
429                } catch (RemoteException e) {
430                    Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
431                }
432            }
433        }
434        // mName is accessed from outside.
435        // It alright without a lock. Here, bluetooth is off, no other thread is
436        // changing mName
437        return mName;
438    }
439
440    private class BluetoothServiceConnection implements ServiceConnection {
441
442        private boolean mGetNameAddressOnly;
443
444        public void setGetNameAddressOnly(boolean getOnly) {
445            mGetNameAddressOnly = getOnly;
446        }
447
448        public boolean isGetNameAddressOnly() {
449            return mGetNameAddressOnly;
450        }
451
452        public void onServiceConnected(ComponentName className, IBinder service) {
453            if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
454            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
455            msg.obj = service;
456            mHandler.sendMessage(msg);
457        }
458
459        public void onServiceDisconnected(ComponentName className) {
460            // Called if we unexpected disconnected.
461            if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
462            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
463            mHandler.sendMessage(msg);
464        }
465    }
466
467    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
468
469    private final Handler mHandler = new Handler() {
470        @Override
471        public void handleMessage(Message msg) {
472            if (DBG) Log.d (TAG, "Message: " + msg.what);
473            switch (msg.what) {
474                case MESSAGE_GET_NAME_AND_ADDRESS: {
475                    if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
476                    synchronized(mConnection) {
477                        //Start bind request
478                        if (mBluetooth == null) {
479                            if (DBG) Log.d(TAG, "Binding to service to get name and address");
480                            mConnection.setGetNameAddressOnly(true);
481                            //Start bind timeout and bind
482                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
483                            mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
484                            Intent i = new Intent(IBluetooth.class.getName());
485                            if (!mContext.bindService(i, mConnection,
486                                                  Context.BIND_AUTO_CREATE)) {
487                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
488                                Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
489                            }
490                        }
491                        else {
492                            Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
493                            mHandler.sendMessage(saveMsg);
494                        }
495                    }
496                    break;
497                }
498                case MESSAGE_SAVE_NAME_AND_ADDRESS: {
499                    if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
500                    synchronized(mConnection) {
501                        if (mBluetooth != null) {
502                            String name =  null;
503                            String address = null;
504                            try {
505                                name =  mBluetooth.getName();
506                                address = mBluetooth.getAddress();
507                            } catch (RemoteException re) {
508                                Log.e(TAG,"",re);
509                            }
510
511                            if (name != null && address != null) {
512                                storeNameAndAddress(name,address);
513                                sendBluetoothServiceDownCallback();
514                                unbindAndFinish();
515                            } else {
516                                if (msg.arg1 < MAX_SAVE_RETRIES) {
517                                    Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
518                                    retryMsg.arg1= 1+msg.arg1;
519                                    if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
520                                    mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
521                                } else {
522                                    Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
523                                    sendBluetoothServiceDownCallback();
524                                    unbindAndFinish();
525                                }
526                            }
527                        }
528                    }
529                    break;
530                }
531                case MESSAGE_ENABLE:
532                    if (DBG) {
533                        Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
534                    }
535
536                    handleEnable(msg.arg1 == 1, msg.arg2 ==1);
537                    break;
538
539                case MESSAGE_DISABLE:
540                    handleDisable(msg.arg1 == 1);
541                    break;
542
543                case MESSAGE_REGISTER_ADAPTER:
544                {
545                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
546                    boolean added = mCallbacks.register(callback);
547                    Log.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
548                }
549                    break;
550                case MESSAGE_UNREGISTER_ADAPTER:
551                {
552                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
553                    boolean removed = mCallbacks.unregister(callback);
554                    Log.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
555                    break;
556                }
557                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
558                {
559                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
560                    mStateChangeCallbacks.register(callback);
561                    break;
562                }
563                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
564                {
565                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
566                    mStateChangeCallbacks.unregister(callback);
567                    break;
568                }
569                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
570                {
571                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
572
573                    //Remove timeout
574                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
575
576                    IBinder service = (IBinder) msg.obj;
577                    synchronized(mConnection) {
578                        mBinding = false;
579                        mBluetooth = IBluetooth.Stub.asInterface(service);
580
581                        if (mConnection.isGetNameAddressOnly()) {
582                            //Request GET NAME AND ADDRESS
583                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
584                            mHandler.sendMessage(getMsg);
585                            return;
586                        }
587
588                        //Register callback object
589                        try {
590                            mBluetooth.registerCallback(mBluetoothCallback);
591                        } catch (RemoteException re) {
592                            Log.e(TAG, "Unable to register BluetoothCallback",re);
593                        }
594
595                        //Inform BluetoothAdapter instances that service is up
596                        int n = mCallbacks.beginBroadcast();
597                        Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
598                        for (int i=0; i <n;i++) {
599                            try {
600                                mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
601                            } catch (RemoteException e) {
602                                Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
603                            }
604                        }
605                        mCallbacks.finishBroadcast();
606
607                        //Do enable request
608                        try {
609                            if (mQuietEnable == false) {
610                                if(!mBluetooth.enable()) {
611                                    Log.e(TAG,"IBluetooth.enable() returned false");
612                                }
613                            }
614                            else
615                            {
616                                if(!mBluetooth.enableNoAutoConnect()) {
617                                    Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
618                                }
619                            }
620                        } catch (RemoteException e) {
621                            Log.e(TAG,"Unable to call enable()",e);
622                        }
623                    }
624                    break;
625                }
626                case MESSAGE_TIMEOUT_BIND: {
627                    Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
628                    synchronized(mConnection) {
629                        mBinding = false;
630                    }
631                    break;
632                }
633                case MESSAGE_BLUETOOTH_STATE_CHANGE:
634                {
635                    int prevState = msg.arg1;
636                    int newState = msg.arg2;
637                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
638                    if (prevState != newState) {
639                        //Notify all proxy objects first of adapter state change
640                        if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
641                            boolean isUp = (newState==BluetoothAdapter.STATE_ON);
642                            sendBluetoothStateCallback(isUp);
643
644                            //If Bluetooth is off, send service down event to proxy objects, and unbind
645                            if (!isUp) {
646                                sendBluetoothServiceDownCallback();
647                                unbindAndFinish();
648                            }
649                        }
650
651                        //Send broadcast message to everyone else
652                        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
653                        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
654                        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
655                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
656                        if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
657                        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
658                                BLUETOOTH_PERM);
659                    }
660                    break;
661                }
662                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
663                {
664                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
665                    sendBluetoothServiceDownCallback();
666
667                    // Send BT state broadcast to update
668                    // the BT icon correctly
669                    Message stateChangeMsg = mHandler.obtainMessage(
670                        MESSAGE_BLUETOOTH_STATE_CHANGE);
671                    stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON;
672                    stateChangeMsg.arg2 =
673                        BluetoothAdapter.STATE_TURNING_OFF;
674                    mHandler.sendMessage(stateChangeMsg);
675                    synchronized(mConnection) {
676                        mBluetooth = null;
677                    }
678                    // Send a Bluetooth Restart message
679                    Message restartMsg = mHandler.obtainMessage(
680                        MESSAGE_RESTART_BLUETOOTH_SERVICE);
681                    mHandler.sendMessageDelayed(restartMsg,
682                        SERVICE_RESTART_TIME_MS);
683                    break;
684                }
685                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
686                {
687                    Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
688                        +" Restart IBluetooth service");
689                    /* Enable without persisting the setting as
690                     it doesnt change when IBluetooth
691                     service restarts */
692                    handleEnable(false, mQuietEnable);
693                    break;
694                }
695
696                case MESSAGE_TIMEOUT_UNBIND:
697                {
698                    Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
699                    synchronized(mConnection) {
700                        mUnbinding = false;
701                    }
702                    break;
703                }
704            }
705        }
706    };
707
708    private void handleEnable(boolean persist, boolean quietMode) {
709        if (persist) {
710            persistBluetoothSetting(true);
711        }
712
713        mQuietEnable = quietMode;
714
715        synchronized(mConnection) {
716            if (mBluetooth == null) {
717                //Start bind timeout and bind
718                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
719                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
720                mConnection.setGetNameAddressOnly(false);
721                Intent i = new Intent(IBluetooth.class.getName());
722                if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
723                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
724                    Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
725                }
726            } else {
727                //Check if name and address is loaded if not get it first.
728                if (!isNameAndAddressSet()) {
729                    try {
730                        if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
731                        storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
732                    } catch (RemoteException e) {Log.e(TAG, "", e);};
733                }
734
735                //Enable bluetooth
736                try {
737                    if (!mQuietEnable) {
738                        if(!mBluetooth.enable()) {
739                            Log.e(TAG,"IBluetooth.enable() returned false");
740                        }
741                    }
742                    else {
743                        if(!mBluetooth.enableNoAutoConnect()) {
744                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
745                        }
746                    }
747                } catch (RemoteException e) {
748                    Log.e(TAG,"Unable to call enable()",e);
749                }
750            }
751        }
752    }
753
754    private void handleDisable(boolean persist) {
755        synchronized(mConnection) {
756            if (mBluetooth != null ) {
757                if (persist) {
758                    persistBluetoothSetting(false);
759                }
760                mConnection.setGetNameAddressOnly(false);
761                if (DBG) Log.d(TAG,"Sending off request.");
762
763                try {
764                    if(!mBluetooth.disable()) {
765                        Log.e(TAG,"IBluetooth.disable() returned false");
766                    }
767                } catch (RemoteException e) {
768                    Log.e(TAG,"Unable to call disable()",e);
769                }
770            }
771        }
772    }
773}
774