1 package com.android.bluetooth.tests; 2 3 import java.io.IOException; 4 import java.util.ArrayList; 5 import java.util.concurrent.CountDownLatch; 6 7 import javax.obex.ClientSession; 8 import javax.obex.HeaderSet; 9 import javax.obex.ObexTransport; 10 import javax.obex.Operation; 11 import javax.obex.ServerSession; 12 13 import junit.framework.Assert; 14 15 import android.content.Context; 16 import android.hardware.camera2.impl.GetCommand; 17 import android.os.Handler; 18 import android.os.Handler.Callback; 19 import android.os.HandlerThread; 20 import android.os.Message; 21 import android.os.PowerManager; 22 import android.util.Log; 23 24 public class TestSequencer implements Callback { 25 protected static String TAG = "TestSequencer"; 26 protected static final boolean D = true; 27 28 private final static int MSG_ID_TIMEOUT = 0x01; 29 private final static int TIMEOUT_VALUE = 100*2000; // ms 30 private ArrayList<SeqStep> mSequence = null; 31 private HandlerThread mHandlerThread = null; 32 private Handler mMessageHandler = null; 33 private ObexTransport mClientTransport; 34 private ObexTransport mServerTransport; 35 36 private ClientSession mClientSession = null; 37 private ServerSession mServerSession = null; 38 public static final int STEP_INDEX_HEADER = 0xF1; /*0xFE*/ 39 40 public enum OPTYPE {CONNECT, PUT, GET, SET_PATH, DISCONNECT}; 41 42 private ITestSequenceConfigurator mConfigurator = null; 43 TestSequencer(ObexTransport clientTransport, ObexTransport serverTransport, ITestSequenceConfigurator configurator)44 public TestSequencer(ObexTransport clientTransport, ObexTransport serverTransport, 45 ITestSequenceConfigurator configurator) 46 throws IOException { 47 /* Setup the looper thread to handle timeout messages */ 48 // mHandlerThread = new HandlerThread("TestTimeoutHandler", 49 // android.os.Process.THREAD_PRIORITY_BACKGROUND); 50 // mHandlerThread.start(); 51 // Looper testLooper = mHandlerThread.getLooper(); 52 // mMessageHandler = new Handler(testLooper, this); 53 //TODO: fix looper cleanup on server - crash after 464 iterations - related to prepare? 54 55 mClientTransport = clientTransport; 56 mServerTransport = serverTransport; 57 58 /* Initialize members */ 59 mSequence = new ArrayList<SeqStep>(); 60 mConfigurator = configurator; 61 Assert.assertNotNull(configurator); 62 } 63 64 /** 65 * Add a test step to the sequencer. 66 * @param type the OBEX operation to perform. 67 * @return the created step, which can be decorated before execution. 68 */ addStep(OPTYPE type, ISeqStepValidator validator)69 public SeqStep addStep(OPTYPE type, ISeqStepValidator validator) { 70 SeqStep newStep = new SeqStep(type); 71 newStep.mValidator = validator; 72 mSequence.add(newStep); 73 return newStep; 74 } 75 76 /** 77 * Add a sub-step to a sequencer step. All requests added to the same index will be send to 78 * the SapServer in the order added before listening for the response. 79 * The response order is not validated - hence for each response received the entire list of 80 * responses in the step will be searched for a match. 81 * @param index the index returned from addStep() to which the sub-step is to be added. 82 * @param request The request to send to the SAP server 83 * @param response The response to EXPECT from the SAP server 84 85 public void addSubStep(int index, SapMessage request, SapMessage response) { 86 SeqStep step = sequence.get(index); 87 step.add(request, response); 88 }*/ 89 90 91 /** 92 * Run the sequence. 93 * Validate the response is either the expected response or one of the expected events. 94 * 95 * @return true when done - asserts at error/fail 96 */ run(Context context)97 public boolean run(Context context) throws IOException { 98 CountDownLatch stopLatch = new CountDownLatch(1); 99 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 100 PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 101 //wl.acquire(); 102 try { 103 /* TODO: 104 * First create sequencer to validate using BT-snoop 105 * 1) Create the transports (this could include a validation sniffer on each side) 106 * 2) Create a server thread with a link to the transport 107 * 3) execute the client operation 108 * 4) validate response 109 * 110 * On server: 111 * 1) validate the request contains the expected content 112 * 2) send response. 113 * */ 114 115 /* Create the server */ 116 if(mServerTransport != null) { 117 mServerSession = new ServerSession(mServerTransport, 118 mConfigurator.getObexServer(mSequence, stopLatch) , null); 119 } 120 121 /* Create the client */ 122 if(mClientTransport != null) { 123 mClientSession = new ClientSession(mClientTransport); 124 125 for(SeqStep step : mSequence) { 126 long stepIndex = mSequence.indexOf(step); 127 128 Log.i(TAG, "Executing step " + stepIndex + " of type: " + step.mType); 129 130 switch(step.mType) { 131 case CONNECT: { 132 HeaderSet reqHeaders = step.mReqHeaders; 133 if(reqHeaders == null) { 134 reqHeaders = new HeaderSet(); 135 } 136 reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex); 137 HeaderSet response = mClientSession.connect(reqHeaders); 138 step.validate(response, null); 139 step.clientPostAction(response, null); 140 break; 141 } 142 case GET:{ 143 HeaderSet reqHeaders = step.mReqHeaders; 144 if(reqHeaders == null) { 145 reqHeaders = new HeaderSet(); 146 } 147 reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex); 148 Log.i(TAG, " Starting operation..."); 149 Operation op = mClientSession.get(reqHeaders); 150 Log.i(TAG, " Operation done..."); 151 step.validate(null, op); 152 step.clientPostAction(null, op); 153 break; 154 } 155 case PUT: { 156 HeaderSet reqHeaders = step.mReqHeaders; 157 if(reqHeaders == null) { 158 reqHeaders = new HeaderSet(); 159 } 160 reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex); 161 Operation op = mClientSession.put(reqHeaders); 162 step.validate(null, op); 163 step.clientPostAction(null, op); 164 break; 165 } 166 case SET_PATH: { 167 HeaderSet reqHeaders = step.mReqHeaders; 168 if(reqHeaders == null) { 169 reqHeaders = new HeaderSet(); 170 } 171 reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex); 172 try{ 173 HeaderSet response = mClientSession.setPath(reqHeaders, 174 step.mSetPathBackup, step.mSetPathCreate);; 175 Log.i(TAG,"Received setPath response..."); 176 step.validate(response, null); 177 step.clientPostAction(response, null); 178 } catch (IOException e) { 179 Log.e(TAG, "Error getting response code", e); 180 } 181 break; 182 } 183 case DISCONNECT: { 184 Log.i(TAG,"Requesting disconnect..."); 185 HeaderSet reqHeaders = step.mReqHeaders; 186 if(reqHeaders == null) { 187 reqHeaders = new HeaderSet(); 188 } 189 reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex); 190 try{ 191 HeaderSet response = mClientSession.disconnect(reqHeaders); 192 Log.i(TAG,"Received disconnect response..."); 193 step.validate(response, null); 194 step.clientPostAction(response, null); 195 } catch (IOException e) { 196 Log.e(TAG, "Error getting response code", e); 197 } 198 break; 199 } 200 default: 201 Assert.assertTrue("Unknown type: " + step.mType, false); 202 break; 203 204 } 205 } 206 mClientSession.close(); 207 } 208 /* All done, close down... */ 209 if(mServerSession != null) { 210 boolean interrupted = false; 211 do { 212 try { 213 interrupted = false; 214 Log.i(TAG,"Waiting for stopLatch signal..."); 215 stopLatch.await(); 216 } catch (InterruptedException e) { 217 Log.w(TAG,e); 218 interrupted = true; 219 } 220 } while (interrupted == true); 221 Log.i(TAG,"stopLatch signal received closing down..."); 222 try { 223 interrupted = false; 224 Log.i(TAG," Sleep 50ms to allow disconnect signal to be send before closing."); 225 Thread.sleep(50); 226 } catch (InterruptedException e) { 227 Log.w(TAG,e); 228 interrupted = true; 229 } 230 mServerSession.close(); 231 } 232 // this will close the I/O streams as well. 233 } finally { 234 //wl.release(); 235 } 236 return true; 237 } 238 shutdown()239 public void shutdown() { 240 // mMessageHandler.removeCallbacksAndMessages(null); 241 // mMessageHandler.quit(); 242 // mMessageHandler = null; 243 } 244 245 246 // private void startTimer() { 247 // Message timeoutMessage = mMessageHandler.obtainMessage(MSG_ID_TIMEOUT); 248 // mMessageHandler.sendMessageDelayed(timeoutMessage, TIMEOUT_VALUE); 249 // } 250 // 251 // private void stopTimer() { 252 // mMessageHandler.removeMessages(MSG_ID_TIMEOUT); 253 // } 254 255 @Override handleMessage(Message msg)256 public boolean handleMessage(Message msg) { 257 258 Log.i(TAG,"Handling message ID: " + msg.what); 259 260 switch(msg.what) { 261 case MSG_ID_TIMEOUT: 262 Log.w(TAG, "Timeout occured!"); 263 /* try { 264 //inStream.close(); 265 } catch (IOException e) { 266 Log.e(TAG, "failed to close inStream", e); 267 } 268 try { 269 //outStream.close(); 270 } catch (IOException e) { 271 Log.e(TAG, "failed to close outStream", e); 272 }*/ 273 break; 274 default: 275 /* Message not handled */ 276 return false; 277 } 278 return true; // Message handles 279 } 280 281 282 283 } 284 285