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