AdapterState.java revision 3558402aae35c6b01c505be012d6736b0c758802
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bluetooth.btservice; 18 19import android.bluetooth.BluetoothAdapter; 20import android.content.Context; 21import android.content.Intent; 22import android.os.Message; 23import android.os.UserManager; 24import android.util.Log; 25 26import com.android.internal.util.State; 27import com.android.internal.util.StateMachine; 28 29/** 30 * This state machine handles Bluetooth Adapter State. 31 * States: 32 * {@link OnState} : Bluetooth is on at this state 33 * {@link OffState}: Bluetooth is off at this state. This is the initial 34 * state. 35 * {@link PendingCommandState} : An enable / disable operation is pending. 36 * TODO(BT): Add per process on state. 37 */ 38 39final class AdapterState extends StateMachine { 40 private static final boolean DBG = true; 41 private static final boolean VDBG = true; 42 private static final String TAG = "BluetoothAdapterState"; 43 44 static final int BLE_TURN_ON = 0; 45 static final int USER_TURN_ON = 1; 46 static final int BREDR_STARTED=2; 47 static final int ENABLED_READY = 3; 48 static final int BLE_STARTED=4; 49 50 static final int USER_TURN_OFF = 20; 51 static final int BEGIN_DISABLE = 21; 52 static final int ALL_DEVICES_DISCONNECTED = 22; 53 static final int BLE_TURN_OFF = 23; 54 55 static final int DISABLED = 24; 56 static final int BLE_STOPPED=25; 57 static final int BREDR_STOPPED = 26; 58 59 static final int BREDR_START_TIMEOUT = 100; 60 static final int ENABLE_TIMEOUT = 101; 61 static final int DISABLE_TIMEOUT = 103; 62 static final int BLE_STOP_TIMEOUT = 104; 63 static final int SET_SCAN_MODE_TIMEOUT = 105; 64 static final int BLE_START_TIMEOUT = 106; 65 static final int BREDR_STOP_TIMEOUT = 107; 66 67 static final int USER_TURN_OFF_DELAY_MS=500; 68 69 //TODO: tune me 70 private static final int ENABLE_TIMEOUT_DELAY = 12000; 71 private static final int DISABLE_TIMEOUT_DELAY = 8000; 72 private static final int BREDR_START_TIMEOUT_DELAY = 4000; 73 //BLE_START_TIMEOUT can happen quickly as it just a start gattservice 74 private static final int BLE_START_TIMEOUT_DELAY = 2000; //To start GattService 75 private static final int BLE_STOP_TIMEOUT_DELAY = 2000; 76 //BREDR_STOP_TIMEOUT can < STOP_TIMEOUT 77 private static final int BREDR_STOP_TIMEOUT_DELAY = 4000; 78 private static final int PROPERTY_OP_DELAY =2000; 79 private AdapterService mAdapterService; 80 private AdapterProperties mAdapterProperties; 81 private PendingCommandState mPendingCommandState = new PendingCommandState(); 82 private OnState mOnState = new OnState(); 83 private OffState mOffState = new OffState(); 84 private BleOnState mBleOnState = new BleOnState(); 85 86 public boolean isTurningOn() { 87 boolean isTurningOn= mPendingCommandState.isTurningOn(); 88 verboseLog("isTurningOn()=" + isTurningOn); 89 return isTurningOn; 90 } 91 92 public boolean isBleTurningOn() { 93 boolean isBleTurningOn= mPendingCommandState.isBleTurningOn(); 94 verboseLog("isBleTurningOn()=" + isBleTurningOn); 95 return isBleTurningOn; 96 } 97 98 public boolean isBleTurningOff() { 99 boolean isBleTurningOff = mPendingCommandState.isBleTurningOff(); 100 verboseLog("isBleTurningOff()=" + isBleTurningOff); 101 return isBleTurningOff; 102 } 103 104 public boolean isTurningOff() { 105 boolean isTurningOff= mPendingCommandState.isTurningOff(); 106 verboseLog("isTurningOff()=" + isTurningOff); 107 return isTurningOff; 108 } 109 110 private AdapterState(AdapterService service, AdapterProperties adapterProperties) { 111 super("BluetoothAdapterState:"); 112 addState(mOnState); 113 addState(mBleOnState); 114 addState(mOffState); 115 addState(mPendingCommandState); 116 mAdapterService = service; 117 mAdapterProperties = adapterProperties; 118 setInitialState(mOffState); 119 } 120 121 public static AdapterState make(AdapterService service, AdapterProperties adapterProperties) { 122 Log.d(TAG, "make() - Creating AdapterState"); 123 AdapterState as = new AdapterState(service, adapterProperties); 124 as.start(); 125 return as; 126 } 127 128 public void doQuit() { 129 quitNow(); 130 } 131 132 public void cleanup() { 133 if(mAdapterProperties != null) 134 mAdapterProperties = null; 135 if(mAdapterService != null) 136 mAdapterService = null; 137 } 138 139 private class OffState extends State { 140 @Override 141 public void enter() { 142 infoLog("Entering OffState"); 143 } 144 145 @Override 146 public boolean processMessage(Message msg) { 147 AdapterService adapterService = mAdapterService; 148 if (adapterService == null) { 149 errorLog("Received message in OffState after cleanup: " + msg.what); 150 return false; 151 } 152 153 debugLog("Current state: OFF, message: " + msg.what); 154 155 switch(msg.what) { 156 case BLE_TURN_ON: 157 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON); 158 mPendingCommandState.setBleTurningOn(true); 159 transitionTo(mPendingCommandState); 160 sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY); 161 adapterService.BleOnProcessStart(); 162 break; 163 164 case USER_TURN_OFF: 165 //TODO: Handle case of service started and stopped without enable 166 break; 167 168 default: 169 return false; 170 } 171 return true; 172 } 173 } 174 175 private class BleOnState extends State { 176 @Override 177 public void enter() { 178 infoLog("Entering BleOnState"); 179 } 180 181 @Override 182 public boolean processMessage(Message msg) { 183 184 AdapterService adapterService = mAdapterService; 185 AdapterProperties adapterProperties = mAdapterProperties; 186 if ((adapterService == null) || (adapterProperties == null)) { 187 errorLog("Received message in BleOnState after cleanup: " + msg.what); 188 return false; 189 } 190 191 debugLog("Current state: BLE ON, message: " + msg.what); 192 193 switch(msg.what) { 194 case USER_TURN_ON: 195 notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON); 196 mPendingCommandState.setTurningOn(true); 197 transitionTo(mPendingCommandState); 198 sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY); 199 adapterService.startCoreServices(); 200 break; 201 202 case USER_TURN_OFF: 203 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF); 204 mPendingCommandState.setBleTurningOff(true); 205 adapterProperties.onBleDisable(); 206 transitionTo(mPendingCommandState); 207 sendMessageDelayed(DISABLE_TIMEOUT, DISABLE_TIMEOUT_DELAY); 208 boolean ret = adapterService.disableNative(); 209 if (!ret) { 210 removeMessages(DISABLE_TIMEOUT); 211 errorLog("Error while calling disableNative"); 212 //FIXME: what about post enable services 213 mPendingCommandState.setBleTurningOff(false); 214 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 215 } 216 break; 217 218 default: 219 return false; 220 } 221 return true; 222 } 223 } 224 225 private class OnState extends State { 226 @Override 227 public void enter() { 228 infoLog("Entering OnState"); 229 230 AdapterService adapterService = mAdapterService; 231 if (adapterService == null) { 232 errorLog("Entered OnState after cleanup"); 233 return; 234 } 235 adapterService.autoConnect(); 236 } 237 238 @Override 239 public boolean processMessage(Message msg) { 240 AdapterProperties adapterProperties = mAdapterProperties; 241 if (adapterProperties == null) { 242 errorLog("Received message in OnState after cleanup: " + msg.what); 243 return false; 244 } 245 246 debugLog("Current state: ON, message: " + msg.what); 247 248 switch(msg.what) { 249 case BLE_TURN_OFF: 250 notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_OFF); 251 mPendingCommandState.setTurningOff(true); 252 transitionTo(mPendingCommandState); 253 254 // Invoke onBluetoothDisable which shall trigger a 255 // setScanMode to SCAN_MODE_NONE 256 Message m = obtainMessage(SET_SCAN_MODE_TIMEOUT); 257 sendMessageDelayed(m, PROPERTY_OP_DELAY); 258 adapterProperties.onBluetoothDisable(); 259 break; 260 261 case USER_TURN_ON: 262 break; 263 264 default: 265 return false; 266 } 267 return true; 268 } 269 } 270 271 private class PendingCommandState extends State { 272 private boolean mIsTurningOn; 273 private boolean mIsTurningOff; 274 private boolean mIsBleTurningOn; 275 private boolean mIsBleTurningOff; 276 277 public void enter() { 278 infoLog("Entering PendingCommandState"); 279 } 280 281 public void setTurningOn(boolean isTurningOn) { 282 mIsTurningOn = isTurningOn; 283 } 284 285 public boolean isTurningOn() { 286 return mIsTurningOn; 287 } 288 289 public void setTurningOff(boolean isTurningOff) { 290 mIsTurningOff = isTurningOff; 291 } 292 293 public boolean isTurningOff() { 294 return mIsTurningOff; 295 } 296 297 public void setBleTurningOn(boolean isBleTurningOn) { 298 mIsBleTurningOn = isBleTurningOn; 299 } 300 301 public boolean isBleTurningOn() { 302 return mIsBleTurningOn; 303 } 304 305 public void setBleTurningOff(boolean isBleTurningOff) { 306 mIsBleTurningOff = isBleTurningOff; 307 } 308 309 public boolean isBleTurningOff() { 310 return mIsBleTurningOff; 311 } 312 313 @Override 314 public boolean processMessage(Message msg) { 315 316 boolean isTurningOn= isTurningOn(); 317 boolean isTurningOff = isTurningOff(); 318 boolean isBleTurningOn = isBleTurningOn(); 319 boolean isBleTurningOff = isBleTurningOff(); 320 321 AdapterService adapterService = mAdapterService; 322 AdapterProperties adapterProperties = mAdapterProperties; 323 if ((adapterService == null) || (adapterProperties == null)) { 324 errorLog("Received message in PendingCommandState after cleanup: " + msg.what); 325 return false; 326 } 327 328 debugLog("Current state: PENDING_COMMAND, message: " + msg.what); 329 330 switch (msg.what) { 331 case USER_TURN_ON: 332 if (isBleTurningOff || isTurningOff) { //TODO:do we need to send it after ble turn off also?? 333 infoLog("Deferring USER_TURN_ON request..."); 334 deferMessage(msg); 335 } 336 break; 337 338 case USER_TURN_OFF: 339 if (isTurningOn || isBleTurningOn) { 340 infoLog("Deferring USER_TURN_OFF request..."); 341 deferMessage(msg); 342 } 343 break; 344 345 case BLE_TURN_ON: 346 if (isTurningOff || isBleTurningOff) { 347 infoLog("Deferring BLE_TURN_ON request..."); 348 deferMessage(msg); 349 } 350 break; 351 352 case BLE_TURN_OFF: 353 if (isTurningOn || isBleTurningOn) { 354 infoLog("Deferring BLE_TURN_OFF request..."); 355 deferMessage(msg); 356 } 357 break; 358 359 case BLE_STARTED: 360 //Remove start timeout 361 removeMessages(BLE_START_TIMEOUT); 362 363 //Enable 364 boolean isGuest = UserManager.get(mAdapterService).isGuestUser(); 365 if (!adapterService.enableNative(isGuest)) { 366 errorLog("Error while turning Bluetooth on"); 367 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 368 transitionTo(mOffState); 369 } else { 370 sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY); 371 } 372 break; 373 374 case BREDR_STARTED: 375 //Remove start timeout 376 removeMessages(BREDR_START_TIMEOUT); 377 adapterProperties.onBluetoothReady(); 378 mPendingCommandState.setTurningOn(false); 379 transitionTo(mOnState); 380 notifyAdapterStateChange(BluetoothAdapter.STATE_ON); 381 break; 382 383 case ENABLED_READY: 384 removeMessages(ENABLE_TIMEOUT); 385 mPendingCommandState.setBleTurningOn(false); 386 transitionTo(mBleOnState); 387 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 388 break; 389 390 case SET_SCAN_MODE_TIMEOUT: 391 warningLog("Timeout while setting scan mode. Continuing with disable..."); 392 //Fall through 393 case BEGIN_DISABLE: 394 removeMessages(SET_SCAN_MODE_TIMEOUT); 395 sendMessageDelayed(BREDR_STOP_TIMEOUT, BREDR_STOP_TIMEOUT_DELAY); 396 adapterService.stopProfileServices(); 397 break; 398 399 case DISABLED: 400 if (isTurningOn) { 401 removeMessages(ENABLE_TIMEOUT); 402 errorLog("Error enabling Bluetooth - hardware init failed?"); 403 mPendingCommandState.setTurningOn(false); 404 transitionTo(mOffState); 405 adapterService.stopProfileServices(); 406 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 407 break; 408 } 409 removeMessages(DISABLE_TIMEOUT); 410 sendMessageDelayed(BLE_STOP_TIMEOUT, BLE_STOP_TIMEOUT_DELAY); 411 if (adapterService.stopGattProfileService()) { 412 debugLog("Stopping Gatt profile services that were post enabled"); 413 break; 414 } 415 //Fall through if no services or services already stopped 416 case BLE_STOPPED: 417 removeMessages(BLE_STOP_TIMEOUT); 418 setBleTurningOff(false); 419 transitionTo(mOffState); 420 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 421 break; 422 423 case BREDR_STOPPED: 424 removeMessages(BREDR_STOP_TIMEOUT); 425 setTurningOff(false); 426 transitionTo(mBleOnState); 427 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 428 break; 429 430 case BLE_START_TIMEOUT: 431 errorLog("Error enabling Bluetooth (BLE start timeout)"); 432 mPendingCommandState.setBleTurningOn(false); 433 transitionTo(mOffState); 434 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 435 break; 436 437 case BREDR_START_TIMEOUT: 438 errorLog("Error enabling Bluetooth (start timeout)"); 439 mPendingCommandState.setTurningOn(false); 440 transitionTo(mBleOnState); 441 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 442 break; 443 444 case ENABLE_TIMEOUT: 445 errorLog("Error enabling Bluetooth (enable timeout)"); 446 mPendingCommandState.setBleTurningOn(false); 447 transitionTo(mOffState); 448 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 449 break; 450 451 case BREDR_STOP_TIMEOUT: 452 errorLog("Error stopping Bluetooth profiles (stop timeout)"); 453 mPendingCommandState.setTurningOff(false); 454 transitionTo(mBleOnState); 455 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 456 break; 457 458 case BLE_STOP_TIMEOUT: 459 errorLog("Error stopping Bluetooth profiles (BLE stop timeout)"); 460 mPendingCommandState.setTurningOff(false); 461 transitionTo(mOffState); 462 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 463 break; 464 465 case DISABLE_TIMEOUT: 466 errorLog("Error disabling Bluetooth (disable timeout)"); 467 if (isTurningOn) 468 mPendingCommandState.setTurningOn(false); 469 adapterService.stopProfileServices(); 470 adapterService.stopGattProfileService(); 471 mPendingCommandState.setTurningOff(false); 472 setBleTurningOff(false); 473 transitionTo(mOffState); 474 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 475 break; 476 477 default: 478 return false; 479 } 480 return true; 481 } 482 } 483 484 private void notifyAdapterStateChange(int newState) { 485 AdapterService adapterService = mAdapterService; 486 AdapterProperties adapterProperties = mAdapterProperties; 487 if ((adapterService == null) || (adapterProperties == null)) { 488 errorLog("notifyAdapterStateChange after cleanup:" + newState); 489 return; 490 } 491 492 int oldState = adapterProperties.getState(); 493 adapterProperties.setState(newState); 494 infoLog("Bluetooth adapter state changed: " + oldState + "-> " + newState); 495 adapterService.updateAdapterState(oldState, newState); 496 } 497 498 void stateChangeCallback(int status) { 499 if (status == AbstractionLayer.BT_STATE_OFF) { 500 sendMessage(DISABLED); 501 502 } else if (status == AbstractionLayer.BT_STATE_ON) { 503 // We should have got the property change for adapter and remote devices. 504 sendMessage(ENABLED_READY); 505 506 } else { 507 errorLog("Incorrect status in stateChangeCallback"); 508 } 509 } 510 511 private void infoLog(String msg) { 512 if (DBG) Log.i(TAG, msg); 513 } 514 515 private void debugLog(String msg) { 516 if (DBG) Log.d(TAG, msg); 517 } 518 519 private void warningLog(String msg) { 520 if (DBG) Log.d(TAG, msg); 521 } 522 523 private void verboseLog(String msg) { 524 if (VDBG) Log.v(TAG, msg); 525 } 526 527 private void errorLog(String msg) { 528 Log.e(TAG, msg); 529 } 530 531} 532