BondStateMachine.java revision 74ae04c73312403e89db0f8e9bd9601d403b4783
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.bluetooth.btservice; 6 7import android.bluetooth.BluetoothAdapter; 8import android.bluetooth.BluetoothDevice; 9import android.content.Context; 10import android.content.Intent; 11import android.os.Message; 12import android.util.Log; 13 14import com.android.bluetooth.Utils; 15import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 16import com.android.internal.util.State; 17import com.android.internal.util.StateMachine; 18 19import java.util.ArrayList; 20 21/** 22 * This state machine handles Bluetooth Adapter State. 23 * States: 24 * {@link StableState} : No device is in bonding / unbonding state. 25 * {@link PendingCommandState} : Some device is in bonding / unbonding state. 26 * TODO(BT) This class can be removed and this logic moved to the stack. 27 */ 28 29final class BondStateMachine extends StateMachine { 30 private static final boolean DBG = true; 31 private static final String TAG = "BluetoothBondStateMachine"; 32 33 static final int CREATE_BOND = 1; 34 static final int CANCEL_BOND = 2; 35 static final int REMOVE_BOND = 3; 36 static final int BONDING_STATE_CHANGE = 4; 37 38 static final int BOND_STATE_NONE = 0; 39 static final int BOND_STATE_BONDING = 1; 40 static final int BOND_STATE_BONDED = 2; 41 42 private AdapterService mAdapterService; 43 private AdapterProperties mAdapterProperties; 44 private RemoteDevices mRemoteDevices; 45 46 private PendingCommandState mPendingCommandState = new PendingCommandState(); 47 private StableState mStableState = new StableState(); 48 49 public BondStateMachine(AdapterService service, 50 AdapterProperties prop, RemoteDevices remoteDevices) { 51 super("BondStateMachine:"); 52 addState(mStableState); 53 addState(mPendingCommandState); 54 mRemoteDevices = remoteDevices; 55 mAdapterService = service; 56 mAdapterProperties = prop; 57 setInitialState(mStableState); 58 } 59 60 public void cleanup() { 61 mAdapterService = null; 62 mRemoteDevices = null; 63 mAdapterProperties = null; 64 } 65 66 private class StableState extends State { 67 @Override 68 public void enter() { 69 infoLog("StableState(): Entering Off State"); 70 } 71 72 @Override 73 public boolean processMessage(Message msg) { 74 if (msg.what == SM_QUIT_CMD) { 75 Log.d(TAG, "Received quit request..."); 76 return false; 77 } 78 79 80 BluetoothDevice dev = (BluetoothDevice)msg.obj; 81 82 switch(msg.what) { 83 84 case CREATE_BOND: 85 createBond(dev, true); 86 break; 87 case REMOVE_BOND: 88 removeBond(dev, true); 89 break; 90 case BONDING_STATE_CHANGE: 91 int newState = msg.arg1; 92 /* if incoming pairing, transition to pending state */ 93 if (newState == BluetoothDevice.BOND_BONDING) 94 { 95 sendIntent(dev, newState); 96 transitionTo(mPendingCommandState); 97 } 98 else 99 { 100 Log.e(TAG, "In stable state, received invalid newState: " + newState); 101 } 102 break; 103 104 case CANCEL_BOND: 105 default: 106 Log.e(TAG, "Received unhandled state: " + msg.what); 107 return false; 108 } 109 return true; 110 } 111 } 112 113 114 private class PendingCommandState extends State { 115 private final ArrayList<BluetoothDevice> mDevices = 116 new ArrayList<BluetoothDevice>(); 117 118 @Override 119 public void enter() { 120 infoLog("Entering PendingCommandState State"); 121 BluetoothDevice dev = (BluetoothDevice)getCurrentMessage().obj; 122 } 123 124 @Override 125 public boolean processMessage(Message msg) { 126 if (msg.what == SM_QUIT_CMD) { 127 Log.d(TAG, "PendingCommandState(): Received quit request..."); 128 return false; 129 } 130 131 BluetoothDevice dev = (BluetoothDevice)msg.obj; 132 boolean result = false; 133 if (mDevices.contains(dev) && 134 msg.what != CANCEL_BOND && msg.what != BONDING_STATE_CHANGE) { 135 deferMessage(msg); 136 return true; 137 } 138 139 switch (msg.what) { 140 case CREATE_BOND: 141 result = createBond(dev, false); 142 break; 143 case REMOVE_BOND: 144 result = removeBond(dev, false); 145 break; 146 case CANCEL_BOND: 147 result = cancelBond(dev); 148 break; 149 case BONDING_STATE_CHANGE: 150 int newState = msg.arg1; 151 sendIntent(dev, newState); 152 if(newState != BluetoothDevice.BOND_BONDING ) 153 { 154 /* this is either none/bonded, remove and transition */ 155 result = !mDevices.remove(dev); 156 if (mDevices.isEmpty()) { 157 transitionTo(mStableState); 158 } 159 } 160 else if(!mDevices.contains(dev)) 161 result=true; 162 break; 163 default: 164 Log.e(TAG, "Received unhandled event:" + msg.what); 165 return false; 166 } 167 if (result) mDevices.add(dev); 168 169 return true; 170 } 171 } 172 173 private boolean cancelBond(BluetoothDevice dev) { 174 if (dev.getBondState() == BluetoothDevice.BOND_BONDING) { 175 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 176 if (!mAdapterService.cancelBondNative(addr)) { 177 Log.e(TAG, "Unexpected error while cancelling bond:"); 178 } else { 179 return true; 180 } 181 } 182 return false; 183 } 184 185 private boolean removeBond(BluetoothDevice dev, boolean transition) { 186 if (dev.getBondState() == BluetoothDevice.BOND_BONDED) { 187 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 188 if (!mAdapterService.removeBondNative(addr)) { 189 Log.e(TAG, "Unexpected error while removing bond:"); 190 } else { 191 if (transition) transitionTo(mPendingCommandState); 192 return true; 193 } 194 195 } 196 return false; 197 } 198 199 private boolean createBond(BluetoothDevice dev, boolean transition) { 200 if (dev.getBondState() == BluetoothDevice.BOND_NONE) { 201 infoLog("Bond address is:" + dev); 202 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 203 if (!mAdapterService.createBondNative(addr)) { 204 sendIntent(dev, BluetoothDevice.BOND_NONE); 205 return false; 206 } else if (transition) { 207 transitionTo(mPendingCommandState); 208 } 209 return true; 210 } 211 return false; 212 } 213 214 private void sendIntent(BluetoothDevice device, int newState) { 215 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); 216 int oldState = devProp.getBondState(); 217 if (oldState == newState) return; 218 219 devProp.setBondState(newState); 220 221 Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 222 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 223 intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); 224 intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 225 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); 226 infoLog("Bond State Change Intent:" + device + " OldState: " + oldState 227 + " NewState: " + newState); 228 } 229 230 void bondStateChangeCallback(int status, byte[] address, int newState) { 231 BluetoothDevice device = mRemoteDevices.getDevice(address); 232 233 if (device == null) { 234 errorLog("No record of the device:" + device); 235 return; 236 } 237 238 infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device 239 + " newState: " + newState); 240 241 Message msg = obtainMessage(BONDING_STATE_CHANGE); 242 msg.obj = device; 243 244 if (newState == BOND_STATE_BONDED) 245 msg.arg1 = BluetoothDevice.BOND_BONDED; 246 else if (newState == BOND_STATE_BONDING) 247 msg.arg1 = BluetoothDevice.BOND_BONDING; 248 else 249 msg.arg1 = BluetoothDevice.BOND_NONE; 250 251 sendMessage(msg); 252 } 253 254 private void infoLog(String msg) { 255 Log.i(TAG, msg); 256 } 257 258 private void errorLog(String msg) { 259 Log.e(TAG, msg); 260 } 261} 262