Moved practically all of the prerefactoring functionality to the new design.

Renamed LayoutTestsRunner activity to TestsListActivity. It will be responsible for restrating the Executer after the crash. Now it only starts
it.
Renamed LayoutTestsRunnerThread to TestsListPreloaderThread. It only preloads tests now.
LayoutTest class is no longer needed, its functionality is in LayoutTestsExecuter.
Most of the functionality from LayoutTestsRunnerThread is now in ManagerService.

Change-Id: I08924d949ceb9f8816888bc8e795256d0542fa99
diff --git a/tests/DumpRenderTree2/AndroidManifest.xml b/tests/DumpRenderTree2/AndroidManifest.xml
index 14df611..1213674 100644
--- a/tests/DumpRenderTree2/AndroidManifest.xml
+++ b/tests/DumpRenderTree2/AndroidManifest.xml
@@ -25,13 +25,13 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".LayoutTestsRunner"
-                  android:label="Layout tests' runner">
+        <activity android:name=".TestsListActivity"
+                  android:label="Tests' list activity">
         </activity>
 
-        <activity android:name=".LayoutTestsExecuter"
-                  android:label="Layout tests' executer"
-                  android:process=":executer">
+        <activity android:name=".LayoutTestsExecutor"
+                  android:label="Layout tests' executor"
+                  android:process=":executor">
         </activity>
 
         <service android:name="ManagerService">
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java
index 3c7dee2..0a80ed4 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java
@@ -27,8 +27,21 @@
 public abstract class AbstractResult {
 
     public enum TestType {
-        TEXT,
-        PIXEL
+        TEXT {
+            @Override
+            public AbstractResult createResult(Bundle bundle) {
+                return new TextResult(bundle);
+            }
+        },
+        RENDER_TREE {
+            @Override
+            public AbstractResult createResult(Bundle bundle) {
+                /** TODO: RenderTree tests are not yet supported */
+                return null;
+            }
+        };
+
+        public abstract AbstractResult createResult(Bundle bundle);
     }
 
     public enum ResultCode {
@@ -101,6 +114,8 @@
      */
     public abstract TestType getType();
 
+    public abstract String getRelativePath();
+
     /**
      * Returns a piece of HTML code that presents a visual diff between a result and
      * the expected result.
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java
deleted file mode 100644
index 1312ef9..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.app.Activity;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.webkit.WebStorage.QuotaUpdater;
-
-import java.io.File;
-
-/**
- * A class that represents a single layout test. It is responsible for running the test,
- * checking its result and creating an AbstractResult object.
- */
-public class LayoutTest {
-
-    private static final String LOG_TAG = "LayoutTest";
-
-    public static final int MSG_ACTUAL_RESULT_OBTAINED = 0;
-
-    private String mRelativePath;
-    private String mTestsRootDirPath;
-    private String mUrl;
-    private boolean mOnTestFinishedCalled;
-    private Message mTestFinishedMsg;
-    private AbstractResult mResult;
-
-    private WebView mWebView;
-    private Activity mActivity;
-
-    private final Handler mResultHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) {
-                mResult.setExpectedTextResult(LayoutTestsRunnerThread
-                        .getExpectedTextResult(mRelativePath));
-                mResult.setExpectedImageResult(LayoutTestsRunnerThread
-                        .getExpectedImageResult(mRelativePath));
-                mTestFinishedMsg.sendToTarget();
-            }
-        }
-    };
-
-    private WebViewClient mWebViewClient = new WebViewClient() {
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            /** Some tests fire up many page loads, we don't want to detect them */
-            if (!url.equals(mUrl)) {
-                return;
-            }
-
-            onTestFinished();
-        }
-    };
-
-    private WebChromeClient mWebChromeClient = new WebChromeClient() {
-        @Override
-        public void onExceededDatabaseQuota(String url, String databaseIdentifier,
-                long currentQuota, long estimatedSize, long totalUsedQuota,
-                QuotaUpdater quotaUpdater) {
-            /** TODO: This should be recorded as part of the text result */
-            quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024);
-        }
-
-        @Override
-        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
-            /** TODO: Alerts should be recorded as part of text result */
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
-            /** TODO: Alerts should be recorded as part of text result */
-            result.confirm();
-            return true;
-        }
-
-        @Override
-        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
-                JsPromptResult result) {
-            /** TODO: Alerts should be recorded as part of text result */
-            result.confirm();
-            return true;
-        }
-
-    };
-
-    public LayoutTest(String relativePath, String testsRootDirPath, Message testFinishedMsg,
-            LayoutTestsRunner activity) {
-        mRelativePath = relativePath;
-        mTestsRootDirPath = testsRootDirPath;
-        mTestFinishedMsg = testFinishedMsg;
-        mActivity = activity;
-    }
-
-    public LayoutTest(AbstractResult result, String relativePath) {
-        mResult = result;
-        mRelativePath = relativePath;
-    }
-
-    public void run() {
-        mWebView = new WebView(mActivity);
-        mActivity.setContentView(mWebView);
-
-        setupWebView();
-
-        /** TODO: Add timeout msg */
-        mUrl = Uri.fromFile(new File(mTestsRootDirPath, mRelativePath)).toString();
-        mWebView.loadUrl(mUrl);
-    }
-
-    private void onTestFinished() {
-        if (mOnTestFinishedCalled) {
-            return;
-        }
-
-        mOnTestFinishedCalled = true;
-
-        /**
-         * If the result has not been set by the time the test finishes we create
-         * a default type of result.
-         */
-        if (mResult == null) {
-            /** TODO: Default type should be RenderTreeResult. We don't support it now. */
-            mResult = new TextResult(mRelativePath);
-        }
-
-        /** TODO: Implement waitUntilDone */
-
-        mResult.obtainActualResults(mWebView,
-                mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED));
-    }
-
-    private void setupWebView() {
-        WebSettings webViewSettings = mWebView.getSettings();
-        webViewSettings.setAppCacheEnabled(true);
-        webViewSettings.setAppCachePath(mActivity.getApplicationContext().getCacheDir().getPath());
-        webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE);
-        webViewSettings.setJavaScriptEnabled(true);
-        webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true);
-        webViewSettings.setSupportMultipleWindows(true);
-        webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-        webViewSettings.setDatabaseEnabled(true);
-        webViewSettings.setDatabasePath(mActivity.getDir("databases", 0).getAbsolutePath());
-        webViewSettings.setDomStorageEnabled(true);
-        webViewSettings.setWorkersEnabled(false);
-        webViewSettings.setXSSAuditorEnabled(false);
-
-        mWebView.setWebViewClient(mWebViewClient);
-        mWebView.setWebChromeClient(mWebChromeClient);
-    }
-
-    public AbstractResult getResult() {
-        return mResult;
-    }
-
-    public String getRelativePath() {
-        return mRelativePath;
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
similarity index 84%
rename from tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java
rename to tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
index 6fd3085..608b14e4 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
@@ -30,6 +30,7 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.Window;
 import android.webkit.JsPromptResult;
 import android.webkit.JsResult;
 import android.webkit.WebChromeClient;
@@ -47,7 +48,7 @@
  * to ManagerService. The reason why is to handle crashing (test that crashes brings down
  * whole process with it).
  */
-public class LayoutTestsExecuter extends Activity {
+public class LayoutTestsExecutor extends Activity {
 
     /** TODO: make it a setting */
     static final String TESTS_ROOT_DIR_PATH =
@@ -55,14 +56,23 @@
             File.separator + "android" +
             File.separator + "LayoutTests";
 
-    private static final String LOG_TAG = "LayoutTestExecuter";
+    private static final String LOG_TAG = "LayoutTestExecutor";
 
     public static final String EXTRA_TESTS_LIST = "TestsList";
+    public static final String EXTRA_TEST_INDEX = "TestIndex";
 
     private static final int MSG_ACTUAL_RESULT_OBTAINED = 0;
 
     private List<String> mTestsList;
-    private int mCurrentTestCount = 0;
+
+    /**
+     * This is a number of currently running test. It is 0-based and doesn't reset after
+     * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts
+     * it.
+     */
+    private int mCurrentTestIndex;
+
+    private int mTotalTestCount;
 
     private WebView mCurrentWebView;
     private String mCurrentTestRelativePath;
@@ -94,6 +104,8 @@
         public void handleMessage(Message msg) {
             if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) {
                 reportResultToService();
+                mCurrentTestIndex++;
+                updateProgressBar();
                 runNextTest();
             }
         }
@@ -153,8 +165,12 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        requestWindowFeature(Window.FEATURE_PROGRESS);
+
         Intent intent = getIntent();
         mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST);
+        mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1);
+        mTotalTestCount = mCurrentTestIndex + mTestsList.size();
 
         bindService(new Intent(this, ManagerService.class), mServiceConnection,
                 Context.BIND_AUTO_CREATE);
