BluetoothManagerService.java revision 55db646c4e43fd24386bf522aef13c0b3075593c
10f42037eb7b5118015c2caca635538324ccf0ccffredc/*
2fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Copyright (C) 2012 The Android Open Source Project
3fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *
4fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Licensed under the Apache License, Version 2.0 (the "License");
5fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * you may not use this file except in compliance with the License.
6fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * You may obtain a copy of the License at
7fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *
8fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *      http://www.apache.org/licenses/LICENSE-2.0
9fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *
10fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Unless required by applicable law or agreed to in writing, software
11fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * distributed under the License is distributed on an "AS IS" BASIS,
12fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * See the License for the specific language governing permissions and
14fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * limitations under the License.
150f42037eb7b5118015c2caca635538324ccf0ccffredc */
160f42037eb7b5118015c2caca635538324ccf0ccffredc
170f42037eb7b5118015c2caca635538324ccf0ccffredcpackage com.android.server;
180f42037eb7b5118015c2caca635538324ccf0ccffredc
1940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xuimport android.app.ActivityManager;
200f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.bluetooth.BluetoothAdapter;
210f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.bluetooth.IBluetooth;
22ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xieimport android.bluetooth.IBluetoothGatt;
23bf072a712f584ae1c01022835b0de21c40513d06fredcimport android.bluetooth.IBluetoothCallback;
240f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.bluetooth.IBluetoothManager;
250f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.bluetooth.IBluetoothManagerCallback;
260f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.bluetooth.IBluetoothStateChangeCallback;
270f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.BroadcastReceiver;
280f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.ComponentName;
290f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.ContentResolver;
300f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.Context;
310f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.Intent;
320f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.IntentFilter;
330f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.ServiceConnection;
3432ab77b4c52db78aea22cb32824c7fd68d6f8c21Matthew Xieimport android.content.pm.PackageManager;
3540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xuimport android.os.Binder;
360f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.os.Handler;
370f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.os.IBinder;
3840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xuimport android.os.Looper;
390f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.os.Message;
4040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xuimport android.os.Process;
41d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredcimport android.os.RemoteCallbackList;
420f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.os.RemoteException;
4340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xuimport android.os.SystemClock;
445ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
450f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.provider.Settings;
460f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.util.Log;
470f42037eb7b5118015c2caca635538324ccf0ccffredcclass BluetoothManagerService extends IBluetoothManager.Stub {
480f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String TAG = "BluetoothManagerService";
490f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final boolean DBG = true;
500f42037eb7b5118015c2caca635538324ccf0ccffredc
510f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
520f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
530f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
540f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String EXTRA_ACTION="action";
55d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu    private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
560f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
570f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
580f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
590f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
601223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M    //Maximum msec to wait for service restart
611223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M    private static final int SERVICE_RESTART_TIME_MS = 200;
62dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu    //Maximum msec to wait for restart due to error
63dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu    private static final int ERROR_RESTART_TIME_MS = 3000;
6440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    //Maximum msec to delay MESSAGE_USER_SWITCHED
6540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private static final int USER_SWITCHED_TIME_MS = 200;
660f42037eb7b5118015c2caca635538324ccf0ccffredc
670f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MESSAGE_ENABLE = 1;
680f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MESSAGE_DISABLE = 2;
69649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private static final int MESSAGE_REGISTER_ADAPTER = 20;
70649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
71649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
72649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
73649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
74649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
751223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M    private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
76bf072a712f584ae1c01022835b0de21c40513d06fredc    private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
770f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MESSAGE_TIMEOUT_BIND =100;
780f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MESSAGE_TIMEOUT_UNBIND =101;
790f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
800f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
8140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private static final int MESSAGE_USER_SWITCHED = 300;
820f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final int MAX_SAVE_RETRIES=3;
83dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu    private static final int MAX_ERROR_RESTART_RETRIES=6;
84dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
85401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // Bluetooth persisted setting is off
86401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private static final int BLUETOOTH_OFF=0;
87401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // Bluetooth persisted setting is on
88401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // and Airplane mode won't affect Bluetooth state at start up
89401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private static final int BLUETOOTH_ON_BLUETOOTH=1;
90401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // Bluetooth persisted setting is on
91401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // but Airplane mode will affect Bluetooth state at start up
92401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // and Airplane mode will have higher priority.
93401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private static final int BLUETOOTH_ON_AIRPLANE=2;
940f42037eb7b5118015c2caca635538324ccf0ccffredc
95ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private static final int SERVICE_IBLUETOOTH = 1;
96ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private static final int SERVICE_IBLUETOOTHGATT = 2;
97ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
980f42037eb7b5118015c2caca635538324ccf0ccffredc    private final Context mContext;
99cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie
100cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie    // Locks are not provided for mName and mAddress.
101cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie    // They are accessed in handler or broadcast receiver, same thread context.
1020f42037eb7b5118015c2caca635538324ccf0ccffredc    private String mAddress;
1030f42037eb7b5118015c2caca635538324ccf0ccffredc    private String mName;
1046fde3098074ab2551867d1cd919958383b15725fMatthew Xie    private final ContentResolver mContentResolver;
1056fde3098074ab2551867d1cd919958383b15725fMatthew Xie    private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
1066fde3098074ab2551867d1cd919958383b15725fMatthew Xie    private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
107649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private IBluetooth mBluetooth;
108ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private IBluetoothGatt mBluetoothGatt;
109649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private boolean mBinding;
110649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private boolean mUnbinding;
111401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // used inside handler thread
112fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta    private boolean mQuietEnable = false;
113401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // configuarion from external IBinder call which is used to
114401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // synchronize with broadcast receiver.
115401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private boolean mQuietEnableExternal;
116401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // configuarion from external IBinder call which is used to
117401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // synchronize with broadcast receiver.
118401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private boolean mEnableExternal;
119401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    // used inside handler thread
12040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private boolean mEnable;
12140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private int mState;
12240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private final BluetoothHandler mHandler;
123dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu    private int mErrorRecoveryRetryCounter;
1240f42037eb7b5118015c2caca635538324ccf0ccffredc
125649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private void registerForAirplaneMode(IntentFilter filter) {
126649fe497cea2f19e937f84218d1080bdcefe47f2fredc        final ContentResolver resolver = mContext.getContentResolver();
127c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate        final String airplaneModeRadios = Settings.Global.getString(resolver,
128c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate                Settings.Global.AIRPLANE_MODE_RADIOS);
129c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate        final String toggleableRadios = Settings.Global.getString(resolver,
130c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
131649fe497cea2f19e937f84218d1080bdcefe47f2fredc        boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
132c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate                airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
133649fe497cea2f19e937f84218d1080bdcefe47f2fredc        if (mIsAirplaneSensitive) {
134649fe497cea2f19e937f84218d1080bdcefe47f2fredc            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
135649fe497cea2f19e937f84218d1080bdcefe47f2fredc        }
136649fe497cea2f19e937f84218d1080bdcefe47f2fredc    }
1370f42037eb7b5118015c2caca635538324ccf0ccffredc
138bf072a712f584ae1c01022835b0de21c40513d06fredc    private final IBluetoothCallback mBluetoothCallback =  new IBluetoothCallback.Stub() {
139bf072a712f584ae1c01022835b0de21c40513d06fredc        @Override
140bf072a712f584ae1c01022835b0de21c40513d06fredc        public void onBluetoothStateChange(int prevState, int newState) throws RemoteException  {
141bf072a712f584ae1c01022835b0de21c40513d06fredc            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
142bf072a712f584ae1c01022835b0de21c40513d06fredc            mHandler.sendMessage(msg);
143bf072a712f584ae1c01022835b0de21c40513d06fredc        }
144bf072a712f584ae1c01022835b0de21c40513d06fredc    };
145bf072a712f584ae1c01022835b0de21c40513d06fredc
146bf072a712f584ae1c01022835b0de21c40513d06fredc    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1470f42037eb7b5118015c2caca635538324ccf0ccffredc        @Override
1480f42037eb7b5118015c2caca635538324ccf0ccffredc        public void onReceive(Context context, Intent intent) {
1490f42037eb7b5118015c2caca635538324ccf0ccffredc            String action = intent.getAction();
150bf072a712f584ae1c01022835b0de21c40513d06fredc            if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
1510f42037eb7b5118015c2caca635538324ccf0ccffredc                String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
152a8c6df0d3a6b929cac3e59abde8309e8a45ea78aFred                if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
1530f42037eb7b5118015c2caca635538324ccf0ccffredc                if (newName != null) {
1540f42037eb7b5118015c2caca635538324ccf0ccffredc                    storeNameAndAddress(newName, null);
1550f42037eb7b5118015c2caca635538324ccf0ccffredc                }
156649fe497cea2f19e937f84218d1080bdcefe47f2fredc            } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
157401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                synchronized(mReceiver) {
158401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    if (isBluetoothPersistedStateOn()) {
159401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        if (isAirplaneModeOn()) {
160401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                            persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
161401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        } else {
162401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
163401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        }
164401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    }
165401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    if (isAirplaneModeOn()) {
166401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        // disable without persisting the setting
167401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        sendDisableMsg();
168401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    } else if (mEnableExternal) {
169401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        // enable without persisting the setting
170401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        sendEnableMsg(mQuietEnableExternal);
171401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    }
172649fe497cea2f19e937f84218d1080bdcefe47f2fredc                }
17340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
17440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
17540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
176401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
177401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                synchronized(mReceiver) {
178401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
179401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        //Enable
180401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
181401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        sendEnableMsg(mQuietEnableExternal);
182401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    }
183401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                }
184401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu
185401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                if (!isNameAndAddressSet()) {
186401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    //Sync the Bluetooth name and address from the Bluetooth Adapter
187401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
188401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    getNameAndAddress();
189401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                }
1900f42037eb7b5118015c2caca635538324ccf0ccffredc            }
1910f42037eb7b5118015c2caca635538324ccf0ccffredc        }
1920f42037eb7b5118015c2caca635538324ccf0ccffredc    };
1930f42037eb7b5118015c2caca635538324ccf0ccffredc
1940f42037eb7b5118015c2caca635538324ccf0ccffredc    BluetoothManagerService(Context context) {
1958d044e8bc287c1a567d82aedbe30085b011544c3Dianne Hackborn        mHandler = new BluetoothHandler(IoThread.get().getLooper());
19640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
1970f42037eb7b5118015c2caca635538324ccf0ccffredc        mContext = context;
1980f42037eb7b5118015c2caca635538324ccf0ccffredc        mBluetooth = null;
1990f42037eb7b5118015c2caca635538324ccf0ccffredc        mBinding = false;
2000f42037eb7b5118015c2caca635538324ccf0ccffredc        mUnbinding = false;
20140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        mEnable = false;
20240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        mState = BluetoothAdapter.STATE_OFF;
203401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        mQuietEnableExternal = false;
204401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        mEnableExternal = false;
2050f42037eb7b5118015c2caca635538324ccf0ccffredc        mAddress = null;
2060f42037eb7b5118015c2caca635538324ccf0ccffredc        mName = null;
207dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        mErrorRecoveryRetryCounter = 0;
2080f42037eb7b5118015c2caca635538324ccf0ccffredc        mContentResolver = context.getContentResolver();
209d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc        mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
210d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc        mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
211401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
2126fde3098074ab2551867d1cd919958383b15725fMatthew Xie        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
21340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        filter.addAction(Intent.ACTION_USER_SWITCHED);
2146fde3098074ab2551867d1cd919958383b15725fMatthew Xie        registerForAirplaneMode(filter);
2156fde3098074ab2551867d1cd919958383b15725fMatthew Xie        mContext.registerReceiver(mReceiver, filter);
2160f42037eb7b5118015c2caca635538324ccf0ccffredc        loadStoredNameAndAddress();
217401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        if (isBluetoothPersistedStateOn()) {
218401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            mEnableExternal = true;
2190f42037eb7b5118015c2caca635538324ccf0ccffredc        }
2200f42037eb7b5118015c2caca635538324ccf0ccffredc    }
2210f42037eb7b5118015c2caca635538324ccf0ccffredc
222649fe497cea2f19e937f84218d1080bdcefe47f2fredc    /**
223649fe497cea2f19e937f84218d1080bdcefe47f2fredc     *  Returns true if airplane mode is currently on
224649fe497cea2f19e937f84218d1080bdcefe47f2fredc     */
225649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private final boolean isAirplaneModeOn() {
226c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate        return Settings.Global.getInt(mContext.getContentResolver(),
227c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
228649fe497cea2f19e937f84218d1080bdcefe47f2fredc    }
229649fe497cea2f19e937f84218d1080bdcefe47f2fredc
230649fe497cea2f19e937f84218d1080bdcefe47f2fredc    /**
231649fe497cea2f19e937f84218d1080bdcefe47f2fredc     *  Returns true if the Bluetooth saved state is "on"
232649fe497cea2f19e937f84218d1080bdcefe47f2fredc     */
233649fe497cea2f19e937f84218d1080bdcefe47f2fredc    private final boolean isBluetoothPersistedStateOn() {
234bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown        return Settings.Global.getInt(mContentResolver,
235401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
236401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    }
237401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu
238401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    /**
239401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu     *  Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
240401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu     */
241401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private final boolean isBluetoothPersistedStateOnBluetooth() {
242401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        return Settings.Global.getInt(mContentResolver,
243401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
244649fe497cea2f19e937f84218d1080bdcefe47f2fredc    }
245649fe497cea2f19e937f84218d1080bdcefe47f2fredc
246649fe497cea2f19e937f84218d1080bdcefe47f2fredc    /**
247649fe497cea2f19e937f84218d1080bdcefe47f2fredc     *  Save the Bluetooth on/off state
248649fe497cea2f19e937f84218d1080bdcefe47f2fredc     *
249649fe497cea2f19e937f84218d1080bdcefe47f2fredc     */
250401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private void persistBluetoothSetting(int value) {
251bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown        Settings.Global.putInt(mContext.getContentResolver(),
252bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown                               Settings.Global.BLUETOOTH_ON,
253401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                               value);
254649fe497cea2f19e937f84218d1080bdcefe47f2fredc    }
255649fe497cea2f19e937f84218d1080bdcefe47f2fredc
256649fe497cea2f19e937f84218d1080bdcefe47f2fredc    /**
257649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * Returns true if the Bluetooth Adapter's name and address is
258649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * locally cached
259649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * @return
260649fe497cea2f19e937f84218d1080bdcefe47f2fredc     */
2610f42037eb7b5118015c2caca635538324ccf0ccffredc    private boolean isNameAndAddressSet() {
2620f42037eb7b5118015c2caca635538324ccf0ccffredc        return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
2630f42037eb7b5118015c2caca635538324ccf0ccffredc    }
2640f42037eb7b5118015c2caca635538324ccf0ccffredc
265649fe497cea2f19e937f84218d1080bdcefe47f2fredc    /**
266649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * Retrieve the Bluetooth Adapter's name and address and save it in
267649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * in the local cache
268649fe497cea2f19e937f84218d1080bdcefe47f2fredc     */
2690f42037eb7b5118015c2caca635538324ccf0ccffredc    private void loadStoredNameAndAddress() {
2700f42037eb7b5118015c2caca635538324ccf0ccffredc        if (DBG) Log.d(TAG, "Loading stored name and address");
271d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu        if (mContext.getResources().getBoolean
272d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu            (com.android.internal.R.bool.config_bluetooth_address_validation) &&
273d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu             Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
274d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu            // if the valid flag is not set, don't load the address and name
275d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu            if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
276d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu            return;
277d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu        }
2780f42037eb7b5118015c2caca635538324ccf0ccffredc        mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
2790f42037eb7b5118015c2caca635538324ccf0ccffredc        mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
280d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu        if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
2810f42037eb7b5118015c2caca635538324ccf0ccffredc    }
2820f42037eb7b5118015c2caca635538324ccf0ccffredc
283649fe497cea2f19e937f84218d1080bdcefe47f2fredc    /**
284649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * Save the Bluetooth name and address in the persistent store.
285649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * Only non-null values will be saved.
286649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * @param name
287649fe497cea2f19e937f84218d1080bdcefe47f2fredc     * @param address
288649fe497cea2f19e937f84218d1080bdcefe47f2fredc     */
2890f42037eb7b5118015c2caca635538324ccf0ccffredc    private void storeNameAndAddress(String name, String address) {
2900f42037eb7b5118015c2caca635538324ccf0ccffredc        if (name != null) {
2910f42037eb7b5118015c2caca635538324ccf0ccffredc            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
2920f42037eb7b5118015c2caca635538324ccf0ccffredc            mName = name;
293649fe497cea2f19e937f84218d1080bdcefe47f2fredc            if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
294649fe497cea2f19e937f84218d1080bdcefe47f2fredc                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
2950f42037eb7b5118015c2caca635538324ccf0ccffredc        }
2960f42037eb7b5118015c2caca635538324ccf0ccffredc
2970f42037eb7b5118015c2caca635538324ccf0ccffredc        if (address != null) {
2980f42037eb7b5118015c2caca635538324ccf0ccffredc            Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
2990f42037eb7b5118015c2caca635538324ccf0ccffredc            mAddress=address;
300649fe497cea2f19e937f84218d1080bdcefe47f2fredc            if (DBG)  Log.d(TAG,"Stored Bluetoothaddress: " +
301649fe497cea2f19e937f84218d1080bdcefe47f2fredc                Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
3020f42037eb7b5118015c2caca635538324ccf0ccffredc        }
303d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu
304d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu        if ((name != null) && (address != null)) {
305d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu            Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
306d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu        }
3070f42037eb7b5118015c2caca635538324ccf0ccffredc    }
3080f42037eb7b5118015c2caca635538324ccf0ccffredc
3090f42037eb7b5118015c2caca635538324ccf0ccffredc    public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
31055db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich        if (callback == null) {
31155db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich            Log.w(TAG, "Callback is null in registerAdapter");
31255db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich            return null;
31355db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich        }
3140f42037eb7b5118015c2caca635538324ccf0ccffredc        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
3150f42037eb7b5118015c2caca635538324ccf0ccffredc        msg.obj = callback;
3160f42037eb7b5118015c2caca635538324ccf0ccffredc        mHandler.sendMessage(msg);
3170f42037eb7b5118015c2caca635538324ccf0ccffredc        synchronized(mConnection) {
3180f42037eb7b5118015c2caca635538324ccf0ccffredc            return mBluetooth;
3190f42037eb7b5118015c2caca635538324ccf0ccffredc        }
3200f42037eb7b5118015c2caca635538324ccf0ccffredc    }
3210f42037eb7b5118015c2caca635538324ccf0ccffredc
3220f42037eb7b5118015c2caca635538324ccf0ccffredc    public void unregisterAdapter(IBluetoothManagerCallback callback) {
32355db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich        if (callback == null) {
32455db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich            Log.w(TAG, "Callback is null in unregisterAdapter");
32555db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich            return;
32655db646c4e43fd24386bf522aef13c0b3075593cNatalie Silvanovich        }
3270f42037eb7b5118015c2caca635538324ccf0ccffredc        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
3280f42037eb7b5118015c2caca635538324ccf0ccffredc                                                "Need BLUETOOTH permission");
3290f42037eb7b5118015c2caca635538324ccf0ccffredc        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
3300f42037eb7b5118015c2caca635538324ccf0ccffredc        msg.obj = callback;
3310f42037eb7b5118015c2caca635538324ccf0ccffredc        mHandler.sendMessage(msg);
3320f42037eb7b5118015c2caca635538324ccf0ccffredc    }
3330f42037eb7b5118015c2caca635538324ccf0ccffredc
3340f42037eb7b5118015c2caca635538324ccf0ccffredc    public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
3350f42037eb7b5118015c2caca635538324ccf0ccffredc        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
3360f42037eb7b5118015c2caca635538324ccf0ccffredc                                                "Need BLUETOOTH permission");
3370f42037eb7b5118015c2caca635538324ccf0ccffredc        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
3380f42037eb7b5118015c2caca635538324ccf0ccffredc        msg.obj = callback;
3390f42037eb7b5118015c2caca635538324ccf0ccffredc        mHandler.sendMessage(msg);
3400f42037eb7b5118015c2caca635538324ccf0ccffredc    }
3410f42037eb7b5118015c2caca635538324ccf0ccffredc
3420f42037eb7b5118015c2caca635538324ccf0ccffredc    public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
3430f42037eb7b5118015c2caca635538324ccf0ccffredc        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
3440f42037eb7b5118015c2caca635538324ccf0ccffredc                                                "Need BLUETOOTH permission");
3450f42037eb7b5118015c2caca635538324ccf0ccffredc        Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
3460f42037eb7b5118015c2caca635538324ccf0ccffredc        msg.obj = callback;
3470f42037eb7b5118015c2caca635538324ccf0ccffredc        mHandler.sendMessage(msg);
3480f42037eb7b5118015c2caca635538324ccf0ccffredc    }
3490f42037eb7b5118015c2caca635538324ccf0ccffredc
3500f42037eb7b5118015c2caca635538324ccf0ccffredc    public boolean isEnabled() {
3516eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
3526eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            (!checkIfCallerIsForegroundUser())) {
3536eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
35440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            return false;
35540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
35640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
3570f42037eb7b5118015c2caca635538324ccf0ccffredc        synchronized(mConnection) {
3580f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
3590f42037eb7b5118015c2caca635538324ccf0ccffredc                return (mBluetooth != null && mBluetooth.isEnabled());
3600f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (RemoteException e) {
3610f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG, "isEnabled()", e);
3620f42037eb7b5118015c2caca635538324ccf0ccffredc            }
3630f42037eb7b5118015c2caca635538324ccf0ccffredc        }
3640f42037eb7b5118015c2caca635538324ccf0ccffredc        return false;
3650f42037eb7b5118015c2caca635538324ccf0ccffredc    }
3660f42037eb7b5118015c2caca635538324ccf0ccffredc
3670f42037eb7b5118015c2caca635538324ccf0ccffredc    public void getNameAndAddress() {
368f24588615efa6c781ad963f1a5bbdf47359e1b53fredc        if (DBG) {
369cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie            Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
370cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                  " mBinding = " + mBinding);
371f24588615efa6c781ad963f1a5bbdf47359e1b53fredc        }
3720f42037eb7b5118015c2caca635538324ccf0ccffredc        Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
3730f42037eb7b5118015c2caca635538324ccf0ccffredc        mHandler.sendMessage(msg);
3740f42037eb7b5118015c2caca635538324ccf0ccffredc    }
375fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta    public boolean enableNoAutoConnect()
376fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta    {
377fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
378fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                                "Need BLUETOOTH ADMIN permission");
37940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
380fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta        if (DBG) {
381fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta            Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
382fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                    " mBinding = " + mBinding);
383fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta        }
3848385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
3858385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen
3868385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen        if (callingAppId != Process.NFC_UID) {
387fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta            throw new SecurityException("no permission to enable Bluetooth quietly");
388fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta        }
3898385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen
390401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        synchronized(mReceiver) {
391401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            mQuietEnableExternal = true;
392401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            mEnableExternal = true;
393401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            sendEnableMsg(true);
394401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        }
395fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta        return true;
396fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta
397fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta    }
3980f42037eb7b5118015c2caca635538324ccf0ccffredc    public boolean enable() {
3996eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
4006eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            (!checkIfCallerIsForegroundUser())) {
4016eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            Log.w(TAG,"enable(): not allowed for non-active and non system user");
40240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            return false;
403f24588615efa6c781ad963f1a5bbdf47359e1b53fredc        }
404f24588615efa6c781ad963f1a5bbdf47359e1b53fredc
405401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
406401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                                                "Need BLUETOOTH ADMIN permission");
407401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        if (DBG) {
408401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
409401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    " mBinding = " + mBinding);
410401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        }
411401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu
412401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        synchronized(mReceiver) {
413401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            mQuietEnableExternal = false;
414401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            mEnableExternal = true;
415401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            // waive WRITE_SECURE_SETTINGS permission check
416401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            long callingIdentity = Binder.clearCallingIdentity();
417401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
418401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            Binder.restoreCallingIdentity(callingIdentity);
419401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            sendEnableMsg(false);
420401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        }
421401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        return true;
4220f42037eb7b5118015c2caca635538324ccf0ccffredc    }
4230f42037eb7b5118015c2caca635538324ccf0ccffredc
4240f42037eb7b5118015c2caca635538324ccf0ccffredc    public boolean disable(boolean persist) {
4250f42037eb7b5118015c2caca635538324ccf0ccffredc        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4260f42037eb7b5118015c2caca635538324ccf0ccffredc                                                "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
42740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
4286eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
4296eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            (!checkIfCallerIsForegroundUser())) {
4306eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            Log.w(TAG,"disable(): not allowed for non-active and non system user");
43140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            return false;
43240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
43340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
434f24588615efa6c781ad963f1a5bbdf47359e1b53fredc        if (DBG) {
435cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie            Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
436cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                " mBinding = " + mBinding);
437cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        }
438f24588615efa6c781ad963f1a5bbdf47359e1b53fredc
439401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        synchronized(mReceiver) {
440401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            if (persist) {
441401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                // waive WRITE_SECURE_SETTINGS permission check
442401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                long callingIdentity = Binder.clearCallingIdentity();
443401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                persistBluetoothSetting(BLUETOOTH_OFF);
444401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                Binder.restoreCallingIdentity(callingIdentity);
445401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            }
446401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            mEnableExternal = false;
447401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu            sendDisableMsg();
448401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        }
4490f42037eb7b5118015c2caca635538324ccf0ccffredc        return true;
4500f42037eb7b5118015c2caca635538324ccf0ccffredc    }
4510f42037eb7b5118015c2caca635538324ccf0ccffredc
452649fe497cea2f19e937f84218d1080bdcefe47f2fredc    public void unbindAndFinish() {
453f24588615efa6c781ad963f1a5bbdf47359e1b53fredc        if (DBG) {
454cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie            Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
455cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                " mBinding = " + mBinding);
456f24588615efa6c781ad963f1a5bbdf47359e1b53fredc        }
457f24588615efa6c781ad963f1a5bbdf47359e1b53fredc
4580f42037eb7b5118015c2caca635538324ccf0ccffredc        synchronized (mConnection) {
4590f42037eb7b5118015c2caca635538324ccf0ccffredc            if (mUnbinding) return;
4600f42037eb7b5118015c2caca635538324ccf0ccffredc            mUnbinding = true;
46140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if (mBluetooth != null) {
462bf072a712f584ae1c01022835b0de21c40513d06fredc                if (!mConnection.isGetNameAddressOnly()) {
463bf072a712f584ae1c01022835b0de21c40513d06fredc                    //Unregister callback object
464bf072a712f584ae1c01022835b0de21c40513d06fredc                    try {
465bf072a712f584ae1c01022835b0de21c40513d06fredc                        mBluetooth.unregisterCallback(mBluetoothCallback);
466bf072a712f584ae1c01022835b0de21c40513d06fredc                    } catch (RemoteException re) {
46740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        Log.e(TAG, "Unable to unregister BluetoothCallback",re);
468bf072a712f584ae1c01022835b0de21c40513d06fredc                    }
469bf072a712f584ae1c01022835b0de21c40513d06fredc                }
4700f42037eb7b5118015c2caca635538324ccf0ccffredc                if (DBG) Log.d(TAG, "Sending unbind request.");
471d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                mBluetooth = null;
472d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                //Unbind
4730f42037eb7b5118015c2caca635538324ccf0ccffredc                mContext.unbindService(mConnection);
474d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                mUnbinding = false;
47540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                mBinding = false;
476f24588615efa6c781ad963f1a5bbdf47359e1b53fredc            } else {
477f24588615efa6c781ad963f1a5bbdf47359e1b53fredc                mUnbinding=false;
4780f42037eb7b5118015c2caca635538324ccf0ccffredc            }
4790f42037eb7b5118015c2caca635538324ccf0ccffredc        }
4800f42037eb7b5118015c2caca635538324ccf0ccffredc    }
4810f42037eb7b5118015c2caca635538324ccf0ccffredc
482ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    public IBluetoothGatt getBluetoothGatt() {
483ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        // sync protection
484ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        return mBluetoothGatt;
485ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    }
486ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
487bf072a712f584ae1c01022835b0de21c40513d06fredc    private void sendBluetoothStateCallback(boolean isUp) {
488bf072a712f584ae1c01022835b0de21c40513d06fredc        int n = mStateChangeCallbacks.beginBroadcast();
489a8c6df0d3a6b929cac3e59abde8309e8a45ea78aFred        if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
490bf072a712f584ae1c01022835b0de21c40513d06fredc        for (int i=0; i <n;i++) {
491bf072a712f584ae1c01022835b0de21c40513d06fredc            try {
492bf072a712f584ae1c01022835b0de21c40513d06fredc                mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
493bf072a712f584ae1c01022835b0de21c40513d06fredc            } catch (RemoteException e) {
494bf072a712f584ae1c01022835b0de21c40513d06fredc                Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
495bf072a712f584ae1c01022835b0de21c40513d06fredc            }
496bf072a712f584ae1c01022835b0de21c40513d06fredc        }
497bf072a712f584ae1c01022835b0de21c40513d06fredc        mStateChangeCallbacks.finishBroadcast();
498bf072a712f584ae1c01022835b0de21c40513d06fredc    }
499bf072a712f584ae1c01022835b0de21c40513d06fredc
500bf072a712f584ae1c01022835b0de21c40513d06fredc    /**
50140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu     * Inform BluetoothAdapter instances that Adapter service is up
50240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu     */
50340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private void sendBluetoothServiceUpCallback() {
50440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        if (!mConnection.isGetNameAddressOnly()) {
50540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
50640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            int n = mCallbacks.beginBroadcast();
50740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
50840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            for (int i=0; i <n;i++) {
50940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                try {
51040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
51140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                }  catch (RemoteException e) {
51240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
51340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                }
51440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            }
51540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            mCallbacks.finishBroadcast();
51640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
51740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    }
51840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    /**
519bf072a712f584ae1c01022835b0de21c40513d06fredc     * Inform BluetoothAdapter instances that Adapter service is down
520bf072a712f584ae1c01022835b0de21c40513d06fredc     */
521bf072a712f584ae1c01022835b0de21c40513d06fredc    private void sendBluetoothServiceDownCallback() {
522d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc        if (!mConnection.isGetNameAddressOnly()) {
523d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
524d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            int n = mCallbacks.beginBroadcast();
525d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
526d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            for (int i=0; i <n;i++) {
527d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                try {
528d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
529d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                }  catch (RemoteException e) {
530d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                    Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
531d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                }
532d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            }
533d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            mCallbacks.finishBroadcast();
534d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc        }
535d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc    }
5360f42037eb7b5118015c2caca635538324ccf0ccffredc    public String getAddress() {
537af5ddbfcf59e1e0bcbd43f1f88270f822c5083b8Matthew Xie        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
538af5ddbfcf59e1e0bcbd43f1f88270f822c5083b8Matthew Xie                                                "Need BLUETOOTH permission");
53940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
5406eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
5416eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            (!checkIfCallerIsForegroundUser())) {
5426eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
5436eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            return null;
54440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
54540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
546116d1d4696ac8e300c83dd8a95e20e67717ef520fredc        synchronized(mConnection) {
547116d1d4696ac8e300c83dd8a95e20e67717ef520fredc            if (mBluetooth != null) {
548116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                try {
549116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                    return mBluetooth.getAddress();
550116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                } catch (RemoteException e) {
551116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                    Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
552116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                }
553116d1d4696ac8e300c83dd8a95e20e67717ef520fredc            }
554116d1d4696ac8e300c83dd8a95e20e67717ef520fredc        }
555cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        // mAddress is accessed from outside.
556cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        // It is alright without a lock. Here, bluetooth is off, no other thread is
557cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        // changing mAddress
5580f42037eb7b5118015c2caca635538324ccf0ccffredc        return mAddress;
5590f42037eb7b5118015c2caca635538324ccf0ccffredc    }
560649fe497cea2f19e937f84218d1080bdcefe47f2fredc
5610f42037eb7b5118015c2caca635538324ccf0ccffredc    public String getName() {
562af5ddbfcf59e1e0bcbd43f1f88270f822c5083b8Matthew Xie        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
563af5ddbfcf59e1e0bcbd43f1f88270f822c5083b8Matthew Xie                                                "Need BLUETOOTH permission");
56440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
5656eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
5666eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            (!checkIfCallerIsForegroundUser())) {
5676eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            Log.w(TAG,"getName(): not allowed for non-active and non system user");
5686eb7652b04b92b0c3786d96e6a97f5f4e46aec69Zhihai Xu            return null;
56940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
57040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
571116d1d4696ac8e300c83dd8a95e20e67717ef520fredc        synchronized(mConnection) {
572116d1d4696ac8e300c83dd8a95e20e67717ef520fredc            if (mBluetooth != null) {
573116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                try {
574116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                    return mBluetooth.getName();
575116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                } catch (RemoteException e) {
576116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                    Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
577116d1d4696ac8e300c83dd8a95e20e67717ef520fredc                }
578116d1d4696ac8e300c83dd8a95e20e67717ef520fredc            }
579116d1d4696ac8e300c83dd8a95e20e67717ef520fredc        }
580cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        // mName is accessed from outside.
581cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        // It alright without a lock. Here, bluetooth is off, no other thread is
582cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        // changing mName
5830f42037eb7b5118015c2caca635538324ccf0ccffredc        return mName;
5840f42037eb7b5118015c2caca635538324ccf0ccffredc    }
5850f42037eb7b5118015c2caca635538324ccf0ccffredc
5860f42037eb7b5118015c2caca635538324ccf0ccffredc    private class BluetoothServiceConnection implements ServiceConnection {
5870f42037eb7b5118015c2caca635538324ccf0ccffredc
5880f42037eb7b5118015c2caca635538324ccf0ccffredc        private boolean mGetNameAddressOnly;
5890f42037eb7b5118015c2caca635538324ccf0ccffredc
5900f42037eb7b5118015c2caca635538324ccf0ccffredc        public void setGetNameAddressOnly(boolean getOnly) {
5910f42037eb7b5118015c2caca635538324ccf0ccffredc            mGetNameAddressOnly = getOnly;
5920f42037eb7b5118015c2caca635538324ccf0ccffredc        }
5930f42037eb7b5118015c2caca635538324ccf0ccffredc
5940f42037eb7b5118015c2caca635538324ccf0ccffredc        public boolean isGetNameAddressOnly() {
5950f42037eb7b5118015c2caca635538324ccf0ccffredc            return mGetNameAddressOnly;
5960f42037eb7b5118015c2caca635538324ccf0ccffredc        }
5970f42037eb7b5118015c2caca635538324ccf0ccffredc
5980f42037eb7b5118015c2caca635538324ccf0ccffredc        public void onServiceConnected(ComponentName className, IBinder service) {
599ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
6000f42037eb7b5118015c2caca635538324ccf0ccffredc            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
601ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
602ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
603ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                msg.arg1 = SERVICE_IBLUETOOTH;
604ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
605ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
606ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                msg.arg1 = SERVICE_IBLUETOOTHGATT;
607ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } else {
608ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                Log.e(TAG, "Unknown service connected: " + className.getClassName());
609ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return;
610ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            }
6110f42037eb7b5118015c2caca635538324ccf0ccffredc            msg.obj = service;
6120f42037eb7b5118015c2caca635538324ccf0ccffredc            mHandler.sendMessage(msg);
6130f42037eb7b5118015c2caca635538324ccf0ccffredc        }
6140f42037eb7b5118015c2caca635538324ccf0ccffredc
6150f42037eb7b5118015c2caca635538324ccf0ccffredc        public void onServiceDisconnected(ComponentName className) {
6160f42037eb7b5118015c2caca635538324ccf0ccffredc            // Called if we unexpected disconnected.
617ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
618ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                           className.getClassName());
6190f42037eb7b5118015c2caca635538324ccf0ccffredc            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
620ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
621ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                msg.arg1 = SERVICE_IBLUETOOTH;
622ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
623ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                msg.arg1 = SERVICE_IBLUETOOTHGATT;
624ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } else {
625ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
626ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return;
627ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            }
6280f42037eb7b5118015c2caca635538324ccf0ccffredc            mHandler.sendMessage(msg);
6290f42037eb7b5118015c2caca635538324ccf0ccffredc        }
6300f42037eb7b5118015c2caca635538324ccf0ccffredc    }
6310f42037eb7b5118015c2caca635538324ccf0ccffredc
6320f42037eb7b5118015c2caca635538324ccf0ccffredc    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
6330f42037eb7b5118015c2caca635538324ccf0ccffredc
63440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private class BluetoothHandler extends Handler {
63540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        public BluetoothHandler(Looper looper) {
63640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            super(looper);
63740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
63840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
6390f42037eb7b5118015c2caca635538324ccf0ccffredc        @Override
6400f42037eb7b5118015c2caca635538324ccf0ccffredc        public void handleMessage(Message msg) {
6410f42037eb7b5118015c2caca635538324ccf0ccffredc            if (DBG) Log.d (TAG, "Message: " + msg.what);
6420f42037eb7b5118015c2caca635538324ccf0ccffredc            switch (msg.what) {
6430f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_GET_NAME_AND_ADDRESS: {
644649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
645cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    synchronized(mConnection) {
6460f42037eb7b5118015c2caca635538324ccf0ccffredc                        //Start bind request
64740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        if ((mBluetooth == null) && (!mBinding)) {
6480f42037eb7b5118015c2caca635538324ccf0ccffredc                            if (DBG) Log.d(TAG, "Binding to service to get name and address");
6490f42037eb7b5118015c2caca635538324ccf0ccffredc                            mConnection.setGetNameAddressOnly(true);
6500f42037eb7b5118015c2caca635538324ccf0ccffredc                            //Start bind timeout and bind
6510f42037eb7b5118015c2caca635538324ccf0ccffredc                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
6520f42037eb7b5118015c2caca635538324ccf0ccffredc                            mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
6530f42037eb7b5118015c2caca635538324ccf0ccffredc                            Intent i = new Intent(IBluetooth.class.getName());
654221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn                            if (!doBind(i, mConnection,
655221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn                                    Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
6560f42037eb7b5118015c2caca635538324ccf0ccffredc                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
65740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            } else {
65840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                mBinding = true;
6590f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
6600f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
661cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        else {
662cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
66340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            saveMsg.arg1 = 0;
66440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            if (mBluetooth != null) {
66540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                mHandler.sendMessage(saveMsg);
66640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            } else {
66740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                // if enable is also called to bind the service
66840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
66940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
67040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            }
671cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        }
6720f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
673649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
674cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
6750f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_SAVE_NAME_AND_ADDRESS: {
676d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    boolean unbind = false;
677649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
678cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    synchronized(mConnection) {
679d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                        if (!mEnable && mBluetooth != null) {
680d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                            try {
681d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                mBluetooth.enable();
682d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                            } catch (RemoteException e) {
683d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                Log.e(TAG,"Unable to call enable()",e);
684d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                            }
685d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                        }
686d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    }
687d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    if (mBluetooth != null) waitForOnOff(true, false);
688d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    synchronized(mConnection) {
689cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        if (mBluetooth != null) {
690cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            String name =  null;
691cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            String address = null;
692cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            try {
693cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                name =  mBluetooth.getName();
694cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                address = mBluetooth.getAddress();
695cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            } catch (RemoteException re) {
696cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                Log.e(TAG,"",re);
697cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            }
6980f42037eb7b5118015c2caca635538324ccf0ccffredc
699cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            if (name != null && address != null) {
700cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                storeNameAndAddress(name,address);
70140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                if (mConnection.isGetNameAddressOnly()) {
702d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                    unbind = true;
70340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                }
704cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            } else {
705cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                if (msg.arg1 < MAX_SAVE_RETRIES) {
706cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                    Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
707cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                    retryMsg.arg1= 1+msg.arg1;
708cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                    if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
709cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                    mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
710cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                } else {
711cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                    Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
71240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                    if (mConnection.isGetNameAddressOnly()) {
713d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                        unbind = true;
71440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                    }
715cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                                }
7160f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
717d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                            if (!mEnable) {
718d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                try {
719d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                    mBluetooth.disable();
720d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                } catch (RemoteException e) {
721d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                    Log.e(TAG,"Unable to call disable()",e);
722d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                                }
723d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                            }
72440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        } else {
72540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            // rebind service by Request GET NAME AND ADDRESS
72640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            // if service is unbinded by disable or
72740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
72840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
72940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            mHandler.sendMessage(getMsg);
7300f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
7310f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
732d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
733d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    if (unbind) {
734d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                        unbindAndFinish();
735d31c32217c17f402c295514a862347dd68c9e16dZhihai Xu                    }
736649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
737649fe497cea2f19e937f84218d1080bdcefe47f2fredc                }
738cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                case MESSAGE_ENABLE:
739f24588615efa6c781ad963f1a5bbdf47359e1b53fredc                    if (DBG) {
740cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
741649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    }
74240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
74340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mEnable = true;
744401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    handleEnable(msg.arg1 == 1);
745649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
7460f42037eb7b5118015c2caca635538324ccf0ccffredc
747cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                case MESSAGE_DISABLE:
74840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
74940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (mEnable && mBluetooth != null) {
75040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        waitForOnOff(true, false);
75140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mEnable = false;
752401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        handleDisable();
75340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        waitForOnOff(false, false);
75440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    } else {
75540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mEnable = false;
756401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        handleDisable();
75740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    }
7580f42037eb7b5118015c2caca635538324ccf0ccffredc                    break;
759cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie
7600f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_REGISTER_ADAPTER:
7610f42037eb7b5118015c2caca635538324ccf0ccffredc                {
7620f42037eb7b5118015c2caca635538324ccf0ccffredc                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
763d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                    boolean added = mCallbacks.register(callback);
764d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                    Log.d(TAG,"Added callback: " +  (callback == null? "null": callback)  +":" +added );
7650f42037eb7b5118015c2caca635538324ccf0ccffredc                }
7660f42037eb7b5118015c2caca635538324ccf0ccffredc                    break;
7670f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_UNREGISTER_ADAPTER:
7680f42037eb7b5118015c2caca635538324ccf0ccffredc                {
7690f42037eb7b5118015c2caca635538324ccf0ccffredc                    IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
770d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                    boolean removed = mCallbacks.unregister(callback);
771d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc                    Log.d(TAG,"Removed callback: " +  (callback == null? "null": callback)  +":" + removed);
7720f42037eb7b5118015c2caca635538324ccf0ccffredc                    break;
773cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
7740f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
7750f42037eb7b5118015c2caca635538324ccf0ccffredc                {
7760f42037eb7b5118015c2caca635538324ccf0ccffredc                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
7779b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    if (callback != null) {
7789b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                        mStateChangeCallbacks.register(callback);
7799b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    }
7800f42037eb7b5118015c2caca635538324ccf0ccffredc                    break;
781cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
7820f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
7830f42037eb7b5118015c2caca635538324ccf0ccffredc                {
7840f42037eb7b5118015c2caca635538324ccf0ccffredc                    IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
7859b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    if (callback != null) {
7869b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                        mStateChangeCallbacks.unregister(callback);
7879b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    }
7880f42037eb7b5118015c2caca635538324ccf0ccffredc                    break;
789cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
7900f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
7910f42037eb7b5118015c2caca635538324ccf0ccffredc                {
792ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
7930f42037eb7b5118015c2caca635538324ccf0ccffredc
7940f42037eb7b5118015c2caca635538324ccf0ccffredc                    IBinder service = (IBinder) msg.obj;
7950f42037eb7b5118015c2caca635538324ccf0ccffredc                    synchronized(mConnection) {
796ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
797ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
798ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            break;
799ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        } // else must be SERVICE_IBLUETOOTH
800ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
801ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        //Remove timeout
802af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
803ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
8040f42037eb7b5118015c2caca635538324ccf0ccffredc                        mBinding = false;
8050f42037eb7b5118015c2caca635538324ccf0ccffredc                        mBluetooth = IBluetooth.Stub.asInterface(service);
8060f42037eb7b5118015c2caca635538324ccf0ccffredc
807af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                        try {
808af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
809af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
810af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
811af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                                Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
812af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                            }
813af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                        } catch (RemoteException e) {
814af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                            Log.e(TAG,"Unable to call configHciSnoopLog", e);
815af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu                        }
816af5971ef27557f02f93b399c92d7e67106d825feZhihai Xu
817cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        if (mConnection.isGetNameAddressOnly()) {
818cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            //Request GET NAME AND ADDRESS
819cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
820cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            mHandler.sendMessage(getMsg);
82140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            if (!mEnable) return;
822cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        }
823bf072a712f584ae1c01022835b0de21c40513d06fredc
82440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mConnection.setGetNameAddressOnly(false);
825cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        //Register callback object
826cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        try {
827cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            mBluetooth.registerCallback(mBluetoothCallback);
828cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        } catch (RemoteException re) {
829cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            Log.e(TAG, "Unable to register BluetoothCallback",re);
830cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        }
831cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        //Inform BluetoothAdapter instances that service is up
83240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        sendBluetoothServiceUpCallback();
83340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
834cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        //Do enable request
835bf072a712f584ae1c01022835b0de21c40513d06fredc                        try {
836fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                            if (mQuietEnable == false) {
837fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                if(!mBluetooth.enable()) {
838fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                    Log.e(TAG,"IBluetooth.enable() returned false");
839fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                }
840fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                            }
841fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                            else
842fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                            {
843fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                if(!mBluetooth.enableNoAutoConnect()) {
844fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                    Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
845fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                                }
846cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            }
847bf072a712f584ae1c01022835b0de21c40513d06fredc                        } catch (RemoteException e) {
848cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                            Log.e(TAG,"Unable to call enable()",e);
8490f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
850bf072a712f584ae1c01022835b0de21c40513d06fredc                    }
85140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
85240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (!mEnable) {
85340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        waitForOnOff(true, false);
854401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        handleDisable();
85540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        waitForOnOff(false, false);
85640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    }
857649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
858cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
859649fe497cea2f19e937f84218d1080bdcefe47f2fredc                case MESSAGE_TIMEOUT_BIND: {
860649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
8610f42037eb7b5118015c2caca635538324ccf0ccffredc                    synchronized(mConnection) {
8620f42037eb7b5118015c2caca635538324ccf0ccffredc                        mBinding = false;
8630f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
864649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
865cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
866bf072a712f584ae1c01022835b0de21c40513d06fredc                case MESSAGE_BLUETOOTH_STATE_CHANGE:
8670f42037eb7b5118015c2caca635538324ccf0ccffredc                {
868bf072a712f584ae1c01022835b0de21c40513d06fredc                    int prevState = msg.arg1;
869bf072a712f584ae1c01022835b0de21c40513d06fredc                    int newState = msg.arg2;
870bf072a712f584ae1c01022835b0de21c40513d06fredc                    if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
87140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mState = newState;
87240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    bluetoothStateChangeHandler(prevState, newState);
873dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    // handle error state transition case from TURNING_ON to OFF
874dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    // unbind and rebind bluetooth service and enable bluetooth
875dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
876dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                        (newState == BluetoothAdapter.STATE_OFF) &&
877dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                        (mBluetooth != null) && mEnable) {
878dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                        recoverBluetoothServiceFromError();
879dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    }
880dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    if (newState == BluetoothAdapter.STATE_ON) {
881dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                        // bluetooth is working, reset the counter
882dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                        if (mErrorRecoveryRetryCounter != 0) {
883dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                            Log.w(TAG, "bluetooth is recovered from error");
884dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                            mErrorRecoveryRetryCounter = 0;
885dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                        }
886dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    }
887649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
888cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
8890f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
8900f42037eb7b5118015c2caca635538324ccf0ccffredc                {
891ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
8921223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                    synchronized(mConnection) {
893ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
894ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            // if service is unbinded already, do nothing and return
895ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            if (mBluetooth == null) break;
896ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            mBluetooth = null;
897ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
898ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            mBluetoothGatt = null;
899ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            break;
900ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        } else {
901ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
902ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                            break;
903ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        }
9041223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                    }
90540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
90640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (mEnable) {
90740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mEnable = false;
90840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // Send a Bluetooth Restart message
90940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        Message restartMsg = mHandler.obtainMessage(
91040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            MESSAGE_RESTART_BLUETOOTH_SERVICE);
91140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mHandler.sendMessageDelayed(restartMsg,
91240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            SERVICE_RESTART_TIME_MS);
91340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    }
91440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
91540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (!mConnection.isGetNameAddressOnly()) {
91640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        sendBluetoothServiceDownCallback();
91740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
91840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // Send BT state broadcast to update
91940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // the BT icon correctly
9204e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
9214e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            (mState == BluetoothAdapter.STATE_ON)) {
9224e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
9234e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                                                        BluetoothAdapter.STATE_TURNING_OFF);
9244e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            mState = BluetoothAdapter.STATE_TURNING_OFF;
9254e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        }
9264e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
9274e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
9284e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                                                        BluetoothAdapter.STATE_OFF);
9294e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        }
9304e22ad35045dc5861193526afe1565d52f983698Zhihai Xu
9314e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
93240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mState = BluetoothAdapter.STATE_OFF;
93340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    }
934649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
935cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
9361223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
9371223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                {
9381223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                    Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
9391223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                        +" Restart IBluetooth service");
9401223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                    /* Enable without persisting the setting as
9411223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                     it doesnt change when IBluetooth
9421223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                     service restarts */
94340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mEnable = true;
944401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                    handleEnable(mQuietEnable);
9451223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                    break;
9461223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M                }
9471223e5a3115e825567972da26e38c0016bdfa268Syed Ibrahim M
9480f42037eb7b5118015c2caca635538324ccf0ccffredc                case MESSAGE_TIMEOUT_UNBIND:
9490f42037eb7b5118015c2caca635538324ccf0ccffredc                {
950649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
9510f42037eb7b5118015c2caca635538324ccf0ccffredc                    synchronized(mConnection) {
9520f42037eb7b5118015c2caca635538324ccf0ccffredc                        mUnbinding = false;
9530f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
954649fe497cea2f19e937f84218d1080bdcefe47f2fredc                    break;
955cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
95640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
95740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                case MESSAGE_USER_SWITCHED:
95840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                {
95940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (DBG) {
96040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        Log.d(TAG, "MESSAGE_USER_SWITCHED");
96140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    }
96240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
96340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    /* disable and enable BT when detect a user switch */
96440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (mEnable && mBluetooth != null) {
96540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        synchronized (mConnection) {
96640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            if (mBluetooth != null) {
96740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                //Unregister callback object
96840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                try {
96940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                    mBluetooth.unregisterCallback(mBluetoothCallback);
97040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                } catch (RemoteException re) {
97140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                    Log.e(TAG, "Unable to unregister",re);
97240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                }
97340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            }
97440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        }
9754e22ad35045dc5861193526afe1565d52f983698Zhihai Xu
9764e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
9774e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
9784e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
9794e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            mState = BluetoothAdapter.STATE_OFF;
9804e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        }
9814e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        if (mState == BluetoothAdapter.STATE_OFF) {
9824e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
9834e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            mState = BluetoothAdapter.STATE_TURNING_ON;
9844e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        }
98540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
98640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        waitForOnOff(true, false);
98740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
9884e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        if (mState == BluetoothAdapter.STATE_TURNING_ON) {
9894e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
9904e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        }
99140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
99240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // disable
993401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        handleDisable();
9944e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        // Pbap service need receive STATE_TURNING_OFF intent to close
9954e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
9964e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                                                    BluetoothAdapter.STATE_TURNING_OFF);
99740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
99840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        waitForOnOff(false, true);
99940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
10004e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
100140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                                    BluetoothAdapter.STATE_OFF);
100240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        sendBluetoothServiceDownCallback();
100340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        synchronized (mConnection) {
100440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            if (mBluetooth != null) {
100540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                mBluetooth = null;
100640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                //Unbind
100740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                                mContext.unbindService(mConnection);
100840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            }
100940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        }
101040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        SystemClock.sleep(100);
101140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
10124e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
10134e22ad35045dc5861193526afe1565d52f983698Zhihai Xu                        mState = BluetoothAdapter.STATE_OFF;
101440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // enable
1015401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                        handleEnable(mQuietEnable);
10168a985d24ce9a38f40ed88fecbdcd0e75e3a68f44John Spurlock                    } else if (mBinding || mBluetooth != null) {
101740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
101840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        userMsg.arg2 = 1 + msg.arg2;
101940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // if user is switched when service is being binding
102040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        // delay sending MESSAGE_USER_SWITCHED
102140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
102240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        if (DBG) {
102340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                            Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
102440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        }
10258a985d24ce9a38f40ed88fecbdcd0e75e3a68f44John Spurlock                    }
102640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    break;
102740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                }
10280f42037eb7b5118015c2caca635538324ccf0ccffredc            }
10290f42037eb7b5118015c2caca635538324ccf0ccffredc        }
103040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    }
1031cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie
1032401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private void handleEnable(boolean quietMode) {
1033fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta        mQuietEnable = quietMode;
1034fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta
1035cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        synchronized(mConnection) {
103640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if ((mBluetooth == null) && (!mBinding)) {
1037cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                //Start bind timeout and bind
1038cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1039cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1040cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                mConnection.setGetNameAddressOnly(false);
1041cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                Intent i = new Intent(IBluetooth.class.getName());
1042221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
1043cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
104440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                } else {
104540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mBinding = true;
1046cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
104740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            } else if (mBluetooth != null) {
104840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                if (mConnection.isGetNameAddressOnly()) {
104940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    // if GetNameAddressOnly is set, we can clear this flag,
105040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    // so the service won't be unbind
105140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    // after name and address are saved
105240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    mConnection.setGetNameAddressOnly(false);
105340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    //Register callback object
105440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    try {
105540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        mBluetooth.registerCallback(mBluetoothCallback);
105640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    } catch (RemoteException re) {
105740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        Log.e(TAG, "Unable to register BluetoothCallback",re);
105840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    }
105940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    //Inform BluetoothAdapter instances that service is up
106040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    sendBluetoothServiceUpCallback();
106140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                }
106240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
1063cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                //Enable bluetooth
1064cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                try {
1065fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                    if (!mQuietEnable) {
1066fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                        if(!mBluetooth.enable()) {
1067fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                            Log.e(TAG,"IBluetooth.enable() returned false");
1068fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                        }
1069fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                    }
1070fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                    else {
1071fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                        if(!mBluetooth.enableNoAutoConnect()) {
1072fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1073fffa86ba834d37684238c83c0dd081133324984dGanesh Ganapathi Batta                        }
1074cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    }
1075cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                } catch (RemoteException e) {
1076cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    Log.e(TAG,"Unable to call enable()",e);
1077cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
1078cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie            }
1079cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        }
1080cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie    }
1081cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie
1082221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1083221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1084221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        intent.setComponent(comp);
1085221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1086221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            Log.e(TAG, "Fail to bind to: " + intent);
1087221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            return false;
1088221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        }
1089221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        return true;
1090221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    }
1091221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn
1092401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private void handleDisable() {
1093cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        synchronized(mConnection) {
109440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            // don't need to disable if GetNameAddressOnly is set,
109540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            // service will be unbinded after Name and Address are saved
109640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
1097cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                if (DBG) Log.d(TAG,"Sending off request.");
1098cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie
1099cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                try {
1100cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    if(!mBluetooth.disable()) {
1101cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                        Log.e(TAG,"IBluetooth.disable() returned false");
1102cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    }
1103cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                } catch (RemoteException e) {
1104cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                    Log.e(TAG,"Unable to call disable()",e);
1105cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie                }
1106cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie            }
1107cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie        }
1108cdce0b9897183f8aef08fe200feb4027fac56290Matthew Xie    }
110940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
111040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private boolean checkIfCallerIsForegroundUser() {
111140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        int foregroundUser;
111240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        int callingUser = UserHandle.getCallingUserId();
11138385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen        int callingUid = Binder.getCallingUid();
111440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        long callingIdentity = Binder.clearCallingIdentity();
11158385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen        int callingAppId = UserHandle.getAppId(callingUid);
111640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        boolean valid = false;
111740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        try {
111840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            foregroundUser = ActivityManager.getCurrentUser();
11198385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen            valid = (callingUser == foregroundUser) ||
11208385c5afbd92da5f2e8bc13d153114bc3a7cb0f5Martijn Coenen                    callingAppId == Process.NFC_UID;
112140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if (DBG) {
112240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
112340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    + " callingUser=" + callingUser
112440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    + " foregroundUser=" + foregroundUser);
112540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            }
112640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        } finally {
112740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            Binder.restoreCallingIdentity(callingIdentity);
112840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
112940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        return valid;
113040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    }
113140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
113240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private void bluetoothStateChangeHandler(int prevState, int newState) {
113340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        if (prevState != newState) {
113440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            //Notify all proxy objects first of adapter state change
113540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
113640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
113740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                sendBluetoothStateCallback(isUp);
113840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
1139ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                if (isUp) {
1140ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    // connect to GattService
114132ab77b4c52db78aea22cb32824c7fd68d6f8c21Matthew Xie                    if (mContext.getPackageManager().hasSystemFeature(
114232ab77b4c52db78aea22cb32824c7fd68d6f8c21Matthew Xie                                                     PackageManager.FEATURE_BLUETOOTH_LE)) {
114332ab77b4c52db78aea22cb32824c7fd68d6f8c21Matthew Xie                        Intent i = new Intent(IBluetoothGatt.class.getName());
1144221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn                        doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
1145ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    }
1146ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                } else {
1147ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    //If Bluetooth is off, send service down event to proxy objects, and unbind
1148ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    if (!isUp && canUnbindBluetoothService()) {
1149ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        sendBluetoothServiceDownCallback();
1150ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        unbindAndFinish();
1151ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    }
115240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                }
115340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            }
115440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
115540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            //Send broadcast message to everyone else
115640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
115740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
115840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
115940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
116040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
116140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
116240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    BLUETOOTH_PERM);
116340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
116440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    }
116540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu
116640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    /**
116740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu     *  if on is true, wait for state become ON
116840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu     *  if off is true, wait for state become OFF
116940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu     *  if both on and off are false, wait for state not ON
117040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu     */
117140874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    private boolean waitForOnOff(boolean on, boolean off) {
117240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        int i = 0;
117340874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        while (i < 10) {
117440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            synchronized(mConnection) {
117540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                try {
117640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (mBluetooth == null) break;
117740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    if (on) {
117840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
117940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    } else if (off) {
118040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1181665e1aed5e99af1e66af56c0d73e32fd86f57273Robert Greenwalt                    } else {
118240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                        if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1183665e1aed5e99af1e66af56c0d73e32fd86f57273Robert Greenwalt                    }
118440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                } catch (RemoteException e) {
118540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    Log.e(TAG, "getState()", e);
118640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                    break;
118740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                }
118840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            }
118940874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            if (on || off) {
119040874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                SystemClock.sleep(300);
1191665e1aed5e99af1e66af56c0d73e32fd86f57273Robert Greenwalt            } else {
119240874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu                SystemClock.sleep(50);
1193665e1aed5e99af1e66af56c0d73e32fd86f57273Robert Greenwalt            }
119440874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu            i++;
119540874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        }
119640874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        Log.e(TAG,"waitForOnOff time out");
119740874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu        return false;
119840874a096ba6448ebffea4b17486dbfbc957c0dfZhihai Xu    }
1199681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu
1200401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private void sendDisableMsg() {
1201401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1202401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    }
1203401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu
1204401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    private void sendEnableMsg(boolean quietMode) {
1205401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1206401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu                             quietMode ? 1 : 0, 0));
1207401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu    }
1208401202b5fe3d67bdf2ae6991fc451f444ecd6989Zhihai Xu
1209681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu    private boolean canUnbindBluetoothService() {
1210681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu        synchronized(mConnection) {
1211681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            //Only unbind with mEnable flag not set
1212681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            //For race condition: disable and enable back-to-back
1213681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            //Avoid unbind right after enable due to callback from disable
1214681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            //Only unbind with Bluetooth at OFF state
1215681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1216681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            try {
1217681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu                if (mEnable || (mBluetooth == null)) return false;
1218681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu                if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1219681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu                return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1220681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            } catch (RemoteException e) {
1221681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu                Log.e(TAG, "getState()", e);
1222681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu            }
1223681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu        }
1224681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu        return false;
1225681ae7fc5e36f8da0c6975b316c93834c0d7b8a3Zhihai Xu    }
1226dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1227dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu    private void recoverBluetoothServiceFromError() {
1228dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        Log.e(TAG,"recoverBluetoothServiceFromError");
1229dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        synchronized (mConnection) {
1230dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            if (mBluetooth != null) {
1231dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                //Unregister callback object
1232dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                try {
1233dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    mBluetooth.unregisterCallback(mBluetoothCallback);
1234dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                } catch (RemoteException re) {
1235dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                    Log.e(TAG, "Unable to unregister",re);
1236dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                }
1237dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            }
1238dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        }
1239dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1240dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        SystemClock.sleep(500);
1241dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1242dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        // disable
1243dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        handleDisable();
1244dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1245dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        waitForOnOff(false, true);
1246dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1247dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        sendBluetoothServiceDownCallback();
1248dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        synchronized (mConnection) {
1249dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            if (mBluetooth != null) {
1250dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                mBluetooth = null;
1251dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                //Unbind
1252dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                mContext.unbindService(mConnection);
1253dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            }
1254dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        }
1255dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1256dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1257dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        mState = BluetoothAdapter.STATE_OFF;
1258dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1259dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        mEnable = false;
1260dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu
1261dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1262dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            // Send a Bluetooth Restart message to reenable bluetooth
1263dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            Message restartMsg = mHandler.obtainMessage(
1264dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu                             MESSAGE_RESTART_BLUETOOTH_SERVICE);
1265dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1266dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        } else {
1267dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu            // todo: notify user to power down and power up phone to make bluetooth work.
1268dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu        }
1269dd9d17d45836bc1cc00136e088445fbca9244e0eZhihai Xu    }
12700f42037eb7b5118015c2caca635538324ccf0ccffredc}
1271