AdapterState.java revision 6654f5c903de510a70f9e72cd5ad7837b615d93f
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.bluetooth.btservice; 6 7import android.bluetooth.BluetoothAdapter; 8import android.content.Context; 9import android.content.Intent; 10import android.os.Message; 11import android.util.Log; 12 13import com.android.internal.util.State; 14import com.android.internal.util.StateMachine; 15 16/** 17 * This state machine handles Bluetooth Adapter State. 18 * States: 19 * {@link OnState} : Bluetooth is on at this state 20 * {@link OffState}: Bluetooth is off at this state. This is the initial 21 * state. 22 * {@link PendingCommandState} : An enable / disable operation is pending. 23 * TODO(BT): Add per process on state. 24 */ 25 26final class AdapterState extends StateMachine { 27 private static final boolean DBG = true; 28 private static final String TAG = "BluetoothAdapterState"; 29 30 static final int USER_TURN_ON = 1; 31 static final int USER_TURN_OFF = 2; 32 static final int AIRPLANE_MODE_ON = 3; 33 static final int AIRPLANE_MODE_OFF = 4; 34 static final int ENABLED_READY = 5; 35 static final int DISABLED = 6; 36 static final int ALL_DEVICES_DISCONNECTED = 7; 37 static final int ENABLE_TIMEOUT = 8; 38 39 private static final int DISCONNECT_TIMEOUT = 3000; 40 private static final int ENABLE_TIMEOUT_DELAY = 6000; // 6 secs 41 42 private AdapterService mAdapterService; 43 private Context mContext; 44 private AdapterProperties mAdapterProperties; 45 private boolean mPendingPersistEnable; 46 private PendingCommandState mPendingCommandState = new PendingCommandState(); 47 private OnState mOnState = new OnState(); 48 private OffState mOffState = new OffState(); 49 50 public AdapterState(AdapterService service, Context context, 51 AdapterProperties adapterProperties) { 52 super("BluetoothAdapterState:"); 53 addState(mOnState); 54 addState(mOffState); 55 addState(mPendingCommandState); 56 mAdapterService = service; 57 mContext = context; 58 mAdapterProperties = adapterProperties; 59 setInitialState(mOffState); 60 } 61 62 public void cleanup() { 63 } 64 65 private class OffState extends State { 66 @Override 67 public void enter() { 68 infoLog("Entering Off State"); 69 } 70 71 @Override 72 public boolean processMessage(Message msg) { 73 switch(msg.what) { 74 case USER_TURN_ON: 75 int persist = msg.arg1; 76 //if (persist == 1) mAdapterService.persistBluetoothSetting(true); 77 //Persist enable state only once enable completes 78 mPendingPersistEnable = (persist ==1); 79 sendIntent(BluetoothAdapter.STATE_TURNING_ON); 80 boolean ret = mAdapterService.enableNative(); 81 if (!ret) { 82 Log.e(TAG, "Error while turning Bluetooth On"); 83 sendIntent(BluetoothAdapter.STATE_OFF); 84 } else { 85 sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY); 86 transitionTo(mPendingCommandState); 87 } 88 break; 89 case AIRPLANE_MODE_OFF: 90 { 91 if(mAdapterService.getBluetoothPersistedSetting()) { 92 Log.i(TAG, "OffState : Turning BT on after Airplane"+ 93 " Mode OFF state"); 94 sendIntent(BluetoothAdapter.STATE_TURNING_ON); 95 ret = mAdapterService.enableNative(); 96 if (!ret) { 97 Log.e(TAG, "Error while turning Bluetooth On"); 98 sendIntent(BluetoothAdapter.STATE_OFF); 99 } else { 100 sendMessageDelayed(ENABLE_TIMEOUT, 101 ENABLE_TIMEOUT_DELAY); 102 transitionTo(mPendingCommandState); 103 } 104 } 105 break; 106 } 107 case USER_TURN_OFF: 108 case AIRPLANE_MODE_ON: 109 //ignore 110 break; 111 default: 112 Log.e(TAG, "Received unhandled state: " + msg.what); 113 return false; 114 } 115 return true; 116 } 117 } 118 119 private class OnState extends State { 120 @Override 121 public void enter() { 122 infoLog("Entering On State"); 123 } 124 125 @Override 126 public boolean processMessage(Message msg) { 127 switch(msg.what) { 128 case USER_TURN_OFF: 129 int persist = msg.arg1; 130 if (persist == 1) { 131 //Persist disable immediately even before disable completes 132 mAdapterService.persistBluetoothSetting(false); 133 } 134 //Fall Through 135 case AIRPLANE_MODE_ON: 136 sendIntent(BluetoothAdapter.STATE_TURNING_OFF); 137 // Invoke onBluetoothDisable which shall trigger a 138 // setScanMode to SCAN_MODE_NONE 139 mAdapterProperties.onBluetoothDisable(); 140 if (mAdapterProperties.getConnectionState() != 141 BluetoothAdapter.STATE_DISCONNECTED) { 142 sendMessageDelayed(ALL_DEVICES_DISCONNECTED, 143 DISCONNECT_TIMEOUT); 144 break; 145 } 146 //Fall Through 147 case ALL_DEVICES_DISCONNECTED: 148 boolean ret = mAdapterService.disableNative(); 149 if (!ret) { 150 Log.e(TAG, "Error while turning Bluetooth Off"); 151 sendIntent(BluetoothAdapter.STATE_ON); 152 } else { 153 transitionTo(mPendingCommandState); 154 } 155 break; 156 case USER_TURN_ON: 157 case AIRPLANE_MODE_OFF: 158 //ignore 159 break; 160 default: 161 Log.e(TAG, "Received unhandled state: " + msg.what); 162 return false; 163 } 164 return true; 165 } 166 } 167 168 private class PendingCommandState extends State { 169 @Override 170 public void enter() { 171 infoLog("Entering PendingCommandState State"); 172 } 173 174 @Override 175 public boolean processMessage(Message msg) { 176 switch (msg.what) { 177 case USER_TURN_ON: 178 case USER_TURN_OFF: 179 case AIRPLANE_MODE_ON: 180 case AIRPLANE_MODE_OFF: 181 deferMessage(msg); 182 break; 183 case ENABLED_READY: 184 removeMessages(ENABLE_TIMEOUT); 185 //Persist enable state only once enable completes 186 if (mPendingPersistEnable) { 187 mAdapterService.persistBluetoothSetting(true); 188 mPendingPersistEnable=false; 189 } 190 mAdapterProperties.onBluetoothReady(); 191 sendIntent(BluetoothAdapter.STATE_ON); 192 transitionTo(mOnState); 193 break; 194 case DISABLED: 195 sendIntent(BluetoothAdapter.STATE_OFF); 196 transitionTo(mOffState); 197 break; 198 case ENABLE_TIMEOUT: 199 errorLog("Error enabling Bluetooth"); 200 sendIntent(BluetoothAdapter.STATE_OFF); 201 transitionTo(mOffState); 202 break; 203 default: 204 Log.e(TAG, "Received unhandled event:" + msg.what); 205 return false; 206 } 207 return true; 208 } 209 } 210 211 212 private void sendIntent(int newState) { 213 int oldState = mAdapterProperties.getState(); 214 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 215 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, oldState); 216 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 217 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 218 mAdapterProperties.setState(newState); 219 220 mContext.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); 221 infoLog("Bluetooth State Change Intent: " + oldState + " -> " + newState); 222 } 223 224 void stateChangeCallback(int status) { 225 if (status == AbstractionLayer.BT_STATE_OFF) { 226 sendMessage(DISABLED); 227 } else if (status == AbstractionLayer.BT_STATE_ON) { 228 // We should have got the property change for adapter and remote devices. 229 sendMessage(ENABLED_READY); 230 } else { 231 errorLog("Incorrect status in stateChangeCallback"); 232 } 233 } 234 235 private void infoLog(String msg) { 236 if (DBG) Log.i(TAG, msg); 237 } 238 239 private void errorLog(String msg) { 240 Log.e(TAG, msg); 241 } 242} 243