Merge "Moved practically all of the prerefactoring functionality to the new design."
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);
                     }