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