@@ -191,7 +207,6 @@
             return;
         }
 
-        mCurrentTestCount++;
         mCurrentTestRelativePath = mTestsList.remove(0);
         mCurrentTestUri =
                 Uri.fromFile(new File(TESTS_ROOT_DIR_PATH, mCurrentTestRelativePath)).toString();
@@ -226,6 +241,7 @@
             Message serviceMsg =
                     Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS);
             Bundle bundle = mCurrentResult.getBundle();
+            bundle.putInt("testIndex", mCurrentTestIndex);
             /** TODO: Add timeout info to bundle */
             serviceMsg.setData(bundle);
             mManagerServiceMessenger.send(serviceMsg);
@@ -234,7 +250,20 @@
         }
     }
 
+    private void updateProgressBar() {
+        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+                mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount);
+        setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " +
+                "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")");
+    }
+
     private void onAllTestsFinished() {
-        Log.d(LOG_TAG + "::onAllTestsFisnihed", "Begin.");
+        try {
+            Message serviceMsg =
+                    Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED);
+            mManagerServiceMessenger.send(serviceMsg);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG + "::onAllTestsFinished", e.getMessage());
+        }
     }
 }
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java
deleted file mode 100644
index 4421aba..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.Window;
-
-/**
- * An Activity that is responsible only for updating the UI features, like titles, progress bars,
- * etc.
- *
- * <p>Also, the webview form the test must be running in this activity's thread if we want
- * to be able to display it on the screen.
- */
-public class LayoutTestsRunner extends Activity {
-
-    public static final int MSG_UPDATE_PROGRESS = 1;
-    public static final int MSG_SHOW_PROGRESS_DIALOG = 2;
-    public static final int MSG_DISMISS_PROGRESS_DIALOG = 3;
-
-    /** Constants for adding extras to an intent */
-    public static final String EXTRA_TEST_PATH = "TestPath";
-
-    private static ProgressDialog sProgressDialog;
-
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE_PROGRESS:
-                    int i = msg.arg1;
-                    int size = msg.arg2;
-                    getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                            i * Window.PROGRESS_END / size);
-                    setTitle(i * 100 / size + "% (" + i + "/" + size + ")");
-                    break;
-
-                case MSG_SHOW_PROGRESS_DIALOG:
-                    sProgressDialog.show();
-                    break;
-
-                case MSG_DISMISS_PROGRESS_DIALOG:
-                    sProgressDialog.dismiss();
-                    break;
-            }
-        }
-    };
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        /** Prepare the progress dialog */
-        sProgressDialog = new ProgressDialog(LayoutTestsRunner.this);
-        sProgressDialog.setCancelable(false);
-        sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
-        sProgressDialog.setTitle(R.string.dialog_progress_title);
-        sProgressDialog.setMessage(getText(R.string.dialog_progress_msg));
-
-        requestWindowFeature(Window.FEATURE_PROGRESS);
-
-        /** Execute the intent */
-        Intent intent = getIntent();
-        if (!intent.getAction().equals(Intent.ACTION_RUN)) {
-            return;
-        }
-        String path = intent.getStringExtra(EXTRA_TEST_PATH);
-
-        new LayoutTestsRunnerThread(path, this).start();
-    }
-
-    public Handler getHandler() {
-        return mHandler;
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java
deleted file mode 100644
index ac814cb..0000000
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree2;
-
-import android.content.Intent;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.LinkedList;
-
-/**
- * A Thread that is responsible for finding and loading the tests, starting them and
- * generating summaries. The actual running of the test is delegated to LayoutTestsRunner
- * activity (a UI thread) because of a WebView object that need to be created in UI thread
- * so it can be displayed on the screen. However, the logic for doing this remains in
- * this class (in handler created in constructor).
- */
-public class LayoutTestsRunnerThread extends Thread {
-
-    private static final String LOG_TAG = "LayoutTestsRunnerThread";
-
-    /** Messages for handler on this thread */
-    public static final int MSG_TEST_FINISHED = 0;
-
-    /** Messages for our handler running on UI thread */
-    public static final int MSG_RUN_TEST = 0;
-
-    /** TODO: make it a setting */
-    private static final String TESTS_ROOT_DIR_PATH =
-            Environment.getExternalStorageDirectory() +
-            File.separator + "android" +
-            File.separator + "LayoutTests";
-
-    /** TODO: make it a setting */
-    private static final String RESULTS_ROOT_DIR_PATH =
-            Environment.getExternalStorageDirectory() +
-            File.separator + "android" +
-            File.separator + "LayoutTests-results";
-
-    /** TODO: Make it a setting */
-    private static final String EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX =
-            "platform" + File.separator +
-            "android-v8" + File.separator;
-
-    /** TODO: Make these settings */
-    private static final String TEXT_RESULT_EXTENSION = "txt";
-    private static final String IMAGE_RESULT_EXTENSION = "png";
-
-    /** A list containing relative paths of tests to run */
-    private LinkedList<String> mTestsList = new LinkedList<String>();
-
-    private FileFilter mFileFilter;
-    private Summarizer mSummarizer;
-
-    /** Our handler running on this thread. Created in run() method. */
-    private Handler mHandler;
-
-    /** Our handler running on UI thread. Created in constructor of this thread. */
-    private Handler mHandlerOnUiThread;
-
-    /**
-     * A relative path to the folder with the tests we want to run or particular test.
-     * Used up to and including preloadTests().
-     */
-    private String mRelativePath;
-
-    private LayoutTestsRunner mActivity;
-
-    private LayoutTest mCurrentTest;
-    private String mCurrentTestPath;
-    private int mCurrentTestCount = 0;
-    private int mTotalTestCount;
-
-    /**
-     * The given path must be relative to the root dir. The given handler must be
-     * able to handle messages that update the display (UI thread).
-     *
-     * @param path
-     * @param uiDisplayHandler
-     */
-    public LayoutTestsRunnerThread(String path, LayoutTestsRunner activity) {
-        mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH);
-        mRelativePath = path;
-        mActivity = activity;
-
-        /** This creates a handler that runs on the thread that _created_ this thread */
-        mHandlerOnUiThread = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case MSG_RUN_TEST:
-                        ((LayoutTest) msg.obj).run();
-                        break;
-                }
-            }
-        };
-    }
-
-    @Override
-    public void run() {
-        Looper.prepare();
-
-        mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH);
-
-        /** A handler obtained from UI thread to handle messages concerning updating the display */
-        final Handler uiDisplayHandler = mActivity.getHandler();
-
-        /** Creates a new handler in _this_ thread */
-        mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case MSG_TEST_FINISHED:
-                        onTestFinished(mCurrentTest);
-                        uiDisplayHandler.obtainMessage(LayoutTestsRunner.MSG_UPDATE_PROGRESS,
-                                mCurrentTestCount, mTotalTestCount).sendToTarget();
-                        runNextTest();
-                        break;
-                }
-            }
-        };
-
-        /** Check if the path is correct */
-        File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath);
-        if (!file.exists()) {
-            Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath);
-            return;
-        }
-
-        /** Populate the tests' list accordingly */
-        if (file.isDirectory()) {
-            uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_SHOW_PROGRESS_DIALOG);
-            preloadTests(mRelativePath);
-            uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_DISMISS_PROGRESS_DIALOG);
-        } else {
-            mTestsList.addLast(mRelativePath);
-            mTotalTestCount = 1;
-        }
-
-        /**
-         * Instead of running next test here, we send a tests' list to Executer activity.
-         * Rest of the code is never executed and will be gradually moved to the service.
-         */
-        Intent intent = new Intent();
-        intent.setClass(mActivity, LayoutTestsExecuter.class);
-        intent.setAction(Intent.ACTION_RUN);
-        intent.putStringArrayListExtra(LayoutTestsExecuter.EXTRA_TESTS_LIST,
-                new ArrayList<String>(mTestsList));
-        mActivity.startActivity(intent);
-
-        Looper.loop();
-    }
-
-    /**
-     * Loads all the tests from the given folders and all the subfolders
-     * into mTestsList.
-     *
-     * @param dirRelativePath
-     */
-    private void preloadTests(String dirRelativePath) {
-        LinkedList<String> foldersList = new LinkedList<String>();
-        foldersList.add(dirRelativePath);
-
-        String relativePath;
-        String currentDirRelativePath;
-        String itemName;
-        File[] items;
-        while (!foldersList.isEmpty()) {
-            currentDirRelativePath = foldersList.removeFirst();
-            items = new File(TESTS_ROOT_DIR_PATH, currentDirRelativePath).listFiles();
-            for (File item : items) {
-                itemName = item.getName();
-                relativePath = currentDirRelativePath + File.separator + itemName;
-
-                if (item.isDirectory() && FileFilter.isTestDir(itemName)) {
-                    foldersList.add(relativePath);
-                    continue;
-                }
-
-                if (FileFilter.isTestFile(itemName)) {
-                    if (!mFileFilter.isSkip(relativePath)) {
-                        mTestsList.addLast(relativePath);
-                    } else {
-                        mSummarizer.addSkippedTest(relativePath);
-                    }
-                }
-            }
-        }
-
-        mTotalTestCount = mTestsList.size();
-    }
-
-    private void runNextTest() {
-        if (mTestsList.isEmpty()) {
-            onFinishedTests();
-            return;
-        }
-
-        mCurrentTestCount++;
-        mCurrentTestPath = mTestsList.removeFirst();
-        mCurrentTest = new LayoutTest(mCurrentTestPath, TESTS_ROOT_DIR_PATH,
-                mHandler.obtainMessage(MSG_TEST_FINISHED), mActivity);
-
-        /**
-         * This will run the test on UI thread. The reason why we need to run the test
-         * on UI thread is because of the WebView. If we want to display the webview on
-         * the screen it needs to be in the UI thread. WebView should be created as
-         * part of the LayoutTest.run() method.
-         */
-        mHandlerOnUiThread.obtainMessage(MSG_RUN_TEST, mCurrentTest).sendToTarget();
-    }
-
-    private void onTestFinished(LayoutTest test) {
-        String testPath = test.getRelativePath();
-
-        /** Obtain the result */
-        AbstractResult result = test.getResult();
-        if (result == null) {
-            Log.e(LOG_TAG + "::runTests", testPath + ": result NULL!!");
-            return;
-        }
-
-        dumpResultData(result, testPath);
-
-        mSummarizer.appendTest(test);
-    }
-
-    private void dumpResultData(AbstractResult result, String testPath) {
-        dumpActualTextResult(result, testPath);
-        dumpActualImageResult(result, testPath);
-    }
-
-    private void dumpActualTextResult(AbstractResult result, String testPath) {
-        String actualTextResult = result.getActualTextResult();
-        if (actualTextResult == null) {
-            return;
-        }
-
-        String resultPath = FileFilter.setPathEnding(testPath, "-actual." + TEXT_RESULT_EXTENSION);
-        FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath),
-                actualTextResult.getBytes(), false);
-    }
-
-    private void dumpActualImageResult(AbstractResult result, String testPath) {
-        byte[] actualImageResult = result.getActualImageResult();
-        if (actualImageResult == null) {
-            return;
-        }
-
-        String resultPath = FileFilter.setPathEnding(testPath, "-actual." + IMAGE_RESULT_EXTENSION);
-        FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath),
-                actualImageResult, false);
-    }
-
-    private void onFinishedTests() {
-        Log.d(LOG_TAG + "::onFinishedTests", "Begin.");
-        Looper.myLooper().quit();
-        mSummarizer.summarize();
-        /** TODO: Present some kind of notification to the user that
-         * allows to chose next action, e.g:
-         * - go to html view of results
-         * - zip results
-         * - run more tests before zipping */
-    }
-
-    public static String getExpectedTextResult(String relativePath) {
-        return new String(getExpectedResult(relativePath, TEXT_RESULT_EXTENSION));
-    }
-
-    public static byte[] getExpectedImageResult(String relativePath) {
-        return getExpectedResult(relativePath, IMAGE_RESULT_EXTENSION);
-    }
-
-    private static byte[] getExpectedResult(String relativePath, String extension) {
-        relativePath = FileFilter.setPathEnding(relativePath, "-expected." + extension);
-
-        byte[] bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath));
-        if (bytes == null) {
-            relativePath = EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX + relativePath;
-            bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath));
-        }
-
-        return bytes;
-    }
-}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
index e452a38..e32247c 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java
@@ -18,12 +18,16 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
 import android.util.Log;
 
