BluetoothManagerService.java revision a0eaaa2a22def29a0c3cb9645a105b773048f5ee
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.ActivityManager;
20import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothProfile;
22import android.bluetooth.IBluetooth;
23import android.bluetooth.IBluetoothGatt;
24import android.bluetooth.IBluetoothCallback;
25import android.bluetooth.IBluetoothHeadset;
26import android.bluetooth.IBluetoothManager;
27import android.bluetooth.IBluetoothManagerCallback;
28import android.bluetooth.IBluetoothProfileServiceConnection;
29import android.bluetooth.IBluetoothStateChangeCallback;
30import android.content.BroadcastReceiver;
31import android.content.ComponentName;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.ServiceConnection;
37import android.content.pm.PackageManager;
38import android.content.pm.UserInfo;
39import android.os.Binder;
40import android.os.Handler;
41import android.os.IBinder;
42import android.os.Looper;
43import android.os.Message;
44import android.os.ParcelFileDescriptor;
45import android.os.Process;
46import android.os.RemoteCallbackList;
47import android.os.RemoteException;
48import android.os.SystemClock;
49import android.os.UserHandle;
50import android.os.UserManager;
51import android.provider.Settings;
52import android.util.Log;
53
54import java.io.FileDescriptor;
55import java.io.IOException;
56import java.io.PrintWriter;
57
58import java.util.HashMap;
59import java.util.Map;
60import java.util.List;
61import java.util.Vector;
62
63class BluetoothManagerService extends IBluetoothManager.Stub {
64    private static final String TAG = "BluetoothManagerService";
65    private static final boolean DBG = true;
66
67    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
68    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
69    private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
70    private static final String EXTRA_ACTION="action";
71    private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
72    private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
73    private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
74    private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
75    private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
76    //Maximum msec to wait for service restart
77    private static final int SERVICE_RESTART_TIME_MS = 200;
78    //Maximum msec to wait for restart due to error
79    private static final int ERROR_RESTART_TIME_MS = 3000;
80    //Maximum msec to delay MESSAGE_USER_SWITCHED
81    private static final int USER_SWITCHED_TIME_MS = 200;
82    // Delay for the addProxy function in msec
83    private static final int ADD_PROXY_DELAY_MS = 100;
84
85    private static final int MESSAGE_ENABLE = 1;
86    private static final int MESSAGE_DISABLE = 2;
87    private static final int MESSAGE_REGISTER_ADAPTER = 20;
88    private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
89    private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
90    private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
91    private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
92    private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
93    private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
94    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
95    private static final int MESSAGE_TIMEOUT_BIND =100;
96    private static final int MESSAGE_TIMEOUT_UNBIND =101;
97    private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
98    private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
99    private static final int MESSAGE_USER_SWITCHED = 300;
100    private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
101    private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
102    private static final int MAX_SAVE_RETRIES=3;
103    private static final int MAX_ERROR_RESTART_RETRIES=6;
104
105    // Bluetooth persisted setting is off
106    private static final int BLUETOOTH_OFF=0;
107    // Bluetooth persisted setting is on
108    // and Airplane mode won't affect Bluetooth state at start up
109    private static final int BLUETOOTH_ON_BLUETOOTH=1;
110    // Bluetooth persisted setting is on
111    // but Airplane mode will affect Bluetooth state at start up
112    // and Airplane mode will have higher priority.
113    private static final int BLUETOOTH_ON_AIRPLANE=2;
114
115    private static final int SERVICE_IBLUETOOTH = 1;
116    private static final int SERVICE_IBLUETOOTHGATT = 2;
117
118    private final Context mContext;
119
120    // Locks are not provided for mName and mAddress.
121    // They are accessed in handler or broadcast receiver, same thread context.
122    private String mAddress;
123    private String mName;
124    private final ContentResolver mContentResolver;
125    private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
126    private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
127    private IBluetooth mBluetooth;
128    private IBluetoothGatt mBluetoothGatt;
129    private boolean mBinding;
130    private boolean mUnbinding;
131    // used inside handler thread
132    private boolean mQuietEnable = false;
133    // configuarion from external IBinder call which is used to
134    // synchronize with broadcast receiver.
135    private boolean mQuietEnableExternal;
136    // configuarion from external IBinder call which is used to
137    // synchronize with broadcast receiver.
138    private boolean mEnableExternal;
139    // used inside handler thread
140    private boolean mEnable;
141    private int mState;
142    private final BluetoothHandler mHandler;
143    private int mErrorRecoveryRetryCounter;
144    private final int mSystemUiUid;
145
146    // Save a ProfileServiceConnections object for each of the bound
147    // bluetooth profile services
148    private final Map <Integer, ProfileServiceConnections> mProfileServices =
149            new HashMap <Integer, ProfileServiceConnections>();
150
151    private void registerForAirplaneMode(IntentFilter filter) {
152        final ContentResolver resolver = mContext.getContentResolver();
153        final String airplaneModeRadios = Settings.Global.getString(resolver,
154                Settings.Global.AIRPLANE_MODE_RADIOS);
155        final String toggleableRadios = Settings.Global.getString(resolver,
156                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
157        boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
158                airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
159        if (mIsAirplaneSensitive) {
160            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
161        }
162    }
163
164    private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
165        @Override
166        public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
167            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
168            mHandler.sendMessage(msg);
169        }
170    };
171
172    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
173        @Override
174        public void onReceive(Context context, Intent intent) {
175            String action = intent.getAction();
176            if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
177                String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
178                if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
179                if (newName != null) {
180                    storeNameAndAddress(newName, null);
181                }
182            } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
183                synchronized(mReceiver) {
184                    if (isBluetoothPersistedStateOn()) {
185                        if (isAirplaneModeOn()) {
186                            persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
187                        } else {
188                            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
189                        }
190                    }
191                    if (isAirplaneModeOn()) {
192                        // disable without persisting the setting
193                        sendDisableMsg();
194                    } else if (mEnableExternal) {
195                        // enable without persisting the setting
196                        sendEnableMsg(mQuietEnableExternal);
197                    }
198                }
199            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
200                mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
201                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
202            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
203                synchronized(mReceiver) {
204                    if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
205                        //Enable
206                        if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
207                        sendEnableMsg(mQuietEnableExternal);
208                    }
209                }
210
211                if (!isNameAndAddressSet()) {
212                    //Sync the Bluetooth name and address from the Bluetooth Adapter
213                    if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
214                    getNameAndAddress();
215                }
216            }
217        }
218    };
219
220    BluetoothManagerService(Context context) {
221        mHandler = new BluetoothHandler(IoThread.get().getLooper());
222
223        mContext = context;
224        mBluetooth = null;
225        mBinding = false;
226        mUnbinding = false;
227        mEnable = false;
228        mState = BluetoothAdapter.STATE_OFF;
229        mQuietEnableExternal = false;
230        mEnableExternal = false;
231        mAddress = null;
232        mName = null;
233        mErrorRecoveryRetryCounter = 0;
234        mContentResolver = context.getContentResolver();
235        mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
236        mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
237        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
238        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
239        filter.addAction(Intent.ACTION_USER_SWITCHED);
240        registerForAirplaneMode(filter);
241        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
242        mContext.registerReceiver(mReceiver, filter);
243        loadStoredNameAndAddress();
244        if (isBluetoothPersistedStateOn()) {
245            mEnableExternal = true;
246        }
247
248        int sysUiUid = -1;
249        try {
250            sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
251                    UserHandle.USER_OWNER);
252        } catch (PackageManager.NameNotFoundException e) {
253            Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e);
254        }
255        mSystemUiUid = sysUiUid;
256    }
257
258    /**
259     *  Returns true if airplane mode is currently on
260     */
261    private final boolean isAirplaneModeOn() {
262        return Settings.Global.getInt(mContext.getContentResolver(),
263                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
264    }
265
266    /**
267     *  Returns true if the Bluetooth saved state is "on"
268     */
269    private final boolean isBluetoothPersistedStateOn() {
270        return Settings.Global.getInt(mContentResolver,
271                Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
272    }
273
274    /**
275     *  Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
276     */
277    private final boolean isBluetoothPersistedStateOnBluetooth() {
278        return Settings.Global.getInt(mContentResolver,
279                Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
280    }
281
282    /**
283     *  Save the Bluetooth on/off state
284     *
285     */
286    private void persistBluetoothSetting(int value) {
287        Settings.Global.putInt(mContext.getContentResolver(),
288                               Settings.Global.BLUETOOTH_ON,
289                               value);
290    }
291
292    /**
293     * Returns true if the Bluetooth Adapter's name and address is
294     * locally cached
295     * @return
296     */
297    private boolean isNameAndAddressSet() {
298        return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
299    }
300
301    /**
302     * Retrieve the Bluetooth Adapter's name and address and save it in
303     * in the local cache
304     */
305    private void loadStoredNameAndAddress() {
306        if (DBG) Log.d(TAG, "Loading stored name and address");
307        if (mContext.getResources().getBoolean
308            (com.android.internal.R.bool.config_bluetooth_address_validation) &&
309             Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
310            // if the valid flag is not set, don't load the address and name
311            if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
312            return;
313        }
314        mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
315        mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
316        if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
317    }
318
319    /**
320     * Save the Bluetooth name and address in the persistent store.
321     * Only non-null values will be saved.
322     * @param name
323     * @param address
324     */
325    private void storeNameAndAddress(String name, String address) {
326        if (name != null) {
327            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
328            mName = name;
329            if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
330                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
331        }
332
333        if (address != null) {
334            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
335            mAddress=address;
336            if (DBG)  Log.d(TAG,"Stored Bluetoothaddress: " +
337                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
338        }
339
340        if ((name != null) && (address != null)) {
341            Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
342        }
343    }
344
345    public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
346        if (callback == null) {
347            Log.w(TAG, "Callback is null in registerAdapter");
348            return null;
349        }
350        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
351        msg.obj = callback;
352        mHandler.sendMessage(msg);
353        synchronized(mConnection) {
354            return mBluetooth;
355        }
356    }
357
358    public void unregisterAdapter(IBluetoothManagerCallback callback) {
359        if (callback == null) {
360            Log.w(TAG, "Callback is null in unregisterAdapter");
361            return;
362        }
363        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
364                                                "Need BLUETOOTH permission");
365        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
366        msg.obj = callback;
367        mHandler.sendMessage(msg);
368    }
369
370    public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
371        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
372                                                "Need BLUETOOTH permission");
373        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
374        msg.obj = callback;
375        mHandler.sendMessage(msg);
376    }
377
378    public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
379        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
380                                                "Need BLUETOOTH permission");
381        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
382        msg.obj = callback;
383        mHandler.sendMessage(msg);
384    }
385
386    public boolean isEnabled() {
387        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
388            (!checkIfCallerIsForegroundUser())) {
389            Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
390            return false;
391        }
392
393        synchronized(mConnection) {
394            try {
395                return (mBluetooth != null && mBluetooth.isEnabled());
396            } catch (RemoteException e) {
397                Log.e(TAG, "isEnabled()", e);
398            }
399        }
400        return false;
401    }
402
403    public void getNameAndAddress() {
404        if (DBG) {
405            Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
406                  " mBinding = " + mBinding);
407        }
408        Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
409        mHandler.sendMessage(msg);
410    }
411    public boolean enableNoAutoConnect()
412    {
413        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
414                                                "Need BLUETOOTH ADMIN permission");
415
416        if (DBG) {
417            Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
418                    " mBinding = " + mBinding);
419        }
420        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
421
422        if (callingAppId != Process.NFC_UID) {
423            throw new SecurityException("no permission to enable Bluetooth quietly");
424        }
425
426        synchronized(mReceiver) {
427            mQuietEnableExternal = true;
428            mEnableExternal = true;
429            sendEnableMsg(true);
430        }
431        return true;
432
433    }
434    public boolean enable() {
435        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
436            (!checkIfCallerIsForegroundUser())) {
437            Log.w(TAG,"enable(): not allowed for non-active and non system user");
438            return false;
439        }
440
441        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
442                                                "Need BLUETOOTH ADMIN permission");
443        if (DBG) {
444            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
445                    " mBinding = " + mBinding);
446        }
447
448        synchronized(mReceiver) {
449            mQuietEnableExternal = false;
450            mEnableExternal = true;
451            // waive WRITE_SECURE_SETTINGS permission check
452            long callingIdentity = Binder.clearCallingIdentity();
453            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
454            Binder.restoreCallingIdentity(callingIdentity);
455            sendEnableMsg(false);
456        }
457        return true;
458    }
459
460    public boolean disable(boolean persist) {
461        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
462                                                "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
463
464        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
465            (!checkIfCallerIsForegroundUser())) {
466            Log.w(TAG,"disable(): not allowed for non-active and non system user");
467            return false;
468        }
469
470        if (DBG) {
471            Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
472                " mBinding = " + mBinding);
473        }
474
475        synchronized(mReceiver) {
476            if (persist) {
477                // waive WRITE_SECURE_SETTINGS permission check
478                long callingIdentity = Binder.clearCallingIdentity();
479                persistBluetoothSetting(BLUETOOTH_OFF);
480                Binder.restoreCallingIdentity(callingIdentity);
481            }
482            mEnableExternal = false;
483            sendDisableMsg();
484        }
485        return true;
486    }
487
488    public void unbindAndFinish() {
489        if (DBG) {
490            Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
491                " mBinding = " + mBinding);
492        }
493
494        synchronized (mConnection) {
495            if (mUnbinding) return;
496            mUnbinding = true;
497            if (mBluetooth != null) {
498                if (!mConnection.isGetNameAddressOnly()) {
499                    //Unregister callback object
500                    try {
501                        mBluetooth.unregisterCallback(mBluetoothCallback);
502                    } catch (RemoteException re) {
503                        Log.e(TAG, "Unable to unregister BluetoothCallback",re);
504                    }
505                }
506                if (DBG) Log.d(TAG, "Sending unbind request.");
507                mBluetooth = null;
508                //Unbind
509                mContext.unbindService(mConnection);
510                mUnbinding = false;
511                mBinding = false;
512            } else {
513                mUnbinding=false;
514            }
515        }
516    }
517
518    public IBluetoothGatt getBluetoothGatt() {
519        // sync protection
520        return mBluetoothGatt;
521    }
522
523    @Override
524    public boolean bindBluetoothProfileService(int bluetoothProfile,
525            IBluetoothProfileServiceConnection proxy) {
526        if (!mEnable) {
527            if (DBG) {
528                Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
529                        ", while Bluetooth was disabled");
530            }
531            return false;
532        }
533        synchronized (mProfileServices) {
534            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
535            if (psc == null) {
536                if (DBG) {
537                    Log.d(TAG, "Creating new ProfileServiceConnections object for"
538                            + " profile: " + bluetoothProfile);
539                }
540
541                if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
542
543                Intent intent = new Intent(IBluetoothHeadset.class.getName());
544                psc = new ProfileServiceConnections(intent);
545                if (!psc.bindService()) return false;
546
547                mProfileServices.put(new Integer(bluetoothProfile), psc);
548            }
549        }
550
551        // Introducing a delay to give the client app time to prepare
552        Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
553        addProxyMsg.arg1 = bluetoothProfile;
554        addProxyMsg.obj = proxy;
555        mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
556        return true;
557    }
558
559    @Override
560    public void unbindBluetoothProfileService(int bluetoothProfile,
561            IBluetoothProfileServiceConnection proxy) {
562        synchronized (mProfileServices) {
563            ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
564            if (psc == null) {
565                return;
566            }
567            psc.removeProxy(proxy);
568        }
569    }
570
571    private void unbindAllBluetoothProfileServices() {
572        synchronized (mProfileServices) {
573            for (Integer i : mProfileServices.keySet()) {
574                ProfileServiceConnections psc = mProfileServices.get(i);
575                try {
576                    mContext.unbindService(psc);
577                } catch (IllegalArgumentException e) {
578                    Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
579                }
580                psc.removeAllProxies();
581            }
582            mProfileServices.clear();
583        }
584    }
585
586    /**
587     * This class manages the clients connected to a given ProfileService
588     * and maintains the connection with that service.
589     */
590    final private class ProfileServiceConnections implements ServiceConnection,
591            IBinder.DeathRecipient {
592        final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
593                new RemoteCallbackList <IBluetoothProfileServiceConnection>();
594        IBinder mService;
595        ComponentName mClassName;
596        Intent mIntent;
597
598        ProfileServiceConnections(Intent intent) {
599            mService = null;
600            mClassName = null;
601            mIntent = intent;
602        }
603
604        private boolean bindService() {
605            if (mIntent != null && mService == null &&
606                    doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
607                Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
608                msg.obj = this;
609                mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
610                return true;
611            }
612            Log.w(TAG, "Unable to bind with intent: " + mIntent);
613            return false;
614        }
615
616        private void addProxy(IBluetoothProfileServiceConnection proxy) {
617            mProxies.register(proxy);
618            if (mService != null) {
619                try{
620                    proxy.onServiceConnected(mClassName, mService);
621                } catch (RemoteException e) {
622                    Log.e(TAG, "Unable to connect to proxy", e);
623                }
624            } else {
625                if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
626                    Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
627                    msg.obj = this;
628                    mHandler.sendMessage(msg);
629                }
630            }
631        }
632
633        private void removeProxy(IBluetoothProfileServiceConnection proxy) {
634            if (proxy != null) {
635                if (mProxies.unregister(proxy)) {
636                    try {
637                        proxy.onServiceDisconnected(mClassName);
638                    } catch (RemoteException e) {
639                        Log.e(TAG, "Unable to disconnect proxy", e);
640                    }
641                }
642            } else {
643                Log.w(TAG, "Trying to remove a null proxy");
644            }
645        }
646
647        private void removeAllProxies() {
648            onServiceDisconnected(mClassName);
649            mProxies.kill();
650        }
651
652        @Override
653        public void onServiceConnected(ComponentName className, IBinder service) {
654            // remove timeout message
655            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
656            mService = service;
657            mClassName = className;
658            try {
659                mService.linkToDeath(this, 0);
660            } catch (RemoteException e) {
661                Log.e(TAG, "Unable to linkToDeath", e);
662            }
663            int n = mProxies.beginBroadcast();
664            for (int i = 0; i < n; i++) {
665                try {
666                    mProxies.getBroadcastItem(i).onServiceConnected(className, service);
667                } catch (RemoteException e) {
668                    Log.e(TAG, "Unable to connect to proxy", e);
669                }
670            }
671            mProxies.finishBroadcast();
672        }
673
674        @Override
675        public void onServiceDisconnected(ComponentName className) {
676            if (mService == null) {
677                return;
678            }
679            mService.unlinkToDeath(this, 0);
680            mService = null;
681            mClassName = null;
682            int n = mProxies.beginBroadcast();
683            for (int i = 0; i < n; i++) {
684                try {
685                    mProxies.getBroadcastItem(i).onServiceDisconnected(className);
686                } catch (RemoteException e) {
687                    Log.e(TAG, "Unable to disconnect from proxy", e);
688                }
689            }
690            mProxies.finishBroadcast();
691        }
692
693        @Override
694        public void binderDied() {
695            if (DBG) {
696                Log.w(TAG, "Profile service for profile: " + mClassName
697                        + " died.");
698            }
699            onServiceDisconnected(mClassName);
700            // Trigger rebind
701            Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
702            msg.obj = this;
703            mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
704        }
705    }
706
707    private void sendBluetoothStateCallback(boolean isUp) {
708        int n = mStateChangeCallbacks.beginBroadcast();
709        if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
710        for (int i=0; i <n;i++) {
711            try {
712                mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
713            } catch (RemoteException e) {
714                Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
715            }
716        }
717        mStateChangeCallbacks.finishBroadcast();
718    }
719
720    /**
721     * Inform BluetoothAdapter instances that Adapter service is up
722     */
723    private void sendBluetoothServiceUpCallback() {
724        if (!mConnection.isGetNameAddressOnly()) {
725            if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
726            int n = mCallbacks.beginBroadcast();
727            Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
728            for (int i=0; i <n;i++) {
729                try {
730                    mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
731                }  catch (RemoteException e) {
732                    Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
733                }
734            }
735            mCallbacks.finishBroadcast();
736        }
737    }
738    /**
739     * Inform BluetoothAdapter instances that Adapter service is down
740     */
741    private void sendBluetoothServiceDownCallback() {
742        if (!mConnection.isGetNameAddressOnly()) {
743            if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
744            int n = mCallbacks.beginBroadcast();
745            Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
746            for (int i=0; i <n;i++) {
747                try {
748                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
749                }  catch (RemoteException e) {
750                    Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
751                }
752            }
753            mCallbacks.finishBroadcast();
754        }
755    }
756    public String getAddress() {
757        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
758                                                "Need BLUETOOTH permission");
759
760        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
761            (!checkIfCallerIsForegroundUser())) {
762            Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
763            return null;
764        }
765
766        synchronized(mConnection) {
767            if (mBluetooth != null) {
768                try {
769                    return mBluetooth.getAddress();
770                } catch (RemoteException e) {
771                    Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
772                }
773            }
774        }
775        // mAddress is accessed from outside.
776        // It is alright without a lock. Here, bluetooth is off, no other thread is
777        // changing mAddress
778        return mAddress;
779    }
780
781    public String getName() {
782        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
783                                                "Need BLUETOOTH permission");
784
785        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
786            (!checkIfCallerIsForegroundUser())) {
787            Log.w(TAG,"getName(): not allowed for non-active and non system user");
788            return null;
789        }
790
791        synchronized(mConnection) {
792            if (mBluetooth != null) {
793                try {
794                    return mBluetooth.getName();
795                } catch (RemoteException e) {
796                    Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
797                }
798            }
799        }
800        // mName is accessed from outside.
801        // It alright without a lock. Here, bluetooth is off, no other thread is
802        // changing mName
803        return mName;
804    }
805
806    private class BluetoothServiceConnection implements ServiceConnection {
807
808        private boolean mGetNameAddressOnly;
809
810        public void setGetNameAddressOnly(boolean getOnly) {
811            mGetNameAddressOnly = getOnly;
812        }
813
814        public boolean isGetNameAddressOnly() {
815            return mGetNameAddressOnly;
816        }
817
818        public void onServiceConnected(ComponentName className, IBinder service) {
819            if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
820            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
821            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
822            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
823                msg.arg1 = SERVICE_IBLUETOOTH;
824                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
825            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
826                msg.arg1 = SERVICE_IBLUETOOTHGATT;
827            } else {
828                Log.e(TAG, "Unknown service connected: " + className.getClassName());
829                return;
830            }
831            msg.obj = service;
832            mHandler.sendMessage(msg);
833        }
834
835        public void onServiceDisconnected(ComponentName className) {
836            // Called if we unexpected disconnected.
837            if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
838                           className.getClassName());
839            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
840            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
841                msg.arg1 = SERVICE_IBLUETOOTH;
842            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
843                msg.arg1 = SERVICE_IBLUETOOTHGATT;
844            } else {
845                Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
846                return;
847            }
848            mHandler.sendMessage(msg);
849        }
850    }
851
852    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
853
854    private class BluetoothHandler extends Handler {
855        public BluetoothHandler(Looper looper) {
856            super(looper);
857        }
858
859        @Override
860        public void handleMessage(Message msg) {
861            if (DBG) Log.d (TAG, "Message: " + msg.what);
862            switch (msg.what) {
863                case MESSAGE_GET_NAME_AND_ADDRESS: {
864                    if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
865                    synchronized(mConnection) {
866                        //Start bind request
867                        if ((mBluetooth == null) && (!mBinding)) {
868                            if (DBG) Log.d(TAG, "Binding to service to get name and address");
869                            mConnection.setGetNameAddressOnly(true);
870                            //Start bind timeout and bind
871                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
872                            mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
873                            Intent i = new Intent(IBluetooth.class.getName());
874                            if (!doBind(i, mConnection,
875                                    Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
876                                    UserHandle.CURRENT)) {
877                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
878                            } else {
879                                mBinding = true;
880                            }
881                        }
882                        else {
883                            Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
884                            saveMsg.arg1 = 0;
885                            if (mBluetooth != null) {
886                                mHandler.sendMessage(saveMsg);
887                            } else {
888                                // if enable is also called to bind the service
889                                // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
890                                mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
891                            }
892                        }
893                    }
894                    break;
895                }
896                case MESSAGE_SAVE_NAME_AND_ADDRESS: {
897                    boolean unbind = false;
898                    if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
899                    synchronized(mConnection) {
900                        if (!mEnable && mBluetooth != null) {
901                            try {
902                                mBluetooth.enable();
903                            } catch (RemoteException e) {
904                                Log.e(TAG,"Unable to call enable()",e);
905                            }
906                        }
907                    }
908                    if (mBluetooth != null) waitForOnOff(true, false);
909                    synchronized(mConnection) {
910                        if (mBluetooth != null) {
911                            String name =  null;
912                            String address = null;
913                            try {
914                                name =  mBluetooth.getName();
915                                address = mBluetooth.getAddress();
916                            } catch (RemoteException re) {
917                                Log.e(TAG,"",re);
918                            }
919
920                            if (name != null && address != null) {
921                                storeNameAndAddress(name,address);
922                                if (mConnection.isGetNameAddressOnly()) {
923                                    unbind = true;
924                                }
925                            } else {
926                                if (msg.arg1 < MAX_SAVE_RETRIES) {
927                                    Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
928                                    retryMsg.arg1= 1+msg.arg1;
929                                    if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
930                                    mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
931                                } else {
932                                    Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
933                                    if (mConnection.isGetNameAddressOnly()) {
934                                        unbind = true;
935                                    }
936                                }
937                            }
938                            if (!mEnable) {
939                                try {
940                                    mBluetooth.disable();
941                                } catch (RemoteException e) {
942                                    Log.e(TAG,"Unable to call disable()",e);
943                                }
944                            }
945                        } else {
946                            // rebind service by Request GET NAME AND ADDRESS
947                            // if service is unbinded by disable or
948                            // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
949                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
950                            mHandler.sendMessage(getMsg);
951                        }
952                    }
953                    if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
954                    if (unbind) {
955                        unbindAndFinish();
956                    }
957                    break;
958                }
959                case MESSAGE_ENABLE:
960                    if (DBG) {
961                        Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
962                    }
963                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
964                    mEnable = true;
965                    handleEnable(msg.arg1 == 1);
966                    break;
967
968                case MESSAGE_DISABLE:
969                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
970                    if (mEnable && mBluetooth != null) {
971                        waitForOnOff(true, false);
972                        mEnable = false;
973                        handleDisable();
974                        waitForOnOff(false, false);
975                    } else {
976                        mEnable = false;
977                        handleDisable();
978                    }
979                    break;
980
981                case MESSAGE_REGISTER_ADAPTER:
982                {
983                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
984                    boolean added = mCallbacks.register(callback);
985                    Log.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
986                }
987                    break;
988                case MESSAGE_UNREGISTER_ADAPTER:
989                {
990                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
991                    boolean removed = mCallbacks.unregister(callback);
992                    Log.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
993                    break;
994                }
995                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
996                {
997                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
998                    if (callback != null) {
999                        mStateChangeCallbacks.register(callback);
1000                    }
1001                    break;
1002                }
1003                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1004                {
1005                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
1006                    if (callback != null) {
1007                        mStateChangeCallbacks.unregister(callback);
1008                    }
1009                    break;
1010                }
1011                case MESSAGE_ADD_PROXY_DELAYED:
1012                {
1013                    ProfileServiceConnections psc = mProfileServices.get(
1014                            new Integer(msg.arg1));
1015                    if (psc == null) {
1016                        break;
1017                    }
1018                    IBluetoothProfileServiceConnection proxy =
1019                            (IBluetoothProfileServiceConnection) msg.obj;
1020                    psc.addProxy(proxy);
1021                    break;
1022                }
1023                case MESSAGE_BIND_PROFILE_SERVICE:
1024                {
1025                    ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1026                    removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1027                    if (psc == null) {
1028                        break;
1029                    }
1030                    psc.bindService();
1031                    break;
1032                }
1033                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1034                {
1035                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
1036
1037                    IBinder service = (IBinder) msg.obj;
1038                    synchronized(mConnection) {
1039                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1040                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
1041                            break;
1042                        } // else must be SERVICE_IBLUETOOTH
1043
1044                        //Remove timeout
1045                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1046
1047                        mBinding = false;
1048                        mBluetooth = IBluetooth.Stub.asInterface(service);
1049
1050                        try {
1051                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1052                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1053                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1054                                Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
1055                            }
1056                        } catch (RemoteException e) {
1057                            Log.e(TAG,"Unable to call configHciSnoopLog", e);
1058                        }
1059
1060                        if (mConnection.isGetNameAddressOnly()) {
1061                            //Request GET NAME AND ADDRESS
1062                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1063                            mHandler.sendMessage(getMsg);
1064                            if (!mEnable) return;
1065                        }
1066
1067                        mConnection.setGetNameAddressOnly(false);
1068                        //Register callback object
1069                        try {
1070                            mBluetooth.registerCallback(mBluetoothCallback);
1071                        } catch (RemoteException re) {
1072                            Log.e(TAG, "Unable to register BluetoothCallback",re);
1073                        }
1074                        //Inform BluetoothAdapter instances that service is up
1075                        sendBluetoothServiceUpCallback();
1076
1077                        //Do enable request
1078                        try {
1079                            if (mQuietEnable == false) {
1080                                if(!mBluetooth.enable()) {
1081                                    Log.e(TAG,"IBluetooth.enable() returned false");
1082                                }
1083                            }
1084                            else
1085                            {
1086                                if(!mBluetooth.enableNoAutoConnect()) {
1087                                    Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1088                                }
1089                            }
1090                        } catch (RemoteException e) {
1091                            Log.e(TAG,"Unable to call enable()",e);
1092                        }
1093                    }
1094
1095                    if (!mEnable) {
1096                        waitForOnOff(true, false);
1097                        handleDisable();
1098                        waitForOnOff(false, false);
1099                    }
1100                    break;
1101                }
1102                case MESSAGE_TIMEOUT_BIND: {
1103                    Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
1104                    synchronized(mConnection) {
1105                        mBinding = false;
1106                    }
1107                    break;
1108                }
1109                case MESSAGE_BLUETOOTH_STATE_CHANGE:
1110                {
1111                    int prevState = msg.arg1;
1112                    int newState = msg.arg2;
1113                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
1114                    mState = newState;
1115                    bluetoothStateChangeHandler(prevState, newState);
1116                    // handle error state transition case from TURNING_ON to OFF
1117                    // unbind and rebind bluetooth service and enable bluetooth
1118                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1119                        (newState == BluetoothAdapter.STATE_OFF) &&
1120                        (mBluetooth != null) && mEnable) {
1121                        recoverBluetoothServiceFromError();
1122                    }
1123                    if (newState == BluetoothAdapter.STATE_ON) {
1124                        // bluetooth is working, reset the counter
1125                        if (mErrorRecoveryRetryCounter != 0) {
1126                            Log.w(TAG, "bluetooth is recovered from error");
1127                            mErrorRecoveryRetryCounter = 0;
1128                        }
1129                    }
1130                    break;
1131                }
1132                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1133                {
1134                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
1135                    synchronized(mConnection) {
1136                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
1137                            // if service is unbinded already, do nothing and return
1138                            if (mBluetooth == null) break;
1139                            mBluetooth = null;
1140                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1141                            mBluetoothGatt = null;
1142                            break;
1143                        } else {
1144                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
1145                            break;
1146                        }
1147                    }
1148
1149                    if (mEnable) {
1150                        mEnable = false;
1151                        // Send a Bluetooth Restart message
1152                        Message restartMsg = mHandler.obtainMessage(
1153                            MESSAGE_RESTART_BLUETOOTH_SERVICE);
1154                        mHandler.sendMessageDelayed(restartMsg,
1155                            SERVICE_RESTART_TIME_MS);
1156                    }
1157
1158                    if (!mConnection.isGetNameAddressOnly()) {
1159                        sendBluetoothServiceDownCallback();
1160
1161                        // Send BT state broadcast to update
1162                        // the BT icon correctly
1163                        if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1164                            (mState == BluetoothAdapter.STATE_ON)) {
1165                            bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1166                                                        BluetoothAdapter.STATE_TURNING_OFF);
1167                            mState = BluetoothAdapter.STATE_TURNING_OFF;
1168                        }
1169                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1170                            bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1171                                                        BluetoothAdapter.STATE_OFF);
1172                        }
1173
1174                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1175                        mState = BluetoothAdapter.STATE_OFF;
1176                    }
1177                    break;
1178                }
1179                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1180                {
1181                    Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1182                        +" Restart IBluetooth service");
1183                    /* Enable without persisting the setting as
1184                     it doesnt change when IBluetooth
1185                     service restarts */
1186                    mEnable = true;
1187                    handleEnable(mQuietEnable);
1188                    break;
1189                }
1190
1191                case MESSAGE_TIMEOUT_UNBIND:
1192                {
1193                    Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
1194                    synchronized(mConnection) {
1195                        mUnbinding = false;
1196                    }
1197                    break;
1198                }
1199
1200                case MESSAGE_USER_SWITCHED:
1201                {
1202                    if (DBG) {
1203                        Log.d(TAG, "MESSAGE_USER_SWITCHED");
1204                    }
1205                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1206                    /* disable and enable BT when detect a user switch */
1207                    if (mEnable && mBluetooth != null) {
1208                        synchronized (mConnection) {
1209                            if (mBluetooth != null) {
1210                                //Unregister callback object
1211                                try {
1212                                    mBluetooth.unregisterCallback(mBluetoothCallback);
1213                                } catch (RemoteException re) {
1214                                    Log.e(TAG, "Unable to unregister",re);
1215                                }
1216                            }
1217                        }
1218
1219                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1220                            // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1221                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1222                            mState = BluetoothAdapter.STATE_OFF;
1223                        }
1224                        if (mState == BluetoothAdapter.STATE_OFF) {
1225                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1226                            mState = BluetoothAdapter.STATE_TURNING_ON;
1227                        }
1228
1229                        waitForOnOff(true, false);
1230
1231                        if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1232                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1233                        }
1234
1235                        unbindAllBluetoothProfileServices();
1236                        // disable
1237                        handleDisable();
1238                        // Pbap service need receive STATE_TURNING_OFF intent to close
1239                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1240                                                    BluetoothAdapter.STATE_TURNING_OFF);
1241
1242                        waitForOnOff(false, true);
1243
1244                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1245                                                    BluetoothAdapter.STATE_OFF);
1246                        sendBluetoothServiceDownCallback();
1247                        synchronized (mConnection) {
1248                            if (mBluetooth != null) {
1249                                mBluetooth = null;
1250                                //Unbind
1251                                mContext.unbindService(mConnection);
1252                            }
1253                        }
1254                        SystemClock.sleep(100);
1255
1256                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1257                        mState = BluetoothAdapter.STATE_OFF;
1258                        // enable
1259                        handleEnable(mQuietEnable);
1260                    } else if (mBinding || mBluetooth != null) {
1261                        Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1262                        userMsg.arg2 = 1 + msg.arg2;
1263                        // if user is switched when service is being binding
1264                        // delay sending MESSAGE_USER_SWITCHED
1265                        mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1266                        if (DBG) {
1267                            Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1268                        }
1269                    }
1270                    break;
1271                }
1272            }
1273        }
1274    }
1275
1276    private void handleEnable(boolean quietMode) {
1277        mQuietEnable = quietMode;
1278
1279        synchronized(mConnection) {
1280            if ((mBluetooth == null) && (!mBinding)) {
1281                //Start bind timeout and bind
1282                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1283                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1284                mConnection.setGetNameAddressOnly(false);
1285                Intent i = new Intent(IBluetooth.class.getName());
1286                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1287                        UserHandle.CURRENT)) {
1288                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1289                } else {
1290                    mBinding = true;
1291                }
1292            } else if (mBluetooth != null) {
1293                if (mConnection.isGetNameAddressOnly()) {
1294                    // if GetNameAddressOnly is set, we can clear this flag,
1295                    // so the service won't be unbind
1296                    // after name and address are saved
1297                    mConnection.setGetNameAddressOnly(false);
1298                    //Register callback object
1299                    try {
1300                        mBluetooth.registerCallback(mBluetoothCallback);
1301                    } catch (RemoteException re) {
1302                        Log.e(TAG, "Unable to register BluetoothCallback",re);
1303                    }
1304                    //Inform BluetoothAdapter instances that service is up
1305                    sendBluetoothServiceUpCallback();
1306                }
1307
1308                //Enable bluetooth
1309                try {
1310                    if (!mQuietEnable) {
1311                        if(!mBluetooth.enable()) {
1312                            Log.e(TAG,"IBluetooth.enable() returned false");
1313                        }
1314                    }
1315                    else {
1316                        if(!mBluetooth.enableNoAutoConnect()) {
1317                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1318                        }
1319                    }
1320                } catch (RemoteException e) {
1321                    Log.e(TAG,"Unable to call enable()",e);
1322                }
1323            }
1324        }
1325    }
1326
1327    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1328        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1329        intent.setComponent(comp);
1330        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1331            Log.e(TAG, "Fail to bind to: " + intent);
1332            return false;
1333        }
1334        return true;
1335    }
1336
1337    private void handleDisable() {
1338        synchronized(mConnection) {
1339            // don't need to disable if GetNameAddressOnly is set,
1340            // service will be unbinded after Name and Address are saved
1341            if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
1342                if (DBG) Log.d(TAG,"Sending off request.");
1343
1344                try {
1345                    if(!mBluetooth.disable()) {
1346                        Log.e(TAG,"IBluetooth.disable() returned false");
1347                    }
1348                } catch (RemoteException e) {
1349                    Log.e(TAG,"Unable to call disable()",e);
1350                }
1351            }
1352        }
1353    }
1354
1355    private boolean checkIfCallerIsForegroundUser() {
1356        int foregroundUser;
1357        int callingUser = UserHandle.getCallingUserId();
1358        int callingUid = Binder.getCallingUid();
1359        long callingIdentity = Binder.clearCallingIdentity();
1360        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1361        UserInfo ui = um.getProfileParent(callingUser);
1362        int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
1363        int callingAppId = UserHandle.getAppId(callingUid);
1364        boolean valid = false;
1365        try {
1366            foregroundUser = ActivityManager.getCurrentUser();
1367            valid = (callingUser == foregroundUser) ||
1368                    parentUser == foregroundUser    ||
1369                    callingAppId == Process.NFC_UID ||
1370                    callingAppId == mSystemUiUid;
1371            if (DBG) {
1372                Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1373                    + " callingUser=" + callingUser
1374                    + " parentUser=" + parentUser
1375                    + " foregroundUser=" + foregroundUser);
1376            }
1377        } finally {
1378            Binder.restoreCallingIdentity(callingIdentity);
1379        }
1380        return valid;
1381    }
1382
1383    private void bluetoothStateChangeHandler(int prevState, int newState) {
1384        if (prevState != newState) {
1385            //Notify all proxy objects first of adapter state change
1386            if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1387                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1388                sendBluetoothStateCallback(isUp);
1389
1390                if (isUp) {
1391                    // connect to GattService
1392                    if (mContext.getPackageManager().hasSystemFeature(
1393                                                     PackageManager.FEATURE_BLUETOOTH_LE)) {
1394                        Intent i = new Intent(IBluetoothGatt.class.getName());
1395                        doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1396                                UserHandle.CURRENT);
1397                    }
1398                } else {
1399                    //If Bluetooth is off, send service down event to proxy objects, and unbind
1400                    if (!isUp && canUnbindBluetoothService()) {
1401                        unbindAllBluetoothProfileServices();
1402                        sendBluetoothServiceDownCallback();
1403                        unbindAndFinish();
1404                    }
1405                }
1406            }
1407
1408            //Send broadcast message to everyone else
1409            Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1410            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1411            intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1412            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1413            if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1414            mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1415                    BLUETOOTH_PERM);
1416        }
1417    }
1418
1419    /**
1420     *  if on is true, wait for state become ON
1421     *  if off is true, wait for state become OFF
1422     *  if both on and off are false, wait for state not ON
1423     */
1424    private boolean waitForOnOff(boolean on, boolean off) {
1425        int i = 0;
1426        while (i < 10) {
1427            synchronized(mConnection) {
1428                try {
1429                    if (mBluetooth == null) break;
1430                    if (on) {
1431                        if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1432                    } else if (off) {
1433                        if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1434                    } else {
1435                        if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1436                    }
1437                } catch (RemoteException e) {
1438                    Log.e(TAG, "getState()", e);
1439                    break;
1440                }
1441            }
1442            if (on || off) {
1443                SystemClock.sleep(300);
1444            } else {
1445                SystemClock.sleep(50);
1446            }
1447            i++;
1448        }
1449        Log.e(TAG,"waitForOnOff time out");
1450        return false;
1451    }
1452
1453    private void sendDisableMsg() {
1454        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1455    }
1456
1457    private void sendEnableMsg(boolean quietMode) {
1458        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1459                             quietMode ? 1 : 0, 0));
1460    }
1461
1462    private boolean canUnbindBluetoothService() {
1463        synchronized(mConnection) {
1464            //Only unbind with mEnable flag not set
1465            //For race condition: disable and enable back-to-back
1466            //Avoid unbind right after enable due to callback from disable
1467            //Only unbind with Bluetooth at OFF state
1468            //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1469            try {
1470                if (mEnable || (mBluetooth == null)) return false;
1471                if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1472                return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1473            } catch (RemoteException e) {
1474                Log.e(TAG, "getState()", e);
1475            }
1476        }
1477        return false;
1478    }
1479
1480    private void recoverBluetoothServiceFromError() {
1481        Log.e(TAG,"recoverBluetoothServiceFromError");
1482        synchronized (mConnection) {
1483            if (mBluetooth != null) {
1484                //Unregister callback object
1485                try {
1486                    mBluetooth.unregisterCallback(mBluetoothCallback);
1487                } catch (RemoteException re) {
1488                    Log.e(TAG, "Unable to unregister",re);
1489                }
1490            }
1491        }
1492
1493        SystemClock.sleep(500);
1494
1495        // disable
1496        handleDisable();
1497
1498        waitForOnOff(false, true);
1499
1500        sendBluetoothServiceDownCallback();
1501        synchronized (mConnection) {
1502            if (mBluetooth != null) {
1503                mBluetooth = null;
1504                //Unbind
1505                mContext.unbindService(mConnection);
1506            }
1507        }
1508
1509        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1510        mState = BluetoothAdapter.STATE_OFF;
1511
1512        mEnable = false;
1513
1514        if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1515            // Send a Bluetooth Restart message to reenable bluetooth
1516            Message restartMsg = mHandler.obtainMessage(
1517                             MESSAGE_RESTART_BLUETOOTH_SERVICE);
1518            mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1519        } else {
1520            // todo: notify user to power down and power up phone to make bluetooth work.
1521        }
1522    }
1523
1524    @Override
1525    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1526        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1527
1528        writer.println("Bluetooth Status");
1529        writer.println("  enabled: " + mEnable);
1530        writer.println("  state: " + mState);
1531        writer.println("  address: " + mAddress);
1532        writer.println("  name: " + mName + "\n");
1533        writer.flush();
1534
1535        if (mBluetooth == null) {
1536            writer.println("Bluetooth Service not connected");
1537        } else {
1538            try {
1539                ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd);
1540                mBluetooth.dump(pfd);
1541                pfd.close();
1542            } catch (RemoteException re) {
1543                writer.println("RemoteException while calling Bluetooth Service");
1544            } catch (IOException re) {
1545                writer.println("IOException attempting to dup() fd");
1546            }
1547        }
1548    }
1549}
1550