AdapterState.java revision 0708fe3087b690439dd9745b2cf1a96f29f570b0
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 final AdapterService mAdapterService; 43 private final Context mContext; 44 private final AdapterProperties mAdapterProperties; 45 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 setInitialState(mOffState); 57 mAdapterService = service; 58 mContext = context; 59 mAdapterProperties = adapterProperties; 60 } 61 62 private class OffState extends State { 63 @Override 64 public void enter() { 65 infoLog("Entering Off State"); 66 } 67 68 @Override 69 public boolean processMessage(Message msg) { 70 switch(msg.what) { 71 case USER_TURN_ON: 72 int persist = msg.arg1; 73 if (persist == 1) mAdapterService.persistBluetoothSetting(true); 74 sendIntent(BluetoothAdapter.STATE_TURNING_ON); 75 boolean ret = mAdapterService.enableNative(); 76 if (!ret) { 77 Log.e(TAG, "Error while turning Bluetooth On"); 78 sendIntent(BluetoothAdapter.STATE_OFF); 79 } else { 80 sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY); 81 transitionTo(mPendingCommandState); 82 } 83 break; 84 case AIRPLANE_MODE_OFF: 85 { 86 if(mAdapterService.getBluetoothPersistedSetting()) { 87 Log.i(TAG, "OffState : Turning BT on after Airplane"+ 88 " Mode OFF state"); 89 sendIntent(BluetoothAdapter.STATE_TURNING_ON); 90 ret = mAdapterService.enableNative(); 91 if (!ret) { 92 Log.e(TAG, "Error while turning Bluetooth On"); 93 sendIntent(BluetoothAdapter.STATE_OFF); 94 } else { 95 sendMessageDelayed(ENABLE_TIMEOUT, 96 ENABLE_TIMEOUT_DELAY); 97 transitionTo(mPendingCommandState); 98 } 99 } 100 break; 101 } 102 case USER_TURN_OFF: 103 case AIRPLANE_MODE_ON: 104 //ignore 105 break; 106 default: 107 Log.e(TAG, "Received unhandled state: " + msg.what); 108 return false; 109 } 110 return true; 111 } 112 } 113 114 private class OnState extends State { 115 @Override 116 public void enter() { 117 infoLog("Entering On State"); 118 } 119 120 @Override 121 public boolean processMessage(Message msg) { 122 switch(msg.what) { 123 case USER_TURN_OFF: 124 int persist = msg.arg1; 125 if (persist == 1) { 126 mAdapterService.persistBluetoothSetting(false); 127 } 128 //Fall Through 129 case AIRPLANE_MODE_ON: 130 sendIntent(BluetoothAdapter.STATE_TURNING_OFF); 131 if (mAdapterProperties.getConnectionState() != 132 BluetoothAdapter.STATE_DISCONNECTED) { 133 sendMessageDelayed(ALL_DEVICES_DISCONNECTED, 134 DISCONNECT_TIMEOUT); 135 break; 136 } 137 //Fall Through 138 case ALL_DEVICES_DISCONNECTED: 139 boolean ret = mAdapterService.disableNative(); 140 if (!ret) { 141 Log.e(TAG, "Error while turning Bluetooth Off"); 142 sendIntent(BluetoothAdapter.STATE_ON); 143 } else { 144 transitionTo(mPendingCommandState); 145 } 146 break; 147 case USER_TURN_ON: 148 case AIRPLANE_MODE_OFF: 149 //ignore 150 break; 151 default: 152 Log.e(TAG, "Received unhandled state: " + msg.what); 153 return false; 154 } 155 return true; 156 } 157 } 158 159 private class PendingCommandState extends State { 160 @Override 161 public void enter() { 162 infoLog("Entering PendingCommandState State"); 163 } 164 165 @Override 166 public boolean processMessage(Message msg) { 167 switch (msg.what) { 168 case USER_TURN_ON: 169 case USER_TURN_OFF: 170 case AIRPLANE_MODE_ON: 171 case AIRPLANE_MODE_OFF: 172 deferMessage(msg); 173 break; 174 case ENABLED_READY: 175 removeMessages(ENABLE_TIMEOUT); 176 mAdapterProperties.onBluetoothReady(); 177 sendIntent(BluetoothAdapter.STATE_ON); 178 transitionTo(mOnState); 179 break; 180 case DISABLED: 181 sendIntent(BluetoothAdapter.STATE_OFF); 182 transitionTo(mOffState); 183 break; 184 case ENABLE_TIMEOUT: 185 errorLog("Error enabling Bluetooth"); 186 sendIntent(BluetoothAdapter.STATE_OFF); 187 transitionTo(mOffState); 188 break; 189 default: 190 Log.e(TAG, "Received unhandled event:" + msg.what); 191 return false; 192 } 193 return true; 194 } 195 } 196 197 198 private void sendIntent(int newState) { 199 int oldState = mAdapterProperties.getState(); 200 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 201 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, oldState); 202 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 203 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 204 mAdapterProperties.setState(newState); 205 206 mContext.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); 207 infoLog("Bluetooth State Change Intent: " + oldState + " -> " + newState); 208 } 209 210 void stateChangeCallback(int status) { 211 if (status == AbstractionLayer.BT_STATE_OFF) { 212 sendMessage(DISABLED); 213 } else if (status == AbstractionLayer.BT_STATE_ON) { 214 // We should have got the property change for adapter and remote devices. 215 sendMessage(ENABLED_READY); 216 } else { 217 errorLog("Incorrect status in stateChangeCallback"); 218 } 219 } 220 221 private void infoLog(String msg) { 222 if (DBG) Log.i(TAG, msg); 223 } 224 225 private void errorLog(String msg) { 226 Log.e(TAG, msg); 227 } 228} 229