+import java.io.File;
+
 /**
  * A service that handles managing the results of tests, informing of crashes, generating
  * summaries, etc.
@@ -32,7 +36,29 @@
 
     private static final String LOG_TAG = "ManagerService";
 
+    /** TODO: make it a setting */
+    static final String TESTS_ROOT_DIR_PATH =
+            Environment.getExternalStorageDirectory() +
+            File.separator + "android" +
+            File.separator + "LayoutTests";
+
+    /** TODO: make it a setting */
+    static final String RESULTS_ROOT_DIR_PATH =
+            Environment.getExternalStorageDirectory() +
+            File.separator + "android" +
+            File.separator + "LayoutTests-results";
+
+    /** TODO: Make it a setting */
+    private static final String EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX =
+            "platform" + File.separator +
+            "android-v8" + File.separator;
+
+    /** TODO: Make these settings */
+    private static final String TEXT_RESULT_EXTENSION = "txt";
+    private static final String IMAGE_RESULT_EXTENSION = "png";
+
     static final int MSG_PROCESS_ACTUAL_RESULTS = 0;
+    static final int MSG_ALL_TESTS_FINISHED = 1;
 
     private Handler mIncomingHandler = new Handler() {
         @Override
@@ -40,6 +66,11 @@
             switch (msg.what) {
                 case MSG_PROCESS_ACTUAL_RESULTS:
                     Log.d(LOG_TAG + ".mIncomingHandler", msg.getData().getString("relativePath"));
+                    onActualResultsObtained(msg.getData());
+                    break;
+
+                case MSG_ALL_TESTS_FINISHED:
+                    mSummarizer.summarize();
                     break;
             }
         }
