package cgeo.geocaching.test; import android.app.Activity; import android.content.ComponentName; import android.content.pm.InstrumentationInfo; import android.os.AsyncTask; import android.os.Bundle; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.List; import butterknife.ButterKnife; public class CgeoTestsActivity extends Activity { private static final String TAG = CgeoTestsActivity.class.getName(); private static final int TIMEOUT = 600 * 1000; private TextView logView; private LogcatAsyncTask logCatTask; private BottomAwareScrollView scrollView; private class LogcatAsyncTask extends AsyncTask<Integer, String, Void> { // TestRunner and silence others private static final String CMD = "logcat -v brief TestRunner:I cgeo:I *:S"; private BufferedReader mReader; private Process mProc; LogcatAsyncTask() { try { mProc = Runtime.getRuntime().exec(CMD); mReader = new BufferedReader(new InputStreamReader( mProc.getInputStream())); } catch (final Exception e) { Log.e(TAG, "Creating proc", e); } } @Override protected void onProgressUpdate(final String... values) { final String line = values[0]; final boolean isAtBottom = scrollView.isAtBottom(); if (!TextUtils.isEmpty(line)) { logView.append(Html.fromHtml("<font color=\"" + color(line) + "\">" + line + "</font><br/>")); if (isAtBottom) { scrollView.scrollTo(0, logView.getBottom()); } } } private String color(final String line) { switch (line.charAt(0)) { case 'E': return "red"; case 'W': return "#FFA500"; case 'D': return "blue"; default: return "white"; } } @Override protected Void doInBackground(final Integer... params) { final long timeout = System.currentTimeMillis() + params[0]; try { do { Thread.sleep(50); publishProgress(mReader.readLine()); } while (System.currentTimeMillis() < timeout); } catch (InterruptedException | IOException e) { publishProgress("ERROR: " + e); } finally { publishProgress("END"); mProc.destroy(); } return null; } } @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.cgeo_tests_activity); logView = ButterKnife.findById(this, R.id.logOutput); scrollView = ButterKnife.findById(this, R.id.scrollView); } @Override protected void onDestroy() { if (logCatTask != null) { logCatTask.cancel(true); } super.onDestroy(); } private InstrumentationInfo getInstrumentationInfo(final String packageName) { final List<InstrumentationInfo> list = getPackageManager() .queryInstrumentation(packageName, 0); return !list.isEmpty() ? list.get(0) : null; } /** * @param v * referenced from XML layout */ public void runTests(final View v) { final Button button = ButterKnife.findById(this, R.id.buttonRun); button.setEnabled(false); runTestsInternally(); } private void runTestsInternally() { final String pn = getPackageName().replaceFirst(".test$", ""); final InstrumentationInfo info = getInstrumentationInfo(pn); if (info == null) { Toast.makeText(this, "Cannot find instrumentation for " + pn, Toast.LENGTH_SHORT) .show(); return; } final ComponentName cn = new ComponentName(info.packageName, info.name); if (startInstrumentation(cn, null, null)) { logCatTask = new LogcatAsyncTask(); logCatTask.execute(TIMEOUT); } else { Toast.makeText(this, "Cannot run instrumentation for " + pn, Toast.LENGTH_SHORT) .show(); } } }