Add AsyncQueryHandler helper for queryEntities().

Recently we added queryEntities() to the ContentProvider
interface to read out Entity objects atomically.  This
change adds a helper to AsyncQueryHandler to perform these
queries on a background thread, returning the result when
finished.
diff --git a/api/current.xml b/api/current.xml
index 69d4d5c..b9fb85a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27892,6 +27892,23 @@
 <parameter name="cursor" type="android.database.Cursor">
 </parameter>
 </method>
+<method name="onQueryEntitiesComplete"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="token" type="int">
+</parameter>
+<parameter name="cookie" type="java.lang.Object">
+</parameter>
+<parameter name="iterator" type="android.content.EntityIterator">
+</parameter>
+</method>
 <method name="onUpdateComplete"
  return="void"
  abstract="false"
@@ -27974,6 +27991,29 @@
 <parameter name="orderBy" type="java.lang.String">
 </parameter>
 </method>
+<method name="startQueryEntities"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="int">
+</parameter>
+<parameter name="cookie" type="java.lang.Object">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="orderBy" type="java.lang.String">
+</parameter>
+</method>
 <method name="startUpdate"
  return="void"
  abstract="false"
diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index c5606ac..5e88de0 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -38,7 +38,8 @@
     private static final int EVENT_ARG_INSERT = 2;
     private static final int EVENT_ARG_UPDATE = 3;
     private static final int EVENT_ARG_DELETE = 4;
-    
+    private static final int EVENT_ARG_QUERY_ENTITIES = 5;
+
     /* package */ final WeakReference<ContentResolver> mResolver;
 
     private static Looper sLooper = null;
@@ -85,13 +86,25 @@
                             cursor.getCount();
                         }
                     } catch (Exception e) {
-                        Log.d(TAG, e.toString());
+                        Log.w(TAG, e.toString());
                         cursor = null;
                     }
 
                     args.result = cursor;
                     break;
 
+                case EVENT_ARG_QUERY_ENTITIES:
+                    EntityIterator iterator = null;
+                    try {
+                        iterator = resolver.queryEntities(args.uri, args.selection,
+                                args.selectionArgs, args.orderBy);
+                    } catch (Exception e) {
+                        Log.w(TAG, e.toString());
+                    }
+
+                    args.result = iterator;
+                    break;
+
                 case EVENT_ARG_INSERT:
                     args.result = resolver.insert(args.uri, args.values);
                     break;
@@ -104,7 +117,6 @@
                 case EVENT_ARG_DELETE:
                     args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
                     break;
-
             }
 
             // passing the original token value back to the caller
@@ -129,7 +141,7 @@
             if (sLooper == null) {
                 HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                 thread.start();
-                
+
                 sLooper = thread.getLooper();
             }
         }
@@ -183,6 +195,44 @@
     }
 
     /**
+     * This method begins an asynchronous query for an {@link EntityIterator}.
+     * When the query is done {@link #onQueryEntitiesComplete} is called.
+     *
+     * @param token A token passed into {@link #onQueryComplete} to identify the
+     *            query.
+     * @param cookie An object that gets passed into {@link #onQueryComplete}
+     * @param uri The URI, using the content:// scheme, for the content to
+     *            retrieve.
+     * @param selection A filter declaring which rows to return, formatted as an
+     *            SQL WHERE clause (excluding the WHERE itself). Passing null
+     *            will return all rows for the given URI.
+     * @param selectionArgs You may include ?s in selection, which will be
+     *            replaced by the values from selectionArgs, in the order that
+     *            they appear in the selection. The values will be bound as
+     *            Strings.
+     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
+     *            (excluding the ORDER BY itself). Passing null will use the
+     *            default sort order, which may be unordered.
+     */
+    public void startQueryEntities(int token, Object cookie, Uri uri, String selection,
+            String[] selectionArgs, String orderBy) {
+        // Use the token as what so cancelOperations works properly
+        Message msg = mWorkerThreadHandler.obtainMessage(token);
+        msg.arg1 = EVENT_ARG_QUERY_ENTITIES;
+
+        WorkerArgs args = new WorkerArgs();
+        args.handler = this;
+        args.uri = uri;
+        args.selection = selection;
+        args.selectionArgs = selectionArgs;
+        args.orderBy = orderBy;
+        args.cookie = cookie;
+        msg.obj = args;
+
+        mWorkerThreadHandler.sendMessage(msg);
+    }
+
+    /**
      * Attempts to cancel operation that has not already started. Note that
      * there is no guarantee that the operation will be canceled. They still may
      * result in a call to on[Query/Insert/Update/Delete]Complete after this
@@ -280,8 +330,8 @@
      * Called when an asynchronous query is completed.
      *
      * @param token the token to identify the query, passed in from
-     *        {@link #startQuery}.
-     * @param cookie the cookie object that's passed in from {@link #startQuery}.
+     *            {@link #startQuery}.
+     * @param cookie the cookie object passed in from {@link #startQuery}.
      * @param cursor The cursor holding the results from the query.
      */
     protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
@@ -289,6 +339,17 @@
     }
 
     /**
+     * Called when an asynchronous query is completed.
+     *
+     * @param token The token to identify the query.
+     * @param cookie The cookie object.
+     * @param iterator The iterator holding the query results.
+     */
+    protected void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+        // Empty
+    }
+
+    /**
      * Called when an asynchronous insert is completed.
      *
      * @param token the token to identify the query, passed in from
@@ -338,13 +399,17 @@
 
         int token = msg.what;
         int event = msg.arg1;
-        
+
         // pass token back to caller on each callback.
         switch (event) {
             case EVENT_ARG_QUERY:
                 onQueryComplete(token, args.cookie, (Cursor) args.result);
                 break;
 
+            case EVENT_ARG_QUERY_ENTITIES:
+                onQueryEntitiesComplete(token, args.cookie, (EntityIterator)args.result);
+                break;
+
             case EVENT_ARG_INSERT:
                 onInsertComplete(token, args.cookie, (Uri) args.result);
                 break;