@@ -47,14 +78,76 @@
 
     private Messenger mMessenger = new Messenger(mIncomingHandler);
 
+    private FileFilter mFileFilter;
+    private Summarizer mSummarizer;
+
     @Override
     public void onCreate() {
         super.onCreate();
-        /** TODO:  */
+
+        mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH);
+        mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH);
     }
 
     @Override
     public IBinder onBind(Intent intent) {
         return mMessenger.getBinder();
     }
+
+    private void onActualResultsObtained(Bundle bundle) {
+        AbstractResult results =
+                AbstractResult.TestType.valueOf(bundle.getString("type")).createResult(bundle);
+        String relativePath = results.getRelativePath();
+        results.setExpectedTextResult(getExpectedTextResult(relativePath));
+        results.setExpectedImageResult(getExpectedImageResult(relativePath));
+
+        dumpActualTextResult(results);
+        dumpActualImageResult(results);
+
+        mSummarizer.appendTest(results);
+    }
+
+    private void dumpActualTextResult(AbstractResult result) {
+        String testPath = result.getRelativePath();
+        String actualTextResult = result.getActualTextResult();
+        if (actualTextResult == null) {
+            return;
+        }
+
+        String resultPath = FileFilter.setPathEnding(testPath, "-actual." + TEXT_RESULT_EXTENSION);
+        FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath),
+                actualTextResult.getBytes(), false);
+    }
+
+    private void dumpActualImageResult(AbstractResult result) {
+        String testPath = result.getRelativePath();
+        byte[] actualImageResult = result.getActualImageResult();
+        if (actualImageResult == null) {
+            return;
+        }
+
+        String resultPath = FileFilter.setPathEnding(testPath, "-actual." + IMAGE_RESULT_EXTENSION);
+        FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath),
+                actualImageResult, false);
+    }
+
+    public static String getExpectedTextResult(String relativePath) {
+        return new String(getExpectedResult(relativePath, TEXT_RESULT_EXTENSION));
+    }
+
+    public static byte[] getExpectedImageResult(String relativePath) {
+        return getExpectedResult(relativePath, IMAGE_RESULT_EXTENSION);
+    }
+
+    private static byte[] getExpectedResult(String relativePath, String extension) {
+        relativePath = FileFilter.setPathEnding(relativePath, "-expected." + extension);
+
+        byte[] bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath));
+        if (bytes == null) {
+            relativePath = EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX + relativePath;
+            bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath));
+        }
+
+        return bytes;
+    }
 }
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
index 4d15bb5..36cde86 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java
@@ -16,8 +16,6 @@
 
 package com.android.dumprendertree2;
 
