Merge "Adding getter functions for script side RS objects. Multiproject change involving on device linker"
diff --git a/api/current.txt b/api/current.txt
index 662ebcd..ffa46ec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6782,6 +6782,13 @@
     method public abstract boolean onMove(int, int);
   }
 
+  public class CrossProcessCursorWrapper extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
+    ctor public CrossProcessCursorWrapper(android.database.Cursor);
+    method public void fillWindow(int, android.database.CursorWindow);
+    method public android.database.CursorWindow getWindow();
+    method public boolean onMove(int, int);
+  }
+
   public abstract interface Cursor {
     method public abstract void close();
     method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -6851,7 +6858,8 @@
   }
 
   public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
-    ctor public CursorWindow(boolean);
+    ctor public CursorWindow(java.lang.String);
+    ctor public deprecated CursorWindow(boolean);
     method public boolean allocRow();
     method public void clear();
     method public void close();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e923349..cc3219b 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -26,6 +26,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.database.CrossProcessCursorWrapper;
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.database.IContentObserver;
@@ -1568,7 +1569,7 @@
             samplePercent);
     }
 
-    private final class CursorWrapperInner extends CursorWrapper {
+    private final class CursorWrapperInner extends CrossProcessCursorWrapper {
         private final IContentProvider mContentProvider;
         public static final String TAG="CursorWrapperInner";
 
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index ee6aec6..74fef29 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -53,7 +53,10 @@
     abstract public boolean isNull(int column);
 
     public int getType(int column) {
-        throw new UnsupportedOperationException();
+        // Reflects the assumption that all commonly used field types (meaning everything
+        // but blobs) are convertible to strings so it should be safe to call
+        // getString to retrieve them.
+        return FIELD_TYPE_STRING;
     }
 
     // TODO implement getBlob in all cursor types
@@ -185,46 +188,9 @@
         return result;
     }
 
-    /**
-     * Copy data from cursor to CursorWindow
-     * @param position start position of data
-     * @param window
-     */
+    @Override
     public void fillWindow(int position, CursorWindow window) {
-        if (position < 0 || position >= getCount()) {
-            return;
-        }
-        window.acquireReference();
-        try {
-            int oldpos = mPos;
-            mPos = position - 1;
-            window.clear();
-            window.setStartPosition(position);
-            int columnNum = getColumnCount();
-            window.setNumColumns(columnNum);
-            while (moveToNext() && window.allocRow()) {
-                for (int i = 0; i < columnNum; i++) {
-                    String field = getString(i);
-                    if (field != null) {
-                        if (!window.putString(field, mPos, i)) {
-                            window.freeLastRow();
-                            break;
-                        }
-                    } else {
-                        if (!window.putNull(mPos, i)) {
-                            window.freeLastRow();
-                            break;
-                        }
-                    }
-                }
-            }
-
-            mPos = oldpos;
-        } catch (IllegalStateException e){
-            // simply ignore it
-        } finally {
-            window.releaseReference();
-        }
+        DatabaseUtils.cursorFillWindow(this, position, window);
     }
 
     public final boolean move(int offset) {
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index d0aedd2..083485f 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -188,15 +188,14 @@
 
     /**
      * If there is a window, clear it.
-     * Otherwise, creates a local window.
+     * Otherwise, creates a new window.
      *
      * @param name The window name.
      * @hide
      */
-    protected void clearOrCreateLocalWindow(String name) {
+    protected void clearOrCreateWindow(String name) {
         if (mWindow == null) {
-            // If there isn't a window set already it will only be accessed locally
-            mWindow = new CursorWindow(name, true /* the window is local only */);
+            mWindow = new CursorWindow(name);
         } else {
             mWindow.clear();
         }
diff --git a/core/java/android/database/CrossProcessCursor.java b/core/java/android/database/CrossProcessCursor.java
index 8e6a5aa..26379cc 100644
--- a/core/java/android/database/CrossProcessCursor.java
+++ b/core/java/android/database/CrossProcessCursor.java
@@ -16,27 +16,63 @@
 
 package android.database;
 
+/**
+ * A cross process cursor is an extension of a {@link Cursor} that also supports
+ * usage from remote processes.
+ * <p>
+ * The contents of a cross process cursor are marshalled to the remote process by
+ * filling {@link CursorWindow} objects using {@link #fillWindow}.  As an optimization,
+ * the cursor can provide a pre-filled window to use via {@link #getWindow} thereby
+ * obviating the need to copy the data to yet another cursor window.
+ */
 public interface CrossProcessCursor extends Cursor {
     /**
-     * returns a pre-filled window, return NULL if no such window
+     * Returns a pre-filled window that contains the data within this cursor.
+     * <p>
+     * In particular, the window contains the row indicated by {@link Cursor#getPosition}.
+     * The window's contents are automatically scrolled whenever the current
+     * row moved outside the range covered by the window.
+     * </p>
+     *
+     * @return The pre-filled window, or null if none.
      */
     CursorWindow getWindow();
 
     /**
-     * copies cursor data into the window start at pos
+     * Copies cursor data into the window.
+     * <p>
+     * Clears the window and fills it with data beginning at the requested
+     * row position until all of the data in the cursor is exhausted
+     * or the window runs out of space.
+     * </p><p>
+     * The filled window uses the same row indices as the original cursor.
+     * For example, if you fill a window starting from row 5 from the cursor,
+     * you can query the contents of row 5 from the window just by asking it
+     * for row 5 because there is a direct correspondence between the row indices
+     * used by the cursor and the window.
+     * </p><p>
+     * The current position of the cursor, as returned by {@link #getPosition},
+     * is not changed by this method.
+     * </p>
+     *
+     * @param position The zero-based index of the first row to copy into the window.
+     * @param window The window to fill.
      */
-    void fillWindow(int pos, CursorWindow winow);
+    void fillWindow(int position, CursorWindow window);
 
     /**
      * This function is called every time the cursor is successfully scrolled
      * to a new position, giving the subclass a chance to update any state it
-     * may have. If it returns false the move function will also do so and the
+     * may have.  If it returns false the move function will also do so and the
      * cursor will scroll to the beforeFirst position.
+     * <p>
+     * This function should be called by methods such as {@link #moveToPosition(int)},
+     * so it will typically not be called from outside of the cursor class itself.
+     * </p>
      *
-     * @param oldPosition the position that we're moving from
-     * @param newPosition the position that we're moving to
-     * @return true if the move is successful, false otherwise
+     * @param oldPosition The position that we're moving from.
+     * @param newPosition The position that we're moving to.
+     * @return True if the move is successful, false otherwise.
      */
     boolean onMove(int oldPosition, int newPosition); 
-    
 }
diff --git a/core/java/android/database/CrossProcessCursorWrapper.java b/core/java/android/database/CrossProcessCursorWrapper.java
new file mode 100644
index 0000000..8c250b8
--- /dev/null
+++ b/core/java/android/database/CrossProcessCursorWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 android.database;
+
+import android.database.CrossProcessCursor;
+import android.database.Cursor;
+import android.database.CursorWindow;
+import android.database.CursorWrapper;
+
+/**
+ * Cursor wrapper that implements {@link CrossProcessCursor}.
+ * <p>
+ * If the wrapper cursor implemented {@link CrossProcessCursor}, then delegates
+ * {@link #fillWindow}, {@link #getWindow()} and {@link #onMove} to it.  Otherwise,
+ * provides default implementations of these methods that traverse the contents
+ * of the cursor similar to {@link AbstractCursor#fillWindow}.
+ * </p><p>
+ * This wrapper can be used to adapt an ordinary {@link Cursor} into a
+ * {@link CrossProcessCursor}.
+ * </p>
+ */
+public class CrossProcessCursorWrapper extends CursorWrapper implements CrossProcessCursor {
+    /**
+     * Creates a cross process cursor wrapper.
+     * @param cursor The underlying cursor to wrap.
+     */
+    public CrossProcessCursorWrapper(Cursor cursor) {
+        super(cursor);
+    }
+
+    @Override
+    public void fillWindow(int position, CursorWindow window) {
+        if (mCursor instanceof CrossProcessCursor) {
+            final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+            crossProcessCursor.fillWindow(position, window);
+            return;
+        }
+
+        DatabaseUtils.cursorFillWindow(mCursor, position, window);
+    }
+
+    @Override
+    public CursorWindow getWindow() {
+        if (mCursor instanceof CrossProcessCursor) {
+            final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+            return crossProcessCursor.getWindow();
+        }
+
+        return null;
+    }
+
+    @Override
+    public boolean onMove(int oldPosition, int newPosition) {
+        if (mCursor instanceof CrossProcessCursor) {
+            final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+            return crossProcessCursor.onMove(oldPosition, newPosition);
+        }
+
+        return true;
+    }
+}
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index dd2c9b7c..215035d 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -25,9 +25,9 @@
 /**
  * Wraps a BulkCursor around an existing Cursor making it remotable.
  * <p>
- * If the wrapped cursor is a {@link AbstractWindowedCursor} then it owns
- * the cursor window.  Otherwise, the adaptor takes ownership of the
- * cursor itself and ensures it gets closed as needed during deactivation
+ * If the wrapped cursor returns non-null from {@link CrossProcessCursor#getWindow}
+ * then it is assumed to own the window.  Otherwise, the adaptor provides a
+ * window to be filled and ensures it gets closed as needed during deactivation
  * and requeries.
  * </p>
  *
@@ -48,12 +48,11 @@
     private CrossProcessCursor mCursor;
 
     /**
-     * The cursor window used by the cross process cursor.
-     * This field is always null for abstract windowed cursors since they are responsible
-     * for managing the lifetime of their window.
+     * The cursor window that was filled by the cross process cursor in the
+     * case where the cursor does not support getWindow.
+     * This field is only ever non-null when the window has actually be filled.
      */
-    private CursorWindow mWindowForNonWindowedCursor;
-    private boolean mWindowForNonWindowedCursorWasFilled;
+    private CursorWindow mFilledWindow;
 
     private static final class ContentObserverProxy extends ContentObserver {
         protected IContentObserver mRemote;
@@ -90,11 +89,10 @@
 
     public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer,
             String providerName) {
-        try {
-            mCursor = (CrossProcessCursor) cursor;
-        } catch (ClassCastException e) {
-            throw new UnsupportedOperationException(
-                    "Only CrossProcessCursor cursors are supported across process for now", e);
+        if (cursor instanceof CrossProcessCursor) {
+            mCursor = (CrossProcessCursor)cursor;
+        } else {
+            mCursor = new CrossProcessCursorWrapper(cursor);
         }
         mProviderName = providerName;
 
@@ -103,11 +101,10 @@
         }
     }
 
-    private void closeWindowForNonWindowedCursorLocked() {
-        if (mWindowForNonWindowedCursor != null) {
-            mWindowForNonWindowedCursor.close();
-            mWindowForNonWindowedCursor = null;
-            mWindowForNonWindowedCursorWasFilled = false;
+    private void closeFilledWindowLocked() {
+        if (mFilledWindow != null) {
+            mFilledWindow.close();
+            mFilledWindow = null;
         }
     }
 
@@ -118,7 +115,7 @@
             mCursor = null;
         }
 
-        closeWindowForNonWindowedCursorLocked();
+        closeFilledWindowLocked();
     }
 
     private void throwIfCursorIsClosed() {
@@ -139,30 +136,24 @@
         synchronized (mLock) {
             throwIfCursorIsClosed();
 
-            CursorWindow window;
-            if (mCursor instanceof AbstractWindowedCursor) {
-                AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor)mCursor;
-                window = windowedCursor.getWindow();
-                if (window == null) {
-                    window = new CursorWindow(mProviderName, false /*localOnly*/);
-                    windowedCursor.setWindow(window);
-                }
+            if (!mCursor.moveToPosition(startPos)) {
+                closeFilledWindowLocked();
+                return null;
+            }
 
-                mCursor.moveToPosition(startPos);
+            CursorWindow window = mCursor.getWindow();
+            if (window != null) {
+                closeFilledWindowLocked();
             } else {
-                window = mWindowForNonWindowedCursor;
+                window = mFilledWindow;
                 if (window == null) {
-                    window = new CursorWindow(mProviderName, false /*localOnly*/);
-                    mWindowForNonWindowedCursor = window;
-                }
-
-                mCursor.moveToPosition(startPos);
-
-                if (!mWindowForNonWindowedCursorWasFilled
-                        || startPos < window.getStartPosition()
-                        || startPos >= window.getStartPosition() + window.getNumRows()) {
+                    mFilledWindow = new CursorWindow(mProviderName);
+                    window = mFilledWindow;
                     mCursor.fillWindow(startPos, window);
-                    mWindowForNonWindowedCursorWasFilled = true;
+                } else if (startPos < window.getStartPosition()
+                        || startPos >= window.getStartPosition() + window.getNumRows()) {
+                    window.clear();
+                    mCursor.fillWindow(startPos, window);
                 }
             }
 
@@ -211,7 +202,7 @@
                 mCursor.deactivate();
             }
 
-            closeWindowForNonWindowedCursorLocked();
+            closeFilledWindowLocked();
         }
     }
 
@@ -227,7 +218,7 @@
         synchronized (mLock) {
             throwIfCursorIsClosed();
 
-            closeWindowForNonWindowedCursorLocked();
+            closeFilledWindowLocked();
 
             try {
                 if (!mCursor.requery()) {
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index a18a721..9c93324 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -31,8 +31,8 @@
 /**
  * A buffer containing multiple cursor rows.
  * <p>
- * A {@link CursorWindow} is read-write when created and used locally.  When sent
- * to a remote process (by writing it to a {@link Parcel}), the remote process
+ * A {@link CursorWindow} is read-write when initially created and used locally.
+ * When sent to a remote process (by writing it to a {@link Parcel}), the remote process
  * receives a read-only view of the cursor window.  Typically the cursor window
  * will be allocated by the producer, filled with data, and then sent to the
  * consumer for reading.
@@ -58,8 +58,7 @@
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
-    private static native int nativeCreate(String name,
-            int cursorWindowSize, boolean localOnly);
+    private static native int nativeCreate(String name, int cursorWindowSize);
     private static native int nativeCreateFromParcel(Parcel parcel);
     private static native void nativeDispose(int windowPtr);
     private static native void nativeWriteToParcel(int windowPtr, Parcel parcel);
@@ -93,14 +92,10 @@
      * </p>
      *
      * @param name The name of the cursor window, or null if none.
-     * @param localWindow True if this window will be used in this process only,
-     * false if it might be sent to another processes.
-     *
-     * @hide
      */
-    public CursorWindow(String name, boolean localWindow) {
+    public CursorWindow(String name) {
         mStartPos = 0;
-        mWindowPtr = nativeCreate(name, sCursorWindowSize, localWindow);
+        mWindowPtr = nativeCreate(name, sCursorWindowSize);
         if (mWindowPtr == 0) {
             throw new CursorWindowAllocationException("Cursor window allocation of " +
                     (sCursorWindowSize / 1024) + " kb failed. " + printStats());
@@ -117,10 +112,14 @@
      * </p>
      *
      * @param localWindow True if this window will be used in this process only,
-     * false if it might be sent to another processes.
+     * false if it might be sent to another processes.  This argument is ignored.
+     *
+     * @deprecated There is no longer a distinction between local and remote
+     * cursor windows.  Use the {@link #CursorWindow(String)} constructor instead.
      */
+    @Deprecated
     public CursorWindow(boolean localWindow) {
-        this(null, localWindow);
+        this((String)null);
     }
 
     private CursorWindow(Parcel source) {
@@ -272,8 +271,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_NULL}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}.
      * @deprecated Use {@link #getType(int, int)} instead.
@@ -287,8 +285,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or
      * {@link Cursor#FIELD_TYPE_NULL}.
@@ -304,8 +301,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_INTEGER}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}.
      * @deprecated Use {@link #getType(int, int)} instead.
@@ -319,8 +315,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_FLOAT}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}.
      * @deprecated Use {@link #getType(int, int)} instead.
@@ -334,8 +329,7 @@
      * Returns true if the field at the specified row and column index
      * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING}
      * or {@link Cursor#FIELD_TYPE_NULL}.
@@ -360,8 +354,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The field type.
      */
@@ -391,8 +384,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a byte array.
      */
@@ -427,8 +419,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a string.
      */
@@ -466,8 +457,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @param buffer The {@link CharArrayBuffer} to hold the string.  It is automatically
      * resized if the requested string is larger than the buffer's current capacity.
@@ -502,8 +492,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a <code>long</code>.
      */
@@ -535,8 +524,7 @@
      * </ul>
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a <code>double</code>.
      */
@@ -557,8 +545,7 @@
      * result to <code>short</code>.
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as a <code>short</code>.
      */
@@ -574,8 +561,7 @@
      * result to <code>int</code>.
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as an <code>int</code>.
      */
@@ -591,8 +577,7 @@
      * result to <code>float</code>.
      * </p>
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return The value of the field as an <code>float</code>.
      */
@@ -604,8 +589,7 @@
      * Copies a byte array into the field at the specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -622,8 +606,7 @@
      * Copies a string into the field at the specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -640,8 +623,7 @@
      * Puts a long integer into the field at the specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -659,8 +641,7 @@
      * specified row and column index.
      *
      * @param value The value to store.
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
@@ -676,8 +657,7 @@
     /**
      * Puts a null value into the field at the specified row and column index.
      *
-     * @param row The zero-based row index, relative to the cursor window's
-     * start position ({@link #getStartPosition()}).
+     * @param row The zero-based row index.
      * @param column The zero-based column index.
      * @return True if successful.
      */
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 320733e..7baeb8c 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -25,9 +25,13 @@
  * use for this class is to extend a cursor while overriding only a subset of its methods.
  */
 public class CursorWrapper implements Cursor {
+    /** @hide */
+    protected final Cursor mCursor;
 
-    private final Cursor mCursor;
-
+    /**
+     * Creates a cursor wrapper.
+     * @param cursor The underlying cursor to wrap.
+     */
     public CursorWrapper(Cursor cursor) {
         mCursor = cursor;
     }
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 8e6f699..a10ca15 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -237,7 +237,8 @@
             return Cursor.FIELD_TYPE_BLOB;
         } else if (obj instanceof Float || obj instanceof Double) {
             return Cursor.FIELD_TYPE_FLOAT;
-        } else if (obj instanceof Long || obj instanceof Integer) {
+        } else if (obj instanceof Long || obj instanceof Integer
+                || obj instanceof Short || obj instanceof Byte) {
             return Cursor.FIELD_TYPE_INTEGER;
         } else {
             return Cursor.FIELD_TYPE_STRING;
@@ -245,6 +246,82 @@
     }
 
     /**
+     * Fills the specified cursor window by iterating over the contents of the cursor.
+     * The window is filled until the cursor is exhausted or the window runs out
+     * of space.
+     *
+     * The original position of the cursor is left unchanged by this operation.
+     *
+     * @param cursor The cursor that contains the data to put in the window.
+     * @param position The start position for filling the window.
+     * @param window The window to fill.
+     * @hide
+     */
+    public static void cursorFillWindow(final Cursor cursor,
+            int position, final CursorWindow window) {
+        if (position < 0 || position >= cursor.getCount()) {
+            return;
+        }
+        window.acquireReference();
+        try {
+            final int oldPos = cursor.getPosition();
+            final int numColumns = cursor.getColumnCount();
+            window.clear();
+            window.setStartPosition(position);
+            window.setNumColumns(numColumns);
+            if (cursor.moveToPosition(position)) {
+                do {
+                    if (!window.allocRow()) {
+                        break;
+                    }
+                    for (int i = 0; i < numColumns; i++) {
+                        final int type = cursor.getType(i);
+                        final boolean success;
+                        switch (type) {
+                            case Cursor.FIELD_TYPE_NULL:
+                                success = window.putNull(position, i);
+                                break;
+
+                            case Cursor.FIELD_TYPE_INTEGER:
+                                success = window.putLong(cursor.getLong(i), position, i);
+                                break;
+
+                            case Cursor.FIELD_TYPE_FLOAT:
+                                success = window.putDouble(cursor.getDouble(i), position, i);
+                                break;
+
+                            case Cursor.FIELD_TYPE_BLOB: {
+                                final byte[] value = cursor.getBlob(i);
+                                success = value != null ? window.putBlob(value, position, i)
+                                        : window.putNull(position, i);
+                                break;
+                            }
+
+                            default: // assume value is convertible to String
+                            case Cursor.FIELD_TYPE_STRING: {
+                                final String value = cursor.getString(i);
+                                success = value != null ? window.putString(value, position, i)
+                                        : window.putNull(position, i);
+                                break;
+                            }
+                        }
+                        if (!success) {
+                            window.freeLastRow();
+                            break;
+                        }
+                    }
+                    position += 1;
+                } while (cursor.moveToNext());
+            }
+            cursor.moveToPosition(oldPos);
+        } catch (IllegalStateException e){
+            // simply ignore it
+        } finally {
+            window.releaseReference();
+        }
+    }
+
+    /**
      * Appends an SQL string to the given StringBuilder, including the opening
      * and closing single quotes. Any single quotes internal to sqlString will
      * be escaped.
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index a1c36e2..9574300 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -155,7 +155,7 @@
     }
 
     private void fillWindow(int startPos) {
-        clearOrCreateLocalWindow(getDatabase().getPath());
+        clearOrCreateWindow(getDatabase().getPath());
         mWindow.setStartPosition(startPos);
         int count = getQuery().fillWindow(mWindow);
         if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7eae739..b9e0fe8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -425,20 +425,17 @@
                     }
                 }
 
+                CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
+                mTranslator = compatibilityInfo.getTranslator();
+
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
                     enableHardwareAcceleration(attrs);
                 }
 
-                CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
-                mTranslator = compatibilityInfo.getTranslator();
-
-                if (mTranslator != null) {
-                    mSurface.setCompatibilityTranslator(mTranslator);
-                }
-
                 boolean restore = false;
                 if (mTranslator != null) {
+                    mSurface.setCompatibilityTranslator(mTranslator);
                     restore = true;
                     attrs.backup();
                     mTranslator.translateWindowLayout(attrs);
@@ -590,6 +587,9 @@
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
 
+        // Don't enable hardware acceleration when the application is in compatibility mode
+        if (mTranslator != null) return;
+
         // Try to enable hardware acceleration if requested
         final boolean hardwareAccelerated = 
                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 722aeea..4a9fcf2 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -57,8 +57,7 @@
     jniThrowException(env, "java/lang/IllegalStateException", msg.string());
 }
 
-static jint nativeCreate(JNIEnv* env, jclass clazz,
-        jstring nameObj, jint cursorWindowSize, jboolean localOnly) {
+static jint nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
     String8 name;
     if (nameObj) {
         const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
@@ -70,7 +69,7 @@
     }
 
     CursorWindow* window;
-    status_t status = CursorWindow::create(name, cursorWindowSize, localOnly, &window);
+    status_t status = CursorWindow::create(name, cursorWindowSize, &window);
     if (status || !window) {
         LOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
                 name.string(), cursorWindowSize, status);
@@ -477,7 +476,7 @@
 static JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
-    { "nativeCreate", "(Ljava/lang/String;IZ)I",
+    { "nativeCreate", "(Ljava/lang/String;I)I",
             (void*)nativeCreate },
     { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",
             (void*)nativeCreateFromParcel },
diff --git a/core/tests/coretests/src/android/database/CursorWindowTest.java b/core/tests/coretests/src/android/database/CursorWindowTest.java
index 07e75cb..8c8081c 100644
--- a/core/tests/coretests/src/android/database/CursorWindowTest.java
+++ b/core/tests/coretests/src/android/database/CursorWindowTest.java
@@ -16,17 +16,11 @@
 
 package android.database;
 
-import android.database.AbstractCursor;
 import android.test.suitebuilder.annotation.SmallTest;
-import com.android.common.ArrayListCursor;
 import android.database.CursorWindow;
 import android.test.PerformanceTestCase;
 
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Random;
 
 import junit.framework.TestCase;
 
@@ -41,48 +35,6 @@
     }
 
     @SmallTest
-    public void testWriteCursorToWindow() throws Exception {
-        // create cursor
-        String[] colNames = new String[]{"name", "number", "profit"};
-        int colsize = colNames.length;
-        ArrayList<ArrayList> list = createTestList(10, colsize);
-        AbstractCursor cursor = new ArrayListCursor(colNames, (ArrayList<ArrayList>) list);
-
-        // fill window
-        CursorWindow window = new CursorWindow(false);
-        cursor.fillWindow(0, window);
-
-        // read from cursor window
-        for (int i = 0; i < list.size(); i++) {
-            ArrayList<Integer> col = list.get(i);
-            for (int j = 0; j < colsize; j++) {
-                String s = window.getString(i, j);
-                int r2 = col.get(j);
-                int r1 = Integer.parseInt(s);
-                assertEquals(r2, r1);
-            }
-        }
-
-        // test cursor window handle startpos != 0 
-        window.clear();
-        cursor.fillWindow(1, window);
-        // read from cursor from window
-        for (int i = 1; i < list.size(); i++) {
-            ArrayList<Integer> col = list.get(i);
-            for (int j = 0; j < colsize; j++) {
-                String s = window.getString(i, j);
-                int r2 = col.get(j);
-                int r1 = Integer.parseInt(s);
-                assertEquals(r2, r1);
-            }
-        }
-
-        // Clear the window and make sure it's empty
-        window.clear();
-        assertEquals(0, window.getNumRows());
-    }
-
-    @SmallTest
     public void testValuesLocalWindow() {
         doTestValues(new CursorWindow(true));
     }
@@ -124,50 +76,4 @@
         assertTrue(window.putBlob(blob, 0, 6));
         assertTrue(Arrays.equals(blob, window.getBlob(0, 6)));
     }
-
-    @SmallTest
-    public void testNull() {
-        CursorWindow window = getOneByOneWindow();
-
-        // Put in a null value and read it back as various types
-        assertTrue(window.putNull(0, 0));
-        assertNull(window.getString(0, 0));
-        assertEquals(0, window.getLong(0, 0));
-        assertEquals(0.0, window.getDouble(0, 0));
-        assertNull(window.getBlob(0, 0));
-    }
-
-    @SmallTest
-    public void testEmptyString() {
-        CursorWindow window = getOneByOneWindow();
-
-        // put size 0 string and read it back as various types
-        assertTrue(window.putString("", 0, 0));
-        assertEquals("", window.getString(0, 0));
-        assertEquals(0, window.getLong(0, 0));
-        assertEquals(0.0, window.getDouble(0, 0));
-    }
-
-    private CursorWindow getOneByOneWindow() {
-        CursorWindow window = new CursorWindow(false);
-        assertTrue(window.setNumColumns(1));
-        assertTrue(window.allocRow());
-        return window;
-    }
-    
-    private static ArrayList<ArrayList> createTestList(int rows, int cols) {
-        ArrayList<ArrayList> list = Lists.newArrayList();
-        Random generator = new Random();
-
-        for (int i = 0; i < rows; i++) {
-            ArrayList<Integer> col = Lists.newArrayList();
-            list.add(col);
-            for (int j = 0; j < cols; j++) {
-                // generate random number
-                Integer r = generator.nextInt();
-                col.add(r);
-            }
-        }
-        return list;
-    }
 }
diff --git a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
index 7726f02..62466f1 100644
--- a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
@@ -16,11 +16,11 @@
 
 package android.widget;
 
-import com.android.common.ArrayListCursor;
 import com.google.android.collect.Lists;
 
 import android.content.Context;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -52,14 +52,14 @@
         super.setUp();
         
         // all the pieces needed for the various tests
-        mFrom = new String[]{"Column1", "Column2"};
+        mFrom = new String[]{"Column1", "Column2", "_id"};
         mTo = new int[]{com.android.internal.R.id.text1, com.android.internal.R.id.text2};
         mLayout = com.android.internal.R.layout.simple_list_item_2;
         mContext = getContext();
 
         // raw data for building a basic test cursor
         mData2x2 = createTestList(2, 2);
-        mCursor2x2 = new ArrayListCursor(mFrom, mData2x2);
+        mCursor2x2 = createCursor(mFrom, mData2x2);
     }
     
     /**
@@ -77,6 +77,7 @@
                 Integer r = generator.nextInt();
                 col.add(r);
             }
+            col.add(i);
         }
         return list;
     }
@@ -115,7 +116,7 @@
         
         // now put in a different cursor (5 rows)
         ArrayList<ArrayList> data2 = createTestList(5, 2);
-        Cursor c2 = new ArrayListCursor(mFrom, data2);
+        Cursor c2 = createCursor(mFrom, data2);
         ca.changeCursor(c2);
         
         // Now see if we can pull 5 rows from the adapter
@@ -155,8 +156,8 @@
         assertEquals(columns[1], 1);
 
         // Now make a new cursor with similar data but rearrange the columns
-        String[] swappedFrom = new String[]{"Column2", "Column1"};
-        Cursor c2 = new ArrayListCursor(swappedFrom, mData2x2);
+        String[] swappedFrom = new String[]{"Column2", "Column1", "_id"};
+        Cursor c2 = createCursor(swappedFrom, mData2x2);
         ca.changeCursor(c2);
         assertEquals(2, ca.getCount());
 
@@ -235,7 +236,15 @@
         assertEquals(1, viewIds.length);
         assertEquals(com.android.internal.R.id.text2, viewIds[0]);
     }
-    
+
+    private static MatrixCursor createCursor(String[] columns, ArrayList<ArrayList> list) {
+        MatrixCursor cursor = new MatrixCursor(columns, list.size());
+        for (ArrayList row : list) {
+            cursor.addRow(row);
+        }
+        return cursor;
+    }
+
     /**
      * This is simply a way to sneak a look at the protected mFrom() array.  A more API-
      * friendly way to do this would be to mock out a View and a ViewBinder and exercise
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index 5d490ed..f0284de 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -80,8 +80,7 @@
 
     ~CursorWindow();
 
-    static status_t create(const String8& name, size_t size, bool localOnly,
-            CursorWindow** outCursorWindow);
+    static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow);
     static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);
 
     status_t writeToParcel(Parcel* parcel);
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index 1b85a71..bf8d7a6 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -40,11 +40,9 @@
     ::close(mAshmemFd);
 }
 
-status_t CursorWindow::create(const String8& name, size_t size, bool localOnly,
-        CursorWindow** outCursorWindow) {
+status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
     String8 ashmemName("CursorWindow: ");
     ashmemName.append(name);
-    ashmemName.append(localOnly ? " (local)" : " (remote)");
 
     status_t result;
     int ashmemFd = ashmem_create_region(ashmemName.string(), size);
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index 3471ec2..a66e19d 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -19,166 +19,20 @@
 import android.content.ContentProvider;
 import android.content.UriMatcher;
 import android.content.ContentValues;
-import android.database.AbstractCursor;
 import android.database.Cursor;
-import android.database.CursorWindow;
+import android.database.MatrixCursor;
 import android.net.Uri;
-import android.os.SystemProperties;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import com.android.internal.telephony.IccConstants;
 import com.android.internal.telephony.AdnRecord;
 import com.android.internal.telephony.IIccPhoneBook;
 
-/**
- * XXX old code -- should be replaced with MatrixCursor.
- * @deprecated This is has been replaced by MatrixCursor.
-*/
-class ArrayListCursor extends AbstractCursor {
-    private String[] mColumnNames;
-    private ArrayList<Object>[] mRows;
-
-    @SuppressWarnings({"unchecked"})
-    public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
-        int colCount = columnNames.length;
-        boolean foundID = false;
-        // Add an _id column if not in columnNames
-        for (int i = 0; i < colCount; ++i) {
-            if (columnNames[i].compareToIgnoreCase("_id") == 0) {
-                mColumnNames = columnNames;
-                foundID = true;
-                break;
-            }
-        }
-
-        if (!foundID) {
-            mColumnNames = new String[colCount + 1];
-            System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
-            mColumnNames[colCount] = "_id";
-        }
-
-        int rowCount = rows.size();
-        mRows = new ArrayList[rowCount];
-
-        for (int i = 0; i < rowCount; ++i) {
-            mRows[i] = rows.get(i);
-            if (!foundID) {
-                mRows[i].add(i);
-            }
-        }
-    }
-
-    @Override
-    public void fillWindow(int position, CursorWindow window) {
-        if (position < 0 || position > getCount()) {
-            return;
-        }
-
-        window.acquireReference();
-        try {
-            int oldpos = mPos;
-            mPos = position - 1;
-            window.clear();
-            window.setStartPosition(position);
-            int columnNum = getColumnCount();
-            window.setNumColumns(columnNum);
-            while (moveToNext() && window.allocRow()) {
-                for (int i = 0; i < columnNum; i++) {
-                    final Object data = mRows[mPos].get(i);
-                    if (data != null) {
-                        if (data instanceof byte[]) {
-                            byte[] field = (byte[]) data;
-                            if (!window.putBlob(field, mPos, i)) {
-                                window.freeLastRow();
-                                break;
-                            }
-                        } else {
-                            String field = data.toString();
-                            if (!window.putString(field, mPos, i)) {
-                                window.freeLastRow();
-                                break;
-                            }
-                        }
-                    } else {
-                        if (!window.putNull(mPos, i)) {
-                            window.freeLastRow();
-                            break;
-                        }
-                    }
-                }
-            }
-
-            mPos = oldpos;
-        } catch (IllegalStateException e){
-            // simply ignore it
-        } finally {
-            window.releaseReference();
-        }
-    }
-
-    @Override
-    public int getCount() {
-        return mRows.length;
-    }
-
-    @Override
-    public String[] getColumnNames() {
-        return mColumnNames;
-    }
-
-    @Override
-    public byte[] getBlob(int columnIndex) {
-        return (byte[]) mRows[mPos].get(columnIndex);
-    }
-
-    @Override
-    public String getString(int columnIndex) {
-        Object cell = mRows[mPos].get(columnIndex);
-        return (cell == null) ? null : cell.toString();
-    }
-
-    @Override
-    public short getShort(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.shortValue();
-    }
-
-    @Override
-    public int getInt(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.intValue();
-    }
-
-    @Override
-    public long getLong(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.longValue();
-    }
-
-    @Override
-    public float getFloat(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.floatValue();
-    }
-
-    @Override
-    public double getDouble(int columnIndex) {
-        Number num = (Number) mRows[mPos].get(columnIndex);
-        return num.doubleValue();
-    }
-
-    @Override
-    public boolean isNull(int columnIndex) {
-        return mRows[mPos].get(columnIndex) == null;
-    }
-}
-
 
 /**
  * {@hide}
@@ -191,7 +45,8 @@
     private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
         "name",
         "number",
-        "emails"
+        "emails",
+        "_id"
     };
 
     private static final int ADN = 1;
@@ -213,70 +68,27 @@
     }
 
 
-    private boolean mSimulator;
-
     @Override
     public boolean onCreate() {
-        String device = SystemProperties.get("ro.product.device");
-        if (!TextUtils.isEmpty(device)) {
-            mSimulator = false;
-        } else {
-            // simulator
-            mSimulator = true;
-        }
-
         return true;
     }
 
     @Override
     public Cursor query(Uri url, String[] projection, String selection,
             String[] selectionArgs, String sort) {
-        ArrayList<ArrayList> results;
+        switch (URL_MATCHER.match(url)) {
+            case ADN:
+                return loadFromEf(IccConstants.EF_ADN);
 
-        if (!mSimulator) {
-            switch (URL_MATCHER.match(url)) {
-                case ADN:
-                    results = loadFromEf(IccConstants.EF_ADN);
-                    break;
+            case FDN:
+                return loadFromEf(IccConstants.EF_FDN);
 
-                case FDN:
-                    results = loadFromEf(IccConstants.EF_FDN);
-                    break;
+            case SDN:
+                return loadFromEf(IccConstants.EF_SDN);
 
-                case SDN:
-                    results = loadFromEf(IccConstants.EF_SDN);
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Unknown URL " + url);
-            }
-        } else {
-            // Fake up some data for the simulator
-            results = new ArrayList<ArrayList>(4);
-            ArrayList<String> contact;
-
-            contact = new ArrayList<String>();
-            contact.add("Ron Stevens/H");
-            contact.add("512-555-5038");
-            results.add(contact);
-
-            contact = new ArrayList<String>();
-            contact.add("Ron Stevens/M");
-            contact.add("512-555-8305");
-            results.add(contact);
-
-            contact = new ArrayList<String>();
-            contact.add("Melissa Owens");
-            contact.add("512-555-8305");
-            results.add(contact);
-
-            contact = new ArrayList<String>();
-            contact.add("Directory Assistence");
-            contact.add("411");
-            results.add(contact);
+            default:
+                throw new IllegalArgumentException("Unknown URL " + url);
         }
-
-        return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
     }
 
     @Override
@@ -473,12 +285,10 @@
         return 1;
     }
 
-    private ArrayList<ArrayList> loadFromEf(int efType) {
-        ArrayList<ArrayList> results = new ArrayList<ArrayList>();
-        List<AdnRecord> adnRecords = null;
-
+    private MatrixCursor loadFromEf(int efType) {
         if (DBG) log("loadFromEf: efType=" + efType);
 
+        List<AdnRecord> adnRecords = null;
         try {
             IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
                     ServiceManager.getService("simphonebook"));
@@ -490,21 +300,21 @@
         } catch (SecurityException ex) {
             if (DBG) log(ex.toString());
         }
+
         if (adnRecords != null) {
             // Load the results
-
-            int N = adnRecords.size();
+            final int N = adnRecords.size();
+            final MatrixCursor cursor = new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES, N);
             if (DBG) log("adnRecords.size=" + N);
             for (int i = 0; i < N ; i++) {
-                loadRecord(adnRecords.get(i), results);
+                loadRecord(adnRecords.get(i), cursor, i);
             }
+            return cursor;
         } else {
             // No results to load
             Log.w(TAG, "Cannot load ADN records");
-            results.clear();
+            return new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES);
         }
-        if (DBG) log("loadFromEf: return results");
-        return results;
     }
 
     private boolean
@@ -584,35 +394,33 @@
     }
 
     /**
-     * Loads an AdnRecord into an ArrayList. Must be called with mLock held.
+     * Loads an AdnRecord into a MatrixCursor. Must be called with mLock held.
      *
      * @param record the ADN record to load from
-     * @param results the array list to put the results in
+     * @param cursor the cursor to receive the results
      */
-    private void loadRecord(AdnRecord record,
-            ArrayList<ArrayList> results) {
+    private void loadRecord(AdnRecord record, MatrixCursor cursor, int id) {
         if (!record.isEmpty()) {
-            ArrayList<String> contact = new ArrayList<String>();
+            Object[] contact = new Object[4];
             String alphaTag = record.getAlphaTag();
             String number = record.getNumber();
-            String[] emails = record.getEmails();
 
             if (DBG) log("loadRecord: " + alphaTag + ", " + number + ",");
-            contact.add(alphaTag);
-            contact.add(number);
-            StringBuilder emailString = new StringBuilder();
+            contact[0] = alphaTag;
+            contact[1] = number;
 
+            String[] emails = record.getEmails();
             if (emails != null) {
+                StringBuilder emailString = new StringBuilder();
                 for (String email: emails) {
                     if (DBG) log("Adding email:" + email);
                     emailString.append(email);
                     emailString.append(",");
                 }
-                contact.add(emailString.toString());
-            } else {
-                contact.add(null);
+                contact[2] = emailString.toString();
             }
-            results.add(contact);
+            contact[3] = id;
+            cursor.addRow(contact);
         }
     }