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