-import android.util.Log;
-
 import java.io.File;
 import java.util.EnumMap;
 import java.util.HashSet;
@@ -155,15 +153,8 @@
         mSkippedTestsList.addLast(relativePath);
     }
 
-    public void appendTest(LayoutTest test) {
-        String testPath = test.getRelativePath();
-
-        /** Obtain the result */
-        AbstractResult result = test.getResult();
-        if (result == null) {
-            Log.e(LOG_TAG + "::appendTest", testPath + ": result NULL!!");
-            return;
-        }
+    public void appendTest(AbstractResult result) {
+        String testPath = result.getRelativePath();
 
         AbstractResult.ResultCode resultCode = result.getResultCode();
 
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
new file mode 100644
index 0000000..a402ae1
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree2;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Window;
+
+import java.util.ArrayList;
+
+/**
+ * An Activity that generates a list of tests and sends the intent to
+ * LayoutTestsExecuter to run them. It also restarts the LayoutTestsExecuter
+ * after it crashes (TODO).
+ */
+public class TestsListActivity extends Activity {
+
+    private static final int MSG_TEST_LIST_PRELOADER_DONE = 0;
+
+    /** Constants for adding extras to an intent */
+    public static final String EXTRA_TEST_PATH = "TestPath";
+
+    private static ProgressDialog sProgressDialog;
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_TEST_LIST_PRELOADER_DONE:
+                    sProgressDialog.dismiss();
+                    mTestsList = (ArrayList<String>)msg.obj;
+                    mTotalTestCount = mTestsList.size();
+                    restartExecutor(0);
+                    break;
+            }
+        }
+    };
+
+    private ArrayList<String> mTestsList;
+    private int mTotalTestCount;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        /** Prepare the progress dialog */
+        sProgressDialog = new ProgressDialog(TestsListActivity.this);
+        sProgressDialog.setCancelable(false);
+        sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+        sProgressDialog.setTitle(R.string.dialog_progress_title);
+        sProgressDialog.setMessage(getText(R.string.dialog_progress_msg));
+
+        requestWindowFeature(Window.FEATURE_PROGRESS);
+
+        Intent intent = getIntent();
+        if (!intent.getAction().equals(Intent.ACTION_RUN)) {
+            return;
+        }
+        String path = intent.getStringExtra(EXTRA_TEST_PATH);
+
+        sProgressDialog.show();
+        Message doneMsg = Message.obtain(mHandler, MSG_TEST_LIST_PRELOADER_DONE);
+
+        new TestsListPreloaderThread(path, doneMsg).start();
+    }
+
+    /**
+     * (Re)starts the executer activity from the given test number (inclusive, 0-based).
+     * This number is an index in mTestsList, not the sublist passed in the intent.
+     *
+     * @param startFrom
+     *      test index in mTestsList to start the tests from (inclusive, 0-based)
+     */
+    private void restartExecutor(int startFrom) {
+        Intent intent = new Intent();
+        intent.setClass(this, LayoutTestsExecutor.class);
+        intent.setAction(Intent.ACTION_RUN);
+        intent.putStringArrayListExtra(LayoutTestsExecutor.EXTRA_TESTS_LIST,
+                new ArrayList<String>(mTestsList.subList(startFrom, mTotalTestCount)));
+        intent.putExtra(LayoutTestsExecutor.EXTRA_TEST_INDEX, startFrom);
+        startActivity(intent);
+    }
+}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
new file mode 100644
index 0000000..f76105d
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListPreloaderThread.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree2;
+
+import android.os.Environment;
+import android.os.Message;
+import android.util.Log;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+/**
+ * A Thread that is responsible for generating a lists of tests to run.
+ */
+public class TestsListPreloaderThread extends Thread {
+
+    private static final String LOG_TAG = "TestsListPreloaderThread";
+
+    /** TODO: make it a setting */
+    private static final String TESTS_ROOT_DIR_PATH =
+            Environment.getExternalStorageDirectory() +
+            File.separator + "android" +
+            File.separator + "LayoutTests";
+
+    /** A list containing relative paths of tests to run */
+    private ArrayList<String> mTestsList = new ArrayList<String>();
+
+    private FileFilter mFileFilter;
+
+    /**
+     * A relative path to the folder with the tests we want to run or particular test.
+     * Used up to and including preloadTests().
+     */
+    private String mRelativePath;
+
+    private Message mDoneMsg;
+
+    /**
+     * The given path must be relative to the root dir.
+     *
+     * @param path
+     * @param doneMsg
+     */
+    public TestsListPreloaderThread(String path, Message doneMsg) {
+        mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH);
+        mRelativePath = path;
+        mDoneMsg = doneMsg;
+    }
+
+    @Override
+    public void run() {
+        /** Check if the path is correct */
+        File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath);
+        if (!file.exists()) {
+            Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath);
+            return;
+        }
+
+        /** Populate the tests' list accordingly */
+        if (file.isDirectory()) {
+            preloadTests(mRelativePath);
+        } else {
+            mTestsList.add(mRelativePath);
+        }
+        mDoneMsg.obj = mTestsList;
+        mDoneMsg.sendToTarget();
+    }
+
+    /**
+     * Loads all the tests from the given folders and all the subfolders
+     * into mTestsList.
+     *
+     * @param dirRelativePath
+     */
+    private void preloadTests(String dirRelativePath) {
+        LinkedList<String> foldersList = new LinkedList<String>();
+        foldersList.add(dirRelativePath);
+
+        String relativePath;
+        String currentDirRelativePath;
+        String itemName;
+        File[] items;
+        while (!foldersList.isEmpty()) {
+            currentDirRelativePath = foldersList.removeFirst();
+            items = new File(TESTS_ROOT_DIR_PATH, currentDirRelativePath).listFiles();
+            for (File item : items) {
+                itemName = item.getName();
+                relativePath = currentDirRelativePath + File.separator + itemName;
+
+                if (item.isDirectory() && FileFilter.isTestDir(itemName)) {
+                    foldersList.add(relativePath);
+                    continue;
+                }
+
+                if (FileFilter.isTestFile(itemName)) {
+                    if (!mFileFilter.isSkip(relativePath)) {
+                        mTestsList.add(relativePath);
+                    } else {
+                        //mSummarizer.addSkippedTest(relativePath);
+                        /** TODO: Summarizer is now in service - figure out how to send the info */
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java
index 7bab4ae..33ee4c7 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java
@@ -61,7 +61,10 @@
         mExpectedResult = bundle.getString("expectedTextualResult");
         mActualResult = bundle.getString("actualTextualResult");
         mRelativePath = bundle.getString("relativePath");
-        mResultCode = ResultCode.valueOf(bundle.getString("resultCode"));
+        String resultCode = bundle.getString("resultCode");
+        if (resultCode != null) {
+            mResultCode = ResultCode.valueOf(resultCode);
+        }
     }
 
     @Override
@@ -177,4 +180,9 @@
         bundle.putString("type", getType().name());
         return bundle;
     }
+
+    @Override
+    public String getRelativePath() {
+        return mRelativePath;
+    }
 }
\ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
index 790d1d3..661a8ec 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java
@@ -17,7 +17,7 @@
 package com.android.dumprendertree2.ui;
 
 import com.android.dumprendertree2.FileFilter;
-import com.android.dumprendertree2.LayoutTestsRunner;
+import com.android.dumprendertree2.TestsListActivity;
 import com.android.dumprendertree2.R;
 
 import android.app.Activity;
@@ -203,9 +203,9 @@
                 } else {
                     /** Run the test */
                     Intent intent = new Intent();
-                    intent.setClass(DirListActivity.this, LayoutTestsRunner.class);
+                    intent.setClass(DirListActivity.this, TestsListActivity.class);
                     intent.setAction(Intent.ACTION_RUN);
-                    intent.putExtra(LayoutTestsRunner.EXTRA_TEST_PATH, item.getRelativePath());
+                    intent.putExtra(TestsListActivity.EXTRA_TEST_PATH, item.getRelativePath());
                     startActivity(intent);
                 }
             }
@@ -277,9 +277,9 @@
                         removeDialog(DIALOG_RUN_ABORT_DIR);
                         /** Run the tests */
                         Intent intent = new Intent();
-                        intent.setClass(DirListActivity.this, LayoutTestsRunner.class);
+                        intent.setClass(DirListActivity.this, TestsListActivity.class);
                         intent.setAction(Intent.ACTION_RUN);
-                        intent.putExtra(LayoutTestsRunner.EXTRA_TEST_PATH,
+                        intent.putExtra(TestsListActivity.EXTRA_TEST_PATH,
                                 args.getString("relativePath"));
                         startActivity(intent);
                     }