1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.verifierusbcompanion; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.Message; 22 import androidx.annotation.NonNull; 23 import android.util.Log; 24 25 import java.util.Arrays; 26 27 /** 28 * Framework for all companion tests of this app. 29 */ 30 abstract class TestCompanion extends Thread { 31 private final @NonNull Context mContext; 32 private final @NonNull TestHandler mHandler; 33 private boolean mShouldAbort; 34 35 /** 36 * Create a new test companion 37 * 38 * @param context Context to be used for the test companion 39 * @param observer Observer observing the test companion 40 */ TestCompanion(@onNull Context context, @NonNull TestObserver observer)41 TestCompanion(@NonNull Context context, @NonNull TestObserver observer) { 42 mContext = context; 43 mHandler = new TestHandler(observer); 44 } 45 46 /** 47 * @return the context to be used by the test companion 48 */ getContext()49 protected @NonNull Context getContext() { 50 return mContext; 51 } 52 requestAbort()53 void requestAbort() { 54 mShouldAbort = true; 55 interrupt(); 56 } 57 58 /** 59 * @return if the test companion should abort 60 */ shouldAbort()61 protected boolean shouldAbort() { 62 return mShouldAbort; 63 } 64 65 /** 66 * Indicate that the test companion succeeded. 67 */ success()68 protected void success() { 69 mHandler.obtainMessage(TestHandler.SUCCESS).sendToTarget(); 70 } 71 72 /** 73 * Indicate that the test companion failed. 74 * 75 * @param error Description why the test failed 76 */ fail(@onNull CharSequence error)77 protected void fail(@NonNull CharSequence error) { 78 mHandler.obtainMessage(TestHandler.FAIL, error).sendToTarget(); 79 } 80 81 /** 82 * Indicate that the test companion was aborted. 83 */ abort()84 private void abort() { 85 mHandler.obtainMessage(TestHandler.ABORT).sendToTarget(); 86 } 87 88 /** 89 * Update the status of the test companion. 90 * 91 * @param status The new status message 92 */ updateStatus(@onNull CharSequence status)93 protected void updateStatus(@NonNull CharSequence status) { 94 Log.i(this.getClass().getSimpleName(), "Status: " + status); 95 96 mHandler.obtainMessage(TestHandler.UPDATE_STATUS, status).sendToTarget(); 97 } 98 99 @Override run()100 public final void run() { 101 try { 102 runTest(); 103 } catch (Throwable e) { 104 if (e instanceof InterruptedException && shouldAbort()) { 105 abort(); 106 } else { 107 fail(e + "\n" + Arrays.toString(e.getStackTrace())); 108 } 109 110 return; 111 } 112 113 success(); 114 } 115 116 /** 117 * The test companion code. 118 * 119 * @throws Throwable If this returns without an exception, the test companion succeeded. 120 */ runTest()121 protected abstract void runTest() throws Throwable; 122 123 /** 124 * Observe the state of this test companion 125 */ 126 public interface TestObserver { onStatusUpdate(@onNull CharSequence status)127 void onStatusUpdate(@NonNull CharSequence status); onSuccess()128 void onSuccess(); onFail(@onNull CharSequence error)129 void onFail(@NonNull CharSequence error); onAbort()130 void onAbort(); 131 } 132 133 /** 134 * Serialize callbacks to main thread. 135 */ 136 public static class TestHandler extends Handler { 137 static final int SUCCESS = 0; 138 static final int FAIL = 1; 139 static final int ABORT = 2; 140 static final int UPDATE_STATUS = 3; 141 142 private final @NonNull TestObserver mObserver; 143 TestHandler(@onNull TestObserver observer)144 TestHandler(@NonNull TestObserver observer) { 145 mObserver = observer; 146 } 147 148 @Override handleMessage(Message msg)149 public void handleMessage(Message msg) { 150 switch (msg.what) { 151 case SUCCESS: 152 mObserver.onSuccess(); 153 break; 154 case FAIL: 155 mObserver.onFail((CharSequence)msg.obj); 156 break; 157 case ABORT: 158 mObserver.onAbort(); 159 break; 160 case UPDATE_STATUS: 161 mObserver.onStatusUpdate((CharSequence)msg.obj); 162 break; 163 } 164 } 165 } 166 } 167