19439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/*
29439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (C) 2006 The Android Open Source Project
39439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * you may not use this file except in compliance with the License.
69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * You may obtain a copy of the License at
79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Unless required by applicable law or agreed to in writing, software
119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * See the License for the specific language governing permissions and
149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * limitations under the License.
159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage android.database;
189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport dalvik.system.CloseGuard;
209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.content.res.Resources;
229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.database.sqlite.SQLiteClosable;
239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.database.sqlite.SQLiteException;
249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.os.Binder;
259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.os.Parcel;
269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.os.Parcelable;
279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.os.Process;
289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.util.Log;
299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.util.SparseIntArray;
309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport android.util.LongSparseArray;
319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * A buffer containing multiple cursor rows.
349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * <p>
359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * A {@link CursorWindow} is read-write when initially created and used locally.
3605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * When sent to a remote process (by writing it to a {@link Parcel}), the remote process
3705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * receives a read-only view of the cursor window.  Typically the cursor window
389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * will be allocated by the producer, filled with data, and then sent to the
399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * consumer for reading.
409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * </p>
413998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun */
423998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic class CursorWindow extends SQLiteClosable implements Parcelable {
439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static final String STATS_TAG = "CursorWindowStats";
449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun    // This static member will be evaluated when first used.
469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static int sCursorWindowSize = -1;
479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun    /**
499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * The native CursorWindow object pointer.  (FOR INTERNAL USE ONLY)
509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @hide
512e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     */
529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public long mWindowPtr;
533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
543998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private int mStartPos;
553998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private final String mName;
563998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
573998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private final CloseGuard mCloseGuard = CloseGuard.get();
583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private static native long nativeCreate(String name, int cursorWindowSize);
603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private static native long nativeCreateFromParcel(Parcel parcel);
619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native void nativeDispose(long windowPtr);
629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native void nativeWriteToParcel(long windowPtr, Parcel parcel);
639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native void nativeClear(long windowPtr);
659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native int nativeGetNumRows(long windowPtr);
679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativeSetNumColumns(long windowPtr, int columnNum);
689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativeAllocRow(long windowPtr);
699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native void nativeFreeLastRow(long windowPtr);
709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native int nativeGetType(long windowPtr, int row, int column);
729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native byte[] nativeGetBlob(long windowPtr, int row, int column);
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native String nativeGetString(long windowPtr, int row, int column);
749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native long nativeGetLong(long windowPtr, int row, int column);
759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native double nativeGetDouble(long windowPtr, int row, int column);
769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native void nativeCopyStringToBuffer(long windowPtr, int row, int column,
779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            CharArrayBuffer buffer);
789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativePutBlob(long windowPtr, byte[] value, int row, int column);
809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativePutString(long windowPtr, String value, int row, int column);
819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativePutLong(long windowPtr, long value, int row, int column);
829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativePutDouble(long windowPtr, double value, int row, int column);
839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native boolean nativePutNull(long windowPtr, int row, int column);
849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private static native String nativeGetName(long windowPtr);
869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates a new empty cursor window and gives it a name.
899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <p>
909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * The cursor initially has no rows or columns.  Call {@link #setNumColumns(int)} to
919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * set the number of columns before adding any rows to the cursor.
929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </p>
939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param name The name of the cursor window, or null if none.
959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public CursorWindow(String name) {
979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mStartPos = 0;
989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mName = name != null && name.length() != 0 ? name : "<unnamed>";
999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (sCursorWindowSize < 0) {
1009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /** The cursor window size. resource xml file specifies the value in kB.
1019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * convert it to bytes here by multiplying with 1024.
1029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
1039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            sCursorWindowSize = Resources.getSystem().getInteger(
1049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
1059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mWindowPtr = nativeCreate(mName, sCursorWindowSize);
1079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (mWindowPtr == 0) {
1089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new CursorWindowAllocationException("Cursor window allocation of " +
1099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    (sCursorWindowSize / 1024) + " kb failed. " + printStats());
1109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mCloseGuard.open("close");
1129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        recordNewWindow(Binder.getCallingPid(), mWindowPtr);
1139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates a new empty cursor window.
1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <p>
1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * The cursor initially has no rows or columns.  Call {@link #setNumColumns(int)} to
1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * set the number of columns before adding any rows to the cursor.
1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </p>
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param localWindow True if this window will be used in this process only,
1239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * false if it might be sent to another processes.  This argument is ignored.
1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @deprecated There is no longer a distinction between local and remote
1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * cursor windows.  Use the {@link #CursorWindow(String)} constructor instead.
1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Deprecated
1299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public CursorWindow(boolean localWindow) {
1309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        this((String)null);
1319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private CursorWindow(Parcel source) {
1349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mStartPos = source.readInt();
1359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mWindowPtr = nativeCreateFromParcel(source);
1369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (mWindowPtr == 0) {
1379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new CursorWindowAllocationException("Cursor window could not be "
1389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    + "created from binder.");
1399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mName = nativeGetName(mWindowPtr);
1419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mCloseGuard.open("close");
1429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Override
1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    protected void finalize() throws Throwable {
1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
1479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (mCloseGuard != null) {
1489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                mCloseGuard.warnIfOpen();
1499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            dispose();
1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
1529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            super.finalize();
1539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void dispose() {
1579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (mCloseGuard != null) {
1589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            mCloseGuard.close();
1599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (mWindowPtr != 0) {
1619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            recordClosingOfWindow(mWindowPtr);
1629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            nativeDispose(mWindowPtr);
1639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            mWindowPtr = 0;
1649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Gets the name of this cursor window, never null.
1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @hide
1709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public String getName() {
1729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return mName;
1739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Clears out the existing contents of the window, making it safe to reuse
1779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * for new data.
1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <p>
1799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * The start position ({@link #getStartPosition()}), number of rows ({@link #getNumRows()}),
1809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * and number of columns in the cursor are all reset to zero.
1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </p>
1829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void clear() {
1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        acquireReference();
1859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
1869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            mStartPos = 0;
1879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            nativeClear(mWindowPtr);
1889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            releaseReference();
1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Gets the start position of this cursor window.
1959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <p>
1969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * The start position is the zero-based index of the first row that this window contains
1979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * relative to the entire result set of the {@link Cursor}.
1989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </p>
1999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return The zero-based start position.
2019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public int getStartPosition() {
2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return mStartPos;
2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Sets the start position of this cursor window.
2089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <p>
2099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * The start position is the zero-based index of the first row that this window contains
2109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * relative to the entire result set of the {@link Cursor}.
2119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </p>
2129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param pos The new zero-based start position.
2149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void setStartPosition(int pos) {
2169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        mStartPos = pos;
2179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Gets the number of rows in this window.
2219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return The number of rows in this cursor window.
2239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public int getNumRows() {
2259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        acquireReference();
2269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return nativeGetNumRows(mWindowPtr);
2289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
2299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            releaseReference();
2309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Sets the number of columns in this window.
2359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <p>
2369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * This method must be called before any rows are added to the window, otherwise
2379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * it will fail to set the number of columns if it differs from the current number
2389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * of columns.
2399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </p>
2409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param columnNum The new number of columns.
2429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return True if successful.
2439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public boolean setNumColumns(int columnNum) {
2459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        acquireReference();
2469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return nativeSetNumColumns(mWindowPtr, columnNum);
2489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
2499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            releaseReference();
2509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Allocates a new row at the end of this cursor window.
2559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return True if successful, false if the cursor window is out of memory.
2579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public boolean allocRow(){
2599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        acquireReference();
2609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return nativeAllocRow(mWindowPtr);
2629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
2639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            releaseReference();
2649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Frees the last row in this cursor window.
2699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void freeLastRow(){
2719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        acquireReference();
2729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            nativeFreeLastRow(mWindowPtr);
2749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
2759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            releaseReference();
2769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns true if the field at the specified row and column index
2819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * has type {@link Cursor#FIELD_TYPE_NULL}.
2829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param row The zero-based row index.
2849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param column The zero-based column index.
2859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}.
2869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @deprecated Use {@link #getType(int, int)} instead.
2879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Deprecated
2899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public boolean isNull(int row, int column) {
2909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return getType(row, column) == Cursor.FIELD_TYPE_NULL;
2919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns true if the field at the specified row and column index
2959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}.
2969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param row The zero-based row index.
2989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param column The zero-based column index.
2999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or
3009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * {@link Cursor#FIELD_TYPE_NULL}.
3019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @deprecated Use {@link #getType(int, int)} instead.
3029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Deprecated
3049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public boolean isBlob(int row, int column) {
3059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int type = getType(row, column);
3069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return type == Cursor.FIELD_TYPE_BLOB || type == Cursor.FIELD_TYPE_NULL;
3079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
3089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
3109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns true if the field at the specified row and column index
3119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * has type {@link Cursor#FIELD_TYPE_INTEGER}.
3129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
3139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param row The zero-based row index.
3149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param column The zero-based column index.
3159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}.
3169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @deprecated Use {@link #getType(int, int)} instead.
3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    @Deprecated
3199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public boolean isLong(int row, int column) {
3209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return getType(row, column) == Cursor.FIELD_TYPE_INTEGER;
3219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
3229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
3243998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun     * Returns true if the field at the specified row and column index
3253998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun     * has type {@link Cursor#FIELD_TYPE_FLOAT}.
3269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
327     * @param row The zero-based row index.
328     * @param column The zero-based column index.
329     * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}.
330     * @deprecated Use {@link #getType(int, int)} instead.
331     */
332    @Deprecated
333    public boolean isFloat(int row, int column) {
334        return getType(row, column) == Cursor.FIELD_TYPE_FLOAT;
335    }
336
337    /**
338     * Returns true if the field at the specified row and column index
339     * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}.
340     *
341     * @param row The zero-based row index.
342     * @param column The zero-based column index.
343     * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING}
344     * or {@link Cursor#FIELD_TYPE_NULL}.
345     * @deprecated Use {@link #getType(int, int)} instead.
346     */
347    @Deprecated
348    public boolean isString(int row, int column) {
349        int type = getType(row, column);
350        return type == Cursor.FIELD_TYPE_STRING || type == Cursor.FIELD_TYPE_NULL;
351    }
352
353    /**
354     * Returns the type of the field at the specified row and column index.
355     * <p>
356     * The returned field types are:
357     * <ul>
358     * <li>{@link Cursor#FIELD_TYPE_NULL}</li>
359     * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
360     * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
361     * <li>{@link Cursor#FIELD_TYPE_STRING}</li>
362     * <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
363     * </ul>
364     * </p>
365     *
366     * @param row The zero-based row index.
367     * @param column The zero-based column index.
368     * @return The field type.
369     */
370    public int getType(int row, int column) {
371        acquireReference();
372        try {
373            return nativeGetType(mWindowPtr, row - mStartPos, column);
374        } finally {
375            releaseReference();
376        }
377    }
378
379    /**
380     * Gets the value of the field at the specified row and column index as a byte array.
381     * <p>
382     * The result is determined as follows:
383     * <ul>
384     * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
385     * is <code>null</code>.</li>
386     * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then the result
387     * is the blob value.</li>
388     * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
389     * is the array of bytes that make up the internal representation of the
390     * string value.</li>
391     * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER} or
392     * {@link Cursor#FIELD_TYPE_FLOAT}, then a {@link SQLiteException} is thrown.</li>
393     * </ul>
394     * </p>
395     *
396     * @param row The zero-based row index.
397     * @param column The zero-based column index.
398     * @return The value of the field as a byte array.
399     */
400    public byte[] getBlob(int row, int column) {
401        acquireReference();
402        try {
403            return nativeGetBlob(mWindowPtr, row - mStartPos, column);
404        } finally {
405            releaseReference();
406        }
407    }
408
409    /**
410     * Gets the value of the field at the specified row and column index as a string.
411     * <p>
412     * The result is determined as follows:
413     * <ul>
414     * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
415     * is <code>null</code>.</li>
416     * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
417     * is the string value.</li>
418     * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
419     * is a string representation of the integer in decimal, obtained by formatting the
420     * value with the <code>printf</code> family of functions using
421     * format specifier <code>%lld</code>.</li>
422     * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
423     * is a string representation of the floating-point value in decimal, obtained by
424     * formatting the value with the <code>printf</code> family of functions using
425     * format specifier <code>%g</code>.</li>
426     * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
427     * {@link SQLiteException} is thrown.</li>
428     * </ul>
429     * </p>
430     *
431     * @param row The zero-based row index.
432     * @param column The zero-based column index.
433     * @return The value of the field as a string.
434     */
435    public String getString(int row, int column) {
436        acquireReference();
437        try {
438            return nativeGetString(mWindowPtr, row - mStartPos, column);
439        } finally {
440            releaseReference();
441        }
442    }
443
444    /**
445     * Copies the text of the field at the specified row and column index into
446     * a {@link CharArrayBuffer}.
447     * <p>
448     * The buffer is populated as follows:
449     * <ul>
450     * <li>If the buffer is too small for the value to be copied, then it is
451     * automatically resized.</li>
452     * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the buffer
453     * is set to an empty string.</li>
454     * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the buffer
455     * is set to the contents of the string.</li>
456     * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the buffer
457     * is set to a string representation of the integer in decimal, obtained by formatting the
458     * value with the <code>printf</code> family of functions using
459     * format specifier <code>%lld</code>.</li>
460     * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the buffer is
461     * set to a string representation of the floating-point value in decimal, obtained by
462     * formatting the value with the <code>printf</code> family of functions using
463     * format specifier <code>%g</code>.</li>
464     * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
465     * {@link SQLiteException} is thrown.</li>
466     * </ul>
467     * </p>
468     *
469     * @param row The zero-based row index.
470     * @param column The zero-based column index.
471     * @param buffer The {@link CharArrayBuffer} to hold the string.  It is automatically
472     * resized if the requested string is larger than the buffer's current capacity.
473      */
474    public void copyStringToBuffer(int row, int column, CharArrayBuffer buffer) {
475        if (buffer == null) {
476            throw new IllegalArgumentException("CharArrayBuffer should not be null");
477        }
478        acquireReference();
479        try {
480            nativeCopyStringToBuffer(mWindowPtr, row - mStartPos, column, buffer);
481        } finally {
482            releaseReference();
483        }
484    }
485
486    /**
487     * Gets the value of the field at the specified row and column index as a <code>long</code>.
488     * <p>
489     * The result is determined as follows:
490     * <ul>
491     * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
492     * is <code>0L</code>.</li>
493     * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
494     * is the value obtained by parsing the string value with <code>strtoll</code>.
495     * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
496     * is the <code>long</code> value.</li>
497     * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
498     * is the floating-point value converted to a <code>long</code>.</li>
499     * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
500     * {@link SQLiteException} is thrown.</li>
501     * </ul>
502     * </p>
503     *
504     * @param row The zero-based row index.
505     * @param column The zero-based column index.
506     * @return The value of the field as a <code>long</code>.
507     */
508    public long getLong(int row, int column) {
509        acquireReference();
510        try {
511            return nativeGetLong(mWindowPtr, row - mStartPos, column);
512        } finally {
513            releaseReference();
514        }
515    }
516
517    /**
518     * Gets the value of the field at the specified row and column index as a
519     * <code>double</code>.
520     * <p>
521     * The result is determined as follows:
522     * <ul>
523     * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
524     * is <code>0.0</code>.</li>
525     * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
526     * is the value obtained by parsing the string value with <code>strtod</code>.
527     * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
528     * is the integer value converted to a <code>double</code>.</li>
529     * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
530     * is the <code>double</code> value.</li>
531     * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
532     * {@link SQLiteException} is thrown.</li>
533     * </ul>
534     * </p>
535     *
536     * @param row The zero-based row index.
537     * @param column The zero-based column index.
538     * @return The value of the field as a <code>double</code>.
539     */
540    public double getDouble(int row, int column) {
541        acquireReference();
542        try {
543            return nativeGetDouble(mWindowPtr, row - mStartPos, column);
544        } finally {
545            releaseReference();
546        }
547    }
548
549    /**
550     * Gets the value of the field at the specified row and column index as a
551     * <code>short</code>.
552     * <p>
553     * The result is determined by invoking {@link #getLong} and converting the
554     * result to <code>short</code>.
555     * </p>
556     *
557     * @param row The zero-based row index.
558     * @param column The zero-based column index.
559     * @return The value of the field as a <code>short</code>.
560     */
561    public short getShort(int row, int column) {
562        return (short) getLong(row, column);
563    }
564
565    /**
566     * Gets the value of the field at the specified row and column index as an
567     * <code>int</code>.
568     * <p>
569     * The result is determined by invoking {@link #getLong} and converting the
570     * result to <code>int</code>.
571     * </p>
572     *
573     * @param row The zero-based row index.
574     * @param column The zero-based column index.
575     * @return The value of the field as an <code>int</code>.
576     */
577    public int getInt(int row, int column) {
578        return (int) getLong(row, column);
579    }
580
581    /**
582     * Gets the value of the field at the specified row and column index as a
583     * <code>float</code>.
584     * <p>
585     * The result is determined by invoking {@link #getDouble} and converting the
586     * result to <code>float</code>.
587     * </p>
588     *
589     * @param row The zero-based row index.
590     * @param column The zero-based column index.
591     * @return The value of the field as an <code>float</code>.
592     */
593    public float getFloat(int row, int column) {
594        return (float) getDouble(row, column);
595    }
596
597    /**
598     * Copies a byte array into the field at the specified row and column index.
599     *
600     * @param value The value to store.
601     * @param row The zero-based row index.
602     * @param column The zero-based column index.
603     * @return True if successful.
604     */
605    public boolean putBlob(byte[] value, int row, int column) {
606        acquireReference();
607        try {
608            return nativePutBlob(mWindowPtr, value, row - mStartPos, column);
609        } finally {
610            releaseReference();
611        }
612    }
613
614    /**
615     * Copies a string into the field at the specified row and column index.
616     *
617     * @param value The value to store.
618     * @param row The zero-based row index.
619     * @param column The zero-based column index.
620     * @return True if successful.
621     */
622    public boolean putString(String value, int row, int column) {
623        acquireReference();
624        try {
625            return nativePutString(mWindowPtr, value, row - mStartPos, column);
626        } finally {
627            releaseReference();
628        }
629    }
630
631    /**
632     * Puts a long integer into the field at the specified row and column index.
633     *
634     * @param value The value to store.
635     * @param row The zero-based row index.
636     * @param column The zero-based column index.
637     * @return True if successful.
638     */
639    public boolean putLong(long value, int row, int column) {
640        acquireReference();
641        try {
642            return nativePutLong(mWindowPtr, value, row - mStartPos, column);
643        } finally {
644            releaseReference();
645        }
646    }
647
648    /**
649     * Puts a double-precision floating point value into the field at the
650     * specified row and column index.
651     *
652     * @param value The value to store.
653     * @param row The zero-based row index.
654     * @param column The zero-based column index.
655     * @return True if successful.
656     */
657    public boolean putDouble(double value, int row, int column) {
658        acquireReference();
659        try {
660            return nativePutDouble(mWindowPtr, value, row - mStartPos, column);
661        } finally {
662            releaseReference();
663        }
664    }
665
666    /**
667     * Puts a null value into the field at the specified row and column index.
668     *
669     * @param row The zero-based row index.
670     * @param column The zero-based column index.
671     * @return True if successful.
672     */
673    public boolean putNull(int row, int column) {
674        acquireReference();
675        try {
676            return nativePutNull(mWindowPtr, row - mStartPos, column);
677        } finally {
678            releaseReference();
679        }
680    }
681
682    public static final Parcelable.Creator<CursorWindow> CREATOR
683            = new Parcelable.Creator<CursorWindow>() {
684        public CursorWindow createFromParcel(Parcel source) {
685            return new CursorWindow(source);
686        }
687
688        public CursorWindow[] newArray(int size) {
689            return new CursorWindow[size];
690        }
691    };
692
693    public static CursorWindow newFromParcel(Parcel p) {
694        return CREATOR.createFromParcel(p);
695    }
696
697    public int describeContents() {
698        return 0;
699    }
700
701    public void writeToParcel(Parcel dest, int flags) {
702        acquireReference();
703        try {
704            dest.writeInt(mStartPos);
705            nativeWriteToParcel(mWindowPtr, dest);
706        } finally {
707            releaseReference();
708        }
709
710        if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
711            releaseReference();
712        }
713    }
714
715    @Override
716    protected void onAllReferencesReleased() {
717        dispose();
718    }
719
720    private static final LongSparseArray<Integer> sWindowToPidMap = new LongSparseArray<Integer>();
721
722    private void recordNewWindow(int pid, long window) {
723        synchronized (sWindowToPidMap) {
724            sWindowToPidMap.put(window, pid);
725            if (Log.isLoggable(STATS_TAG, Log.VERBOSE)) {
726                Log.i(STATS_TAG, "Created a new Cursor. " + printStats());
727            }
728        }
729    }
730
731    private void recordClosingOfWindow(long window) {
732        synchronized (sWindowToPidMap) {
733            if (sWindowToPidMap.size() == 0) {
734                // this means we are not in the ContentProvider.
735                return;
736            }
737            sWindowToPidMap.delete(window);
738        }
739    }
740
741    private String printStats() {
742        StringBuilder buff = new StringBuilder();
743        int myPid = Process.myPid();
744        int total = 0;
745        SparseIntArray pidCounts = new SparseIntArray();
746        synchronized (sWindowToPidMap) {
747            int size = sWindowToPidMap.size();
748            if (size == 0) {
749                // this means we are not in the ContentProvider.
750                return "";
751            }
752            for (int indx = 0; indx < size; indx++) {
753                int pid = sWindowToPidMap.valueAt(indx);
754                int value = pidCounts.get(pid);
755                pidCounts.put(pid, ++value);
756            }
757        }
758        int numPids = pidCounts.size();
759        for (int i = 0; i < numPids;i++) {
760            buff.append(" (# cursors opened by ");
761            int pid = pidCounts.keyAt(i);
762            if (pid == myPid) {
763                buff.append("this proc=");
764            } else {
765                buff.append("pid " + pid + "=");
766            }
767            int num = pidCounts.get(pid);
768            buff.append(num + ")");
769            total += num;
770        }
771        // limit the returned string size to 1000
772        String s = (buff.length() > 980) ? buff.substring(0, 980) : buff.toString();
773        return "# Open Cursors=" + total + s;
774    }
775
776    @Override
777    public String toString() {
778        return getName() + " {" + Long.toHexString(mWindowPtr) + "}";
779    }
780}
781