Merge "Changed Summarizer to add header before printing the path in summary.txt and details.html"
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index a5a8a92..658fc58 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -37,7 +37,6 @@
 @SuppressWarnings("deprecation")
 public class SQLiteStatement extends SQLiteProgram
 {
-
     private static final String TAG = "SQLiteStatement";
 
     private static final boolean READ = true;
@@ -45,9 +44,9 @@
 
     private SQLiteDatabase mOrigDb;
     private int mState;
-    /** possible value for {@link #mState}. indicates that a transaction is started.} */
+    /** possible value for {@link #mState}. indicates that a transaction is started. */
     private static final int TRANS_STARTED = 1;
-    /** possible value for {@link #mState}. indicates that a lock is acquired.} */
+    /** possible value for {@link #mState}. indicates that a lock is acquired. */
     private static final int LOCK_ACQUIRED = 2;
 
     /**
@@ -81,8 +80,8 @@
      */
     public int executeUpdateDelete() {
         synchronized(this) {
-            long timeStart = acquireAndLock(WRITE);
             try {
+                long timeStart = acquireAndLock(WRITE);
                 int numChanges = native_execute();
                 mDatabase.logTimeStat(mSql, timeStart);
                 return numChanges;
@@ -103,8 +102,8 @@
      */
     public long executeInsert() {
         synchronized(this) {
-            long timeStart = acquireAndLock(WRITE);
             try {
+                long timeStart = acquireAndLock(WRITE);
                 long lastInsertedRowId = native_executeInsert();
                 mDatabase.logTimeStat(mSql, timeStart);
                 return lastInsertedRowId;
@@ -124,8 +123,8 @@
      */
     public long simpleQueryForLong() {
         synchronized(this) {
-            long timeStart = acquireAndLock(READ);
             try {
+                long timeStart = acquireAndLock(READ);
                 long retValue = native_1x1_long();
                 mDatabase.logTimeStat(mSql, timeStart);
                 return retValue;
@@ -145,8 +144,8 @@
      */
     public String simpleQueryForString() {
         synchronized(this) {
-            long timeStart = acquireAndLock(READ);
             try {
+                long timeStart = acquireAndLock(READ);
                 String retValue = native_1x1_string();
                 mDatabase.logTimeStat(mSql, timeStart);
                 return retValue;
@@ -166,8 +165,8 @@
      */
     public ParcelFileDescriptor simpleQueryForBlobFileDescriptor() {
         synchronized(this) {
-            long timeStart = acquireAndLock(READ);
             try {
+                long timeStart = acquireAndLock(READ);
                 ParcelFileDescriptor retValue = native_1x1_blob_ashmem();
                 mDatabase.logTimeStat(mSql, timeStart);
                 return retValue;
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9f2a49c..b2a0a46 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -110,15 +110,28 @@
 
     private final static String TAG = "MediaScanner";
 
-    private static final String[] PRESCAN_PROJECTION = new String[] {
+    private static final String[] FILES_PRESCAN_PROJECTION = new String[] {
             Files.FileColumns._ID, // 0
             Files.FileColumns.DATA, // 1
-            Files.FileColumns.DATE_MODIFIED, // 2
+            Files.FileColumns.FORMAT, // 2
+            Files.FileColumns.DATE_MODIFIED, // 3
     };
 
-    private static final int PRESCAN_ID_COLUMN_INDEX = 0;
-    private static final int PRESCAN_PATH_COLUMN_INDEX = 1;
-    private static final int PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 2;
+    private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0;
+    private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1;
+    private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2;
+    private static final int FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 3;
+
+    private static final String[] MEDIA_PRESCAN_PROJECTION = new String[] {
+            MediaStore.MediaColumns._ID, // 0
+            MediaStore.MediaColumns.DATA, // 1
+            MediaStore.MediaColumns.DATE_MODIFIED, // 2
+    };
+
+    private static final int MEDIA_PRESCAN_ID_COLUMN_INDEX = 0;
+    private static final int MEDIA_PRESCAN_PATH_COLUMN_INDEX = 1;
+    private static final int MEDIA_PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 2;
+
 
     private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] {
             Audio.Playlists.Members.PLAYLIST_ID, // 0
@@ -316,14 +329,16 @@
         long mRowId;
         String mPath;
         long mLastModified;
+        int mFormat;
         boolean mSeenInFileSystem;
         boolean mLastModifiedChanged;
 
-        FileCacheEntry(Uri tableUri, long rowId, String path, long lastModified) {
+        FileCacheEntry(Uri tableUri, long rowId, String path, long lastModified, int format) {
             mTableUri = tableUri;
             mRowId = rowId;
             mPath = path;
             mLastModified = lastModified;
+            mFormat = format;
             mSeenInFileSystem = false;
             mLastModifiedChanged = false;
         }
@@ -444,7 +459,7 @@
                 } else {
                     tableUri = mFilesUri;
                 }
-                entry = new FileCacheEntry(tableUri, 0, path, 0);
+                entry = new FileCacheEntry(tableUri, 0, path, 0, 0);
                 mFileCache.put(key, entry);
             }
             entry.mSeenInFileSystem = true;
@@ -884,13 +899,15 @@
             if (prescanFiles) {
                 // First read existing files from the files table
 
-                c = mMediaProvider.query(mFilesUri, PRESCAN_PROJECTION, where, selectionArgs, null);
+                c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
+                        where, selectionArgs, null);
 
                 if (c != null) {
                     while (c.moveToNext()) {
-                        long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
-                        String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
-                        long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+                        long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
+                        String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
+                        int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
+                        long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
 
                         // Only consider entries with absolute path names.
                         // This allows storing URIs in the database without the
@@ -902,7 +919,7 @@
                             }
 
                             FileCacheEntry entry = new FileCacheEntry(mFilesUri, rowId, path,
-                                    lastModified);
+                                    lastModified, format);
                             mFileCache.put(key, entry);
                         }
                     }
@@ -912,12 +929,13 @@
             }
 
             // Read existing files from the audio table and update FileCacheEntry
-            c = mMediaProvider.query(mAudioUri, PRESCAN_PROJECTION, where, selectionArgs, null);
+            c = mMediaProvider.query(mAudioUri, MEDIA_PRESCAN_PROJECTION,
+                    where, selectionArgs, null);
             if (c != null) {
                 while (c.moveToNext()) {
-                    long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
-                    String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
-                    long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+                    long rowId = c.getLong(MEDIA_PRESCAN_ID_COLUMN_INDEX);
+                    String path = c.getString(MEDIA_PRESCAN_PATH_COLUMN_INDEX);
+                    long lastModified = c.getLong(MEDIA_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
 
                     // Only consider entries with absolute path names.
                     // This allows storing URIs in the database without the
@@ -930,7 +948,7 @@
                         FileCacheEntry entry = mFileCache.get(path);
                         if (entry == null) {
                             mFileCache.put(key, new FileCacheEntry(mAudioUri, rowId, path,
-                                    lastModified));
+                                    lastModified, 0));
                         } else {
                             // update the entry
                             entry.mTableUri = mAudioUri;
@@ -943,12 +961,13 @@
             }
 
             // Read existing files from the video table and update FileCacheEntry
-            c = mMediaProvider.query(mVideoUri, PRESCAN_PROJECTION, where, selectionArgs, null);
+            c = mMediaProvider.query(mVideoUri, MEDIA_PRESCAN_PROJECTION,
+                    where, selectionArgs, null);
             if (c != null) {
                 while (c.moveToNext()) {
-                    long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
-                    String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
-                    long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+                    long rowId = c.getLong(MEDIA_PRESCAN_ID_COLUMN_INDEX);
+                    String path = c.getString(MEDIA_PRESCAN_PATH_COLUMN_INDEX);
+                    long lastModified = c.getLong(MEDIA_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
 
                     // Only consider entries with absolute path names.
                     // This allows storing URIs in the database without the
@@ -961,7 +980,7 @@
                         FileCacheEntry entry = mFileCache.get(path);
                         if (entry == null) {
                             mFileCache.put(key, new FileCacheEntry(mVideoUri, rowId, path,
-                                    lastModified));
+                                    lastModified, 0));
                         } else {
                             // update the entry
                             entry.mTableUri = mVideoUri;
@@ -974,12 +993,13 @@
             }
 
             // Read existing files from the video table and update FileCacheEntry
-            c = mMediaProvider.query(mImagesUri, PRESCAN_PROJECTION, where, selectionArgs, null);
+            c = mMediaProvider.query(mImagesUri, MEDIA_PRESCAN_PROJECTION,
+                    where, selectionArgs, null);
             if (c != null) {
                 while (c.moveToNext()) {
-                    long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
-                    String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
-                    long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+                    long rowId = c.getLong(MEDIA_PRESCAN_ID_COLUMN_INDEX);
+                    String path = c.getString(MEDIA_PRESCAN_PATH_COLUMN_INDEX);
+                    long lastModified = c.getLong(MEDIA_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
 
                     // Only consider entries with absolute path names.
                     // This allows storing URIs in the database without the
@@ -992,7 +1012,7 @@
                         FileCacheEntry entry = mFileCache.get(path);
                         if (entry == null) {
                             mFileCache.put(key, new FileCacheEntry(mImagesUri, rowId, path,
-                                    lastModified));
+                                    lastModified, 0));
                         } else {
                             // update the entry
                             entry.mTableUri = mImagesUri;
@@ -1006,13 +1026,13 @@
 
             if (mProcessPlaylists) {
                 // Read existing files from the playlists table and update FileCacheEntry
-                c = mMediaProvider.query(mPlaylistsUri, PRESCAN_PROJECTION, where,
-                                            selectionArgs, null);
+                c = mMediaProvider.query(mPlaylistsUri, MEDIA_PRESCAN_PROJECTION,
+                        where, selectionArgs, null);
                 if (c != null) {
                     while (c.moveToNext()) {
-                        long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
-                        String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
-                        long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+                        long rowId = c.getLong(MEDIA_PRESCAN_ID_COLUMN_INDEX);
+                        String path = c.getString(MEDIA_PRESCAN_PATH_COLUMN_INDEX);
+                        long lastModified = c.getLong(MEDIA_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
 
                         // Only consider entries with absolute path names.
                         // This allows storing URIs in the database without the
@@ -1025,7 +1045,7 @@
                             FileCacheEntry entry = mFileCache.get(path);
                             if (entry == null) {
                                 mFileCache.put(key, new FileCacheEntry(mPlaylistsUri, rowId, path,
-                                        lastModified));
+                                        lastModified, 0));
                             } else {
                                 // update the entry
                                 entry.mTableUri = mPlaylistsUri;
@@ -1109,12 +1129,14 @@
             // remove database entries for files that no longer exist.
             boolean fileMissing = false;
 
-            if (!entry.mSeenInFileSystem) {
-                if (inScanDirectory(path, directories)) {
+            if (!entry.mSeenInFileSystem && !MtpConstants.isAbstractObject(entry.mFormat)) {
+                if (entry.mFormat != MtpConstants.FORMAT_ASSOCIATION &&
+                        inScanDirectory(path, directories)) {
                     // we didn't see this file in the scan directory.
                     fileMissing = true;
                 } else {
-                    // the file is outside of our scan directory,
+                    // the file actually a directory or other abstract object
+                    // or is outside of our scan directory,
                     // so we need to check for file existence here.
                     File testFile = new File(path);
                     if (!testFile.exists()) {
@@ -1134,9 +1156,11 @@
                     ContentValues values = new ContentValues();
                     values.put(MediaStore.Audio.Playlists.DATA, "");
                     values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, 0);
-                    mMediaProvider.update(ContentUris.withAppendedId(mPlaylistsUri, entry.mRowId), values, null, null);
+                    mMediaProvider.update(ContentUris.withAppendedId(mPlaylistsUri, entry.mRowId),
+                            values, null, null);
                 } else {
-                    mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId), null, null);
+                    mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId),
+                            null, null);
                     iterator.remove();
                 }
             }
diff --git a/media/java/android/media/MtpConstants.java b/media/java/android/media/MtpConstants.java
index 153f64f..a7d33ce 100644
--- a/media/java/android/media/MtpConstants.java
+++ b/media/java/android/media/MtpConstants.java
@@ -138,6 +138,28 @@
     public static final int FORMAT_ABSTRACT_CONTACT = 0xBB81;
     public static final int FORMAT_VCARD_2 = 0xBB82;
 
+    public static boolean isAbstractObject(int format) {
+        switch (format) {
+            case FORMAT_ABSTRACT_MULTIMEDIA_ALBUM:
+            case FORMAT_ABSTRACT_IMAGE_ALBUM:
+            case FORMAT_ABSTRACT_AUDIO_ALBUM:
+            case FORMAT_ABSTRACT_VIDEO_ALBUM:
+            case FORMAT_ABSTRACT_AV_PLAYLIST:
+            case FORMAT_ABSTRACT_CONTACT_GROUP:
+            case FORMAT_ABSTRACT_MESSAGE_FOLDER:
+            case FORMAT_ABSTRACT_CHAPTERED_PRODUCTION:
+            case FORMAT_ABSTRACT_AUDIO_PLAYLIST:
+            case FORMAT_ABSTRACT_VIDEO_PLAYLIST:
+            case FORMAT_ABSTRACT_MEDIACAST:
+            case FORMAT_ABSTRACT_DOCUMENT:
+            case FORMAT_ABSTRACT_MESSSAGE:
+            case FORMAT_ABSTRACT_CONTACT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     // MTP object properties
     public static final int PROPERTY_STORAGE_ID = 0xDC01;
     public static final int PROPERTY_OBJECT_FORMAT = 0xDC02;
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 6b0b761..b64299a 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -478,12 +478,26 @@
         }
     }
 
+    private int deleteRecursive(int handle) throws RemoteException {
+        int[] children = getObjectList(0 /* storageID */, 0 /* format */, handle);
+        Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
+        // delete parent first, to avoid potential infinite recursion
+        int count = mMediaProvider.delete(uri, null, null);
+        if (count == 1) {
+            if (children != null) {
+                for (int i = 0; i < children.length; i++) {
+                    count += deleteRecursive(children[i]);
+                }
+            }
+        }
+        return count;
+    }
+
     private int deleteFile(int handle) {
         Log.d(TAG, "deleteFile: " + handle);
         mDatabaseModified = true;
-        Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
         try {
-            if (mMediaProvider.delete(uri, null, null) == 1) {
+            if (deleteRecursive(handle) > 0) {
                 return MtpConstants.RESPONSE_OK;
             } else {
                 return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 3d3bd62..6332b4e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -21,6 +21,8 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <sys/stat.h>
+#include <dirent.h>
 
 #include <cutils/properties.h>
 
@@ -686,21 +688,77 @@
     return result;
 }
 
+static void deleteRecursive(const char* path) {
+    char pathbuf[PATH_MAX];
+    int pathLength = strlen(path);
+    if (pathLength >= sizeof(pathbuf) - 1) {
+        LOGE("path too long: %s\n", path);
+    }
+    strcpy(pathbuf, path);
+    if (pathbuf[pathLength - 1] != '/') {
+        pathbuf[pathLength++] = '/';
+    }
+    char* fileSpot = pathbuf + pathLength;
+    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
+
+    DIR* dir = opendir(path);
+    if (!dir) {
+        LOGE("opendir %s failed: %s", path, strerror(errno));
+        return;
+    }
+
+    struct dirent* entry;
+    while ((entry = readdir(dir))) {
+        const char* name = entry->d_name;
+
+        // ignore "." and ".."
+        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+            continue;
+        }
+
+        int nameLength = strlen(name);
+        if (nameLength > pathRemaining) {
+            LOGE("path %s/%s too long\n", path, name);
+            continue;
+        }
+        strcpy(fileSpot, name);
+
+        int type = entry->d_type;
+        if (entry->d_type == DT_DIR) {
+            deleteRecursive(pathbuf);
+            rmdir(pathbuf);
+        } else {
+            unlink(pathbuf);
+        }
+    }
+}
+
+static void deletePath(const char* path) {
+    struct stat statbuf;
+    if (stat(path, &statbuf) == 0) {
+        if (S_ISDIR(statbuf.st_mode)) {
+            deleteRecursive(path);
+            rmdir(path);
+        } else {
+            unlink(path);
+        }
+    } else {
+        LOGE("deletePath stat failed for %s: %s", path, strerror(errno));
+    }
+}
+
 MtpResponseCode MtpServer::doDeleteObject() {
     MtpObjectHandle handle = mRequest.getParameter(1);
-    MtpObjectFormat format = mRequest.getParameter(1);
+    MtpObjectFormat format = mRequest.getParameter(2);
     // FIXME - support deleting all objects if handle is 0xFFFFFFFF
     // FIXME - implement deleting objects by format
-    // FIXME - handle non-empty directories
 
     MtpString filePath;
     int64_t fileLength;
     int result = mDatabase->getObjectFilePath(handle, filePath, fileLength);
     if (result == MTP_RESPONSE_OK) {
         LOGV("deleting %s", (const char *)filePath);
-        // one of these should work
-        rmdir((const char *)filePath);
-        unlink((const char *)filePath);
+        deletePath((const char *)filePath);
         return mDatabase->deleteFile(handle);
     } else {
         return result;
diff --git a/tests/DumpRenderTree2/assets/run_layout_tests.py b/tests/DumpRenderTree2/assets/run_layout_tests.py
index c584d596..d5bf8b3 100755
--- a/tests/DumpRenderTree2/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree2/assets/run_layout_tests.py
@@ -32,6 +32,10 @@
 
   tmpdir = tempfile.gettempdir()
 
+  # Restart the server
+  cmd = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), "run_apache2.py") + " restart"
+  os.system(cmd);
+
   # Run the tests in path
   cmd = "adb shell am instrument "
   cmd += "-e class com.android.dumprendertree2.scriptsupport.Starter#startLayoutTests "
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java
index a82037e..ec8409a 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestController.java
@@ -35,12 +35,9 @@
         mLayoutTestsExecutor = layoutTestsExecutor;
     }
 
-    public void waitUntilDone() {
-        mLayoutTestsExecutor.waitUntilDone();
-    }
-
-    public void notifyDone() {
-        mLayoutTestsExecutor.notifyDone();
+    public void clearAllDatabases() {
+        Log.i(LOG_TAG, "clearAllDatabases() called");
+        WebStorage.getInstance().deleteAllData();
     }
 
     public void dumpAsText() {
@@ -55,19 +52,27 @@
         mLayoutTestsExecutor.dumpChildFramesAsText();
     }
 
-    public void clearAllDatabases() {
-        Log.i(LOG_TAG, "clearAllDatabases() called");
-        WebStorage.getInstance().deleteAllData();
+    public void dumpDatabaseCallbacks() {
+        mLayoutTestsExecutor.dumpDatabaseCallbacks();
+    }
+
+    public void notifyDone() {
+        mLayoutTestsExecutor.notifyDone();
+    }
+
+    public void overridePreference(String key, boolean value) {
+        mLayoutTestsExecutor.overridePreference(key, value);
+    }
+
+    public void setAppCacheMaximumSize(long size) {
+        Log.i(LOG_TAG, "setAppCacheMaximumSize() called with: " + size);
+        WebStorage.getInstance().setAppCacheMaximumSize(size);
     }
 
     public void setCanOpenWindows() {
         mLayoutTestsExecutor.setCanOpenWindows();
     }
 
-    public void dumpDatabaseCallbacks() {
-        mLayoutTestsExecutor.dumpDatabaseCallbacks();
-    }
-
     public void setDatabaseQuota(long quota) {
         /** TODO: Reset this before every test! */
         Log.i(LOG_TAG, "setDatabaseQuota() called with: " + quota);
@@ -79,21 +84,6 @@
         mLayoutTestsExecutor.setGeolocationPermission(allow);
     }
 
-    public void overridePreference(String key, boolean value) {
-        mLayoutTestsExecutor.overridePreference(key, value);
-    }
-
-    public void setMockGeolocationPosition(double latitude, double longitude, double accuracy) {
-        Log.i(LOG_TAG, "setMockGeolocationPosition(): " + "latitude=" + latitude +
-                " longitude=" + longitude + " accuracy=" + accuracy);
-        MockGeolocation.getInstance().setPosition(latitude, longitude, accuracy);
-    }
-
-    public void setMockGeolocationError(int code, String message) {
-        Log.i(LOG_TAG, "setMockGeolocationError(): " + "code=" + code + " message=" + message);
-        MockGeolocation.getInstance().setError(code, message);
-    }
-
     public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
             boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
         // Configuration is in WebKit, so stay on WebCore thread, but go via LayoutTestsExecutor
@@ -104,4 +94,19 @@
         mLayoutTestsExecutor.setMockDeviceOrientation(
                 canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
     }
-}
\ No newline at end of file
+
+    public void setMockGeolocationError(int code, String message) {
+        Log.i(LOG_TAG, "setMockGeolocationError(): " + "code=" + code + " message=" + message);
+        MockGeolocation.getInstance().setError(code, message);
+    }
+
+    public void setMockGeolocationPosition(double latitude, double longitude, double accuracy) {
+        Log.i(LOG_TAG, "setMockGeolocationPosition(): " + "latitude=" + latitude +
+                " longitude=" + longitude + " accuracy=" + accuracy);
+        MockGeolocation.getInstance().setPosition(latitude, longitude, accuracy);
+    }
+
+    public void waitUntilDone() {
+        mLayoutTestsExecutor.waitUntilDone();
+    }
+}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
index c997911..4c7124b 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
@@ -519,24 +519,12 @@
             assert mCurrentState.isRunningState() : "mCurrentState = " + mCurrentState.name();
 
             switch (msg.what) {
-                case MSG_WAIT_UNTIL_DONE:
-                    mCurrentState = CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST;
-                    break;
-
-                case MSG_NOTIFY_DONE:
-                    if (mCurrentState == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST) {
-                        onTestFinished();
-                    }
-                    break;
-
                 case MSG_DUMP_AS_TEXT:
                     if (mCurrentResult == null) {
                         mCurrentResult = new TextResult(mCurrentTestRelativePath);
                     }
-
                     assert mCurrentResult instanceof TextResult
                             : "mCurrentResult instanceof" + mCurrentResult.getClass().getName();
-
                     break;
 
                 case MSG_DUMP_CHILD_FRAMES_AS_TEXT:
@@ -551,27 +539,13 @@
                     ((TextResult)mCurrentResult).setDumpChildFramesAsText(true);
                     break;
 
-                case MSG_SET_CAN_OPEN_WINDOWS:
-                    mCanOpenWindows = true;
-                    break;
-
                 case MSG_DUMP_DATABASE_CALLBACKS:
                     mDumpDatabaseCallbacks = true;
                     break;
 
-                case MSG_SET_GEOLOCATION_PERMISSION:
-                    mIsGeolocationPermissionSet = true;
-                    mGeolocationPermission = msg.arg1 == 1;
-
-                    if (mPendingGeolocationPermissionCallbacks != null) {
-                        Iterator<GeolocationPermissions.Callback> iter =
-                                mPendingGeolocationPermissionCallbacks.keySet().iterator();
-                        while (iter.hasNext()) {
-                            GeolocationPermissions.Callback callback = iter.next();
-                            String origin = mPendingGeolocationPermissionCallbacks.get(callback);
-                            callback.invoke(origin, mGeolocationPermission, false);
-                        }
-                        mPendingGeolocationPermissionCallbacks = null;
+                case MSG_NOTIFY_DONE:
+                    if (mCurrentState == CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST) {
+                        onTestFinished();
                     }
                     break;
 
@@ -591,6 +565,30 @@
                     }
                     break;
 
+                case MSG_SET_CAN_OPEN_WINDOWS:
+                    mCanOpenWindows = true;
+                    break;
+
+                case MSG_SET_GEOLOCATION_PERMISSION:
+                    mIsGeolocationPermissionSet = true;
+                    mGeolocationPermission = msg.arg1 == 1;
+
+                    if (mPendingGeolocationPermissionCallbacks != null) {
+                        Iterator<GeolocationPermissions.Callback> iter =
+                                mPendingGeolocationPermissionCallbacks.keySet().iterator();
+                        while (iter.hasNext()) {
+                            GeolocationPermissions.Callback callback = iter.next();
+                            String origin = mPendingGeolocationPermissionCallbacks.get(callback);
+                            callback.invoke(origin, mGeolocationPermission, false);
+                        }
+                        mPendingGeolocationPermissionCallbacks = null;
+                    }
+                    break;
+
+                case MSG_WAIT_UNTIL_DONE:
+                    mCurrentState = CurrentState.WAITING_FOR_ASYNCHRONOUS_TEST;
+                    break;
+
                 default:
                     assert false : "msg.what=" + msg.what;
                     break;
@@ -605,16 +603,6 @@
         mPendingGeolocationPermissionCallbacks = null;
     }
 
-    public void waitUntilDone() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE);
-    }
-
-    public void notifyDone() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": notifyDone() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_NOTIFY_DONE);
-    }
-
     public void dumpAsText(boolean enablePixelTest) {
         Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpAsText(" + enablePixelTest + ") called");
         /** TODO: Implement */
@@ -629,22 +617,14 @@
         mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_CHILD_FRAMES_AS_TEXT);
     }
 
-    public void setCanOpenWindows() {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setCanOpenWindows() called");
-        mLayoutTestControllerHandler.sendEmptyMessage(MSG_SET_CAN_OPEN_WINDOWS);
-    }
-
     public void dumpDatabaseCallbacks() {
         Log.i(LOG_TAG, mCurrentTestRelativePath + ": dumpDatabaseCallbacks() called");
         mLayoutTestControllerHandler.sendEmptyMessage(MSG_DUMP_DATABASE_CALLBACKS);
     }
 
-    public void setGeolocationPermission(boolean allow) {
-        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setGeolocationPermission(" + allow +
-                ") called");
-        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_GEOLOCATION_PERMISSION);
-        msg.arg1 = allow ? 1 : 0;
-        msg.sendToTarget();
+    public void notifyDone() {
+        Log.i(LOG_TAG, mCurrentTestRelativePath + ": notifyDone() called");
+        mLayoutTestControllerHandler.sendEmptyMessage(MSG_NOTIFY_DONE);
     }
 
     public void overridePreference(String key, boolean value) {
@@ -656,6 +636,19 @@
         msg.sendToTarget();
     }
 
+    public void setCanOpenWindows() {
+        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setCanOpenWindows() called");
+        mLayoutTestControllerHandler.sendEmptyMessage(MSG_SET_CAN_OPEN_WINDOWS);
+    }
+
+    public void setGeolocationPermission(boolean allow) {
+        Log.i(LOG_TAG, mCurrentTestRelativePath + ": setGeolocationPermission(" + allow +
+                ") called");
+        Message msg = mLayoutTestControllerHandler.obtainMessage(MSG_SET_GEOLOCATION_PERMISSION);
+        msg.arg1 = allow ? 1 : 0;
+        msg.sendToTarget();
+    }
+
     public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
             boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
         Log.i(LOG_TAG, mCurrentTestRelativePath + ": setMockDeviceOrientation(" + canProvideAlpha +
@@ -664,4 +657,9 @@
         mCurrentWebView.setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta,
                 canProvideGamma, gamma);
     }
+
+    public void waitUntilDone() {
+        Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called");
+        mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE);
+    }
 }