BondStateMachine.java revision ff4f17bf64978d0738c66e1b6dd70be8664efc24
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 private final AdapterService mAdapterService; 39 private final Context mContext; 40 private final AdapterProperties mAdapterProperties; 41 private final RemoteDevices mRemoteDevices; 42 43 private PendingCommandState mPendingCommandState = new PendingCommandState(); 44 private StableState mStableState = new StableState(); 45 46 public BondStateMachine(AdapterService service, Context context, 47 AdapterProperties prop) { 48 super("BondStateMachine:"); 49 addState(mStableState); 50 addState(mPendingCommandState); 51 setInitialState(mStableState); 52 mAdapterService = service; 53 mAdapterProperties = prop; 54 mContext = context; 55 mRemoteDevices = RemoteDevices.getInstance(service, context); 56 } 57 58 private class StableState extends State { 59 @Override 60 public void enter() { 61 infoLog("Entering Off State"); 62 } 63 64 @Override 65 public boolean processMessage(Message msg) { 66 BluetoothDevice dev = (BluetoothDevice)msg.obj; 67 switch(msg.what) { 68 case CREATE_BOND: 69 createBond(dev, true); 70 break; 71 case REMOVE_BOND: 72 removeBond(dev, true); 73 break; 74 case CANCEL_BOND: 75 case BONDING_STATE_CHANGE: 76 default: 77 Log.e(TAG, "Received unhandled state: " + msg.what); 78 return false; 79 } 80 return true; 81 } 82 } 83 84 85 private class PendingCommandState extends State { 86 private final ArrayList<BluetoothDevice> mDevices = 87 new ArrayList<BluetoothDevice>(); 88 89 @Override 90 public void enter() { 91 infoLog("Entering PendingCommandState State"); 92 BluetoothDevice dev = (BluetoothDevice)getCurrentMessage().obj; 93 mDevices.add(dev); 94 } 95 96 @Override 97 public boolean processMessage(Message msg) { 98 BluetoothDevice dev = (BluetoothDevice)msg.obj; 99 boolean result; 100 if (mDevices.contains(dev) && 101 msg.what != CANCEL_BOND && msg.what != BONDING_STATE_CHANGE) { 102 deferMessage(msg); 103 return true; 104 } 105 106 switch (msg.what) { 107 case CREATE_BOND: 108 result = createBond(dev, false); 109 break; 110 case REMOVE_BOND: 111 result = removeBond(dev, false); 112 break; 113 case CANCEL_BOND: 114 result = cancelBond(dev); 115 break; 116 case BONDING_STATE_CHANGE: 117 int newState = msg.arg1; 118 sendIntent(dev, newState); 119 result = mDevices.remove(dev); 120 if (mDevices.isEmpty()) { 121 transitionTo(mStableState); 122 } 123 break; 124 default: 125 Log.e(TAG, "Received unhandled event:" + msg.what); 126 return false; 127 } 128 if (result) mDevices.add(dev); 129 130 return true; 131 } 132 } 133 134 private boolean cancelBond(BluetoothDevice dev) { 135 if (dev.getBondState() == BluetoothDevice.BOND_BONDING) { 136 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 137 if (!mAdapterService.cancelBondNative(addr)) { 138 Log.e(TAG, "Unexpected error while cancelling bond:"); 139 } else { 140 return true; 141 } 142 } 143 return false; 144 } 145 146 private boolean removeBond(BluetoothDevice dev, boolean transition) { 147 if (dev.getBondState() == BluetoothDevice.BOND_BONDED) { 148 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 149 if (!mAdapterService.removeBondNative(addr)) { 150 Log.e(TAG, "Unexpected error while removing bond:"); 151 } else { 152 if (transition) transitionTo(mPendingCommandState); 153 return true; 154 } 155 156 } 157 return false; 158 } 159 160 private boolean createBond(BluetoothDevice dev, boolean transition) { 161 if (dev.getBondState() == BluetoothDevice.BOND_NONE) { 162 sendIntent(dev, BluetoothDevice.BOND_BONDING); 163 infoLog("Bond address is:" + dev); 164 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 165 if (!mAdapterService.createBondNative(addr)) { 166 sendIntent(dev, BluetoothDevice.BOND_NONE); 167 } else if (transition) { 168 transitionTo(mPendingCommandState); 169 } 170 return true; 171 } 172 return false; 173 } 174 175 private void sendIntent(BluetoothDevice device, int newState) { 176 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); 177 int oldState = devProp.getBondState(); 178 if (oldState == newState) return; 179 180 devProp.setBondState(newState); 181 182 Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 183 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 184 intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); 185 intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 186 mContext.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); 187 infoLog("Bond State Change Intent:" + device + " OldState: " + oldState 188 + " NewState: " + newState); 189 } 190 191 void bondStateChangeCallback(int status, byte[] address, int newState) { 192 BluetoothDevice device = mRemoteDevices.getDevice(address); 193 194 if (device == null) { 195 errorLog("No record of the device:" + device); 196 return; 197 } 198 199 infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device 200 + " newState: " + newState); 201 202 Message msg = obtainMessage(BONDING_STATE_CHANGE); 203 msg.obj = device; 204 205 int state = (newState == 1 ? BluetoothDevice.BOND_BONDED : BluetoothDevice.BOND_NONE); 206 msg.arg1 = state; 207 sendMessage(msg); 208 } 209 210 private void infoLog(String msg) { 211 Log.i(TAG, msg); 212 } 213 214 private void errorLog(String msg) { 215 Log.e(TAG, msg); 216 } 217} 218