1c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang/*
2c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * Copyright (C) 2009 Google Inc.
3c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang *
4c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * Licensed under the Apache License, Version 2.0 (the "License");
5c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * you may not use this file except in compliance with the License.
6c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * You may obtain a copy of the License at
7c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang *
8c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang *      http://www.apache.org/licenses/LICENSE-2.0
9c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang *
10c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * Unless required by applicable law or agreed to in writing, software
11c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * distributed under the License is distributed on an "AS IS" BASIS,
12c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * See the License for the specific language governing permissions and
14c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang * limitations under the License.
15c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang */
16c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang
17c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huangpackage com.android.mms;
18c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang
19f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport java.util.ArrayList;
20f114492537753bc68640d4a0d403861387296bcbMark Wagner
21f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.app.SearchManager;
22f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.content.ContentResolver;
23f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.content.ContentValues;
24f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.content.Intent;
25f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.database.CharArrayBuffer;
26f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.database.ContentObserver;
27f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.database.CrossProcessCursor;
28f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.database.Cursor;
29f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.database.CursorWindow;
30f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.database.DataSetObserver;
31627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagnerimport android.database.sqlite.SQLiteException;
32f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.net.Uri;
33f114492537753bc68640d4a0d403861387296bcbMark Wagnerimport android.os.Bundle;
34c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagnerimport android.text.TextUtils;
35c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang
36c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang/**
37f114492537753bc68640d4a0d403861387296bcbMark Wagner * Suggestions provider for mms.  Queries the "words" table to provide possible word suggestions.
38c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang */
39f114492537753bc68640d4a0d403861387296bcbMark Wagnerpublic class SuggestionsProvider extends android.content.ContentProvider {
40c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang
41c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang    final static String AUTHORITY = "com.android.mms.SuggestionsProvider";
42f114492537753bc68640d4a0d403861387296bcbMark Wagner//    final static int MODE = DATABASE_MODE_QUERIES + DATABASE_MODE_2LINES;
43c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang
44c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang    public SuggestionsProvider() {
45c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang        super();
46f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
47f114492537753bc68640d4a0d403861387296bcbMark Wagner
48f114492537753bc68640d4a0d403861387296bcbMark Wagner    @Override
49f114492537753bc68640d4a0d403861387296bcbMark Wagner    public int delete(Uri uri, String selection, String[] selectionArgs) {
50f114492537753bc68640d4a0d403861387296bcbMark Wagner        return 0;
51f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
52f114492537753bc68640d4a0d403861387296bcbMark Wagner
53f114492537753bc68640d4a0d403861387296bcbMark Wagner    @Override
54f114492537753bc68640d4a0d403861387296bcbMark Wagner    public String getType(Uri uri) {
55f114492537753bc68640d4a0d403861387296bcbMark Wagner        return null;
56f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
57f114492537753bc68640d4a0d403861387296bcbMark Wagner
58f114492537753bc68640d4a0d403861387296bcbMark Wagner    @Override
59f114492537753bc68640d4a0d403861387296bcbMark Wagner    public Uri insert(Uri uri, ContentValues values) {
60f114492537753bc68640d4a0d403861387296bcbMark Wagner        return null;
61f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
62f114492537753bc68640d4a0d403861387296bcbMark Wagner
63f114492537753bc68640d4a0d403861387296bcbMark Wagner    @Override
64f114492537753bc68640d4a0d403861387296bcbMark Wagner    public boolean onCreate() {
65f114492537753bc68640d4a0d403861387296bcbMark Wagner        return true;
66f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
67f114492537753bc68640d4a0d403861387296bcbMark Wagner
68f114492537753bc68640d4a0d403861387296bcbMark Wagner    @Override
69f114492537753bc68640d4a0d403861387296bcbMark Wagner    public Cursor query(Uri uri, String[] projection, String selection,
70f114492537753bc68640d4a0d403861387296bcbMark Wagner            String[] selectionArgs, String sortOrder) {
71f114492537753bc68640d4a0d403861387296bcbMark Wagner        Uri u = Uri.parse(String.format(
72f114492537753bc68640d4a0d403861387296bcbMark Wagner                "content://mms-sms/searchSuggest?pattern=%s",
73f114492537753bc68640d4a0d403861387296bcbMark Wagner                selectionArgs[0]));
74f114492537753bc68640d4a0d403861387296bcbMark Wagner        Cursor c = getContext().getContentResolver().query(
75f114492537753bc68640d4a0d403861387296bcbMark Wagner                u,
76f114492537753bc68640d4a0d403861387296bcbMark Wagner                null,
77f114492537753bc68640d4a0d403861387296bcbMark Wagner                null,
78f114492537753bc68640d4a0d403861387296bcbMark Wagner                null,
79f114492537753bc68640d4a0d403861387296bcbMark Wagner                null);
80f114492537753bc68640d4a0d403861387296bcbMark Wagner
81f114492537753bc68640d4a0d403861387296bcbMark Wagner        return new SuggestionsCursor(c, selectionArgs[0]);
82f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
83f114492537753bc68640d4a0d403861387296bcbMark Wagner
84f114492537753bc68640d4a0d403861387296bcbMark Wagner    @Override
85f114492537753bc68640d4a0d403861387296bcbMark Wagner    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
86f114492537753bc68640d4a0d403861387296bcbMark Wagner        return 0;
87f114492537753bc68640d4a0d403861387296bcbMark Wagner    }
88f114492537753bc68640d4a0d403861387296bcbMark Wagner
89f114492537753bc68640d4a0d403861387296bcbMark Wagner    private class SuggestionsCursor implements CrossProcessCursor {
90f114492537753bc68640d4a0d403861387296bcbMark Wagner        Cursor mDatabaseCursor;
91f114492537753bc68640d4a0d403861387296bcbMark Wagner        int mColumnCount;
92f114492537753bc68640d4a0d403861387296bcbMark Wagner        int mCurrentRow;
93f114492537753bc68640d4a0d403861387296bcbMark Wagner        ArrayList<Row> mRows = new ArrayList<Row>();
94c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner        String mQuery;
95f114492537753bc68640d4a0d403861387296bcbMark Wagner
96f114492537753bc68640d4a0d403861387296bcbMark Wagner        public SuggestionsCursor(Cursor cursor, String query) {
97f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor = cursor;
98c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner            mQuery = query;
99f114492537753bc68640d4a0d403861387296bcbMark Wagner
100f114492537753bc68640d4a0d403861387296bcbMark Wagner            mColumnCount = cursor.getColumnCount();
101627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner            try {
102627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner                computeRows();
103627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner            } catch (SQLiteException ex) {
104627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner                // This can happen if the user enters -n (anything starting with -).
105627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner                // sqlite3/fts3 can't handle it.  Google for "logic error or missing database fts3"
106627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner                // for commentary on it.
107627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner                mRows.clear(); // assume no results
108627ffa0f154c4ed9ac5071af5f5fb2903234665eMark Wagner            }
109f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
110f114492537753bc68640d4a0d403861387296bcbMark Wagner
111f114492537753bc68640d4a0d403861387296bcbMark Wagner        public int getCount() {
112f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mRows.size();
113f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
114f114492537753bc68640d4a0d403861387296bcbMark Wagner
115f114492537753bc68640d4a0d403861387296bcbMark Wagner        private class Row {
116c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner            private String mSnippet;
117c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner            private int mRowNumber;
118c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner
119c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner            public Row(int row, String snippet) {
120c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                mSnippet = snippet.trim();
121f114492537753bc68640d4a0d403861387296bcbMark Wagner                mRowNumber = row;
122f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
123c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner            public String getSnippet() {
124c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                return mSnippet;
125f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
126f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
127f114492537753bc68640d4a0d403861387296bcbMark Wagner
128c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner        /*
129c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner         * Compute rows for rows in the cursor.  The cursor can contain duplicates which
130c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner         * are filtered out in the while loop.  Using DISTINCT on the result of the
131c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner         * FTS3 snippet function does not work so we do it here in the code.
132c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner         */
133f114492537753bc68640d4a0d403861387296bcbMark Wagner        private void computeRows() {
134c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner            int snippetColumn = mDatabaseCursor.getColumnIndex("snippet");
135f114492537753bc68640d4a0d403861387296bcbMark Wagner
136f114492537753bc68640d4a0d403861387296bcbMark Wagner            int count = mDatabaseCursor.getCount();
137c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner            String previousSnippet = null;
138c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner
139f114492537753bc68640d4a0d403861387296bcbMark Wagner            for (int i = 0; i < count; i++) {
140f114492537753bc68640d4a0d403861387296bcbMark Wagner                mDatabaseCursor.moveToPosition(i);
141c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                String snippet = mDatabaseCursor.getString(snippetColumn);
142c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                if (!TextUtils.equals(previousSnippet, snippet)) {
143c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                    mRows.add(new Row(i, snippet));
144c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                    previousSnippet = snippet;
145c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                }
146f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
147f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
148f114492537753bc68640d4a0d403861387296bcbMark Wagner
149f114492537753bc68640d4a0d403861387296bcbMark Wagner        private int [] computeOffsets(String offsetsString) {
150f114492537753bc68640d4a0d403861387296bcbMark Wagner            String [] vals = offsetsString.split(" ");
151f114492537753bc68640d4a0d403861387296bcbMark Wagner
152f114492537753bc68640d4a0d403861387296bcbMark Wagner            int [] retvals = new int[vals.length];
153f114492537753bc68640d4a0d403861387296bcbMark Wagner            for (int i = retvals.length-1; i >= 0; i--) {
154f114492537753bc68640d4a0d403861387296bcbMark Wagner                retvals[i] = Integer.parseInt(vals[i]);
155f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
156f114492537753bc68640d4a0d403861387296bcbMark Wagner            return retvals;
157f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
158f114492537753bc68640d4a0d403861387296bcbMark Wagner
159f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void fillWindow(int position, CursorWindow window) {
160f114492537753bc68640d4a0d403861387296bcbMark Wagner            int count = getCount();
161f114492537753bc68640d4a0d403861387296bcbMark Wagner            if (position < 0 || position > count + 1) {
162f114492537753bc68640d4a0d403861387296bcbMark Wagner                return;
163f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
164f114492537753bc68640d4a0d403861387296bcbMark Wagner            window.acquireReference();
165f114492537753bc68640d4a0d403861387296bcbMark Wagner            try {
166f114492537753bc68640d4a0d403861387296bcbMark Wagner                int oldpos = getPosition();
167f114492537753bc68640d4a0d403861387296bcbMark Wagner                int pos = position;
168f114492537753bc68640d4a0d403861387296bcbMark Wagner                window.clear();
169f114492537753bc68640d4a0d403861387296bcbMark Wagner                window.setStartPosition(position);
170f114492537753bc68640d4a0d403861387296bcbMark Wagner                int columnNum = getColumnCount();
171f114492537753bc68640d4a0d403861387296bcbMark Wagner                window.setNumColumns(columnNum);
172f114492537753bc68640d4a0d403861387296bcbMark Wagner                while (moveToPosition(pos) && window.allocRow()) {
173f114492537753bc68640d4a0d403861387296bcbMark Wagner                    for (int i = 0; i < columnNum; i++) {
174f114492537753bc68640d4a0d403861387296bcbMark Wagner                        String field = getString(i);
175f114492537753bc68640d4a0d403861387296bcbMark Wagner                        if (field != null) {
176f114492537753bc68640d4a0d403861387296bcbMark Wagner                            if (!window.putString(field, pos, i)) {
177f114492537753bc68640d4a0d403861387296bcbMark Wagner                                window.freeLastRow();
178f114492537753bc68640d4a0d403861387296bcbMark Wagner                                break;
179f114492537753bc68640d4a0d403861387296bcbMark Wagner                            }
180f114492537753bc68640d4a0d403861387296bcbMark Wagner                        } else {
181f114492537753bc68640d4a0d403861387296bcbMark Wagner                            if (!window.putNull(pos, i)) {
182f114492537753bc68640d4a0d403861387296bcbMark Wagner                                window.freeLastRow();
183f114492537753bc68640d4a0d403861387296bcbMark Wagner                                break;
184f114492537753bc68640d4a0d403861387296bcbMark Wagner                            }
185f114492537753bc68640d4a0d403861387296bcbMark Wagner                        }
186f114492537753bc68640d4a0d403861387296bcbMark Wagner                    }
187f114492537753bc68640d4a0d403861387296bcbMark Wagner                    ++pos;
188f114492537753bc68640d4a0d403861387296bcbMark Wagner                }
189f114492537753bc68640d4a0d403861387296bcbMark Wagner                moveToPosition(oldpos);
190f114492537753bc68640d4a0d403861387296bcbMark Wagner            } catch (IllegalStateException e){
191f114492537753bc68640d4a0d403861387296bcbMark Wagner                // simply ignore it
192f114492537753bc68640d4a0d403861387296bcbMark Wagner            } finally {
193f114492537753bc68640d4a0d403861387296bcbMark Wagner                window.releaseReference();
194f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
195f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
196f114492537753bc68640d4a0d403861387296bcbMark Wagner
197f114492537753bc68640d4a0d403861387296bcbMark Wagner        public CursorWindow getWindow() {
1982d869da0b1dc4bb09d204e4845ef24db48a24b52Mark Wagner            return null;
199f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
200f114492537753bc68640d4a0d403861387296bcbMark Wagner
201f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean onMove(int oldPosition, int newPosition) {
202f114492537753bc68640d4a0d403861387296bcbMark Wagner            return ((CrossProcessCursor)mDatabaseCursor).onMove(oldPosition, newPosition);
203f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
204f114492537753bc68640d4a0d403861387296bcbMark Wagner
205f114492537753bc68640d4a0d403861387296bcbMark Wagner        /*
206f114492537753bc68640d4a0d403861387296bcbMark Wagner         * These "virtual columns" are columns which don't exist in the underlying
207f114492537753bc68640d4a0d403861387296bcbMark Wagner         * database cursor but are exported by this cursor.  For example, we compute
208f114492537753bc68640d4a0d403861387296bcbMark Wagner         * a "word" by taking the substring of the full row text in the words table
209f114492537753bc68640d4a0d403861387296bcbMark Wagner         * using the provided offsets.
210f114492537753bc68640d4a0d403861387296bcbMark Wagner         */
211f114492537753bc68640d4a0d403861387296bcbMark Wagner        private String [] mVirtualColumns = new String [] {
212f114492537753bc68640d4a0d403861387296bcbMark Wagner                SearchManager.SUGGEST_COLUMN_INTENT_DATA,
213f114492537753bc68640d4a0d403861387296bcbMark Wagner                SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
214f114492537753bc68640d4a0d403861387296bcbMark Wagner                SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
215c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner                SearchManager.SUGGEST_COLUMN_TEXT_1,
216f114492537753bc68640d4a0d403861387296bcbMark Wagner            };
217f114492537753bc68640d4a0d403861387296bcbMark Wagner
218f114492537753bc68640d4a0d403861387296bcbMark Wagner        // Cursor column offsets for the above virtual columns.
219f114492537753bc68640d4a0d403861387296bcbMark Wagner        // These columns exist after the natural columns in the
220f114492537753bc68640d4a0d403861387296bcbMark Wagner        // database cursor.  So, for example, the column called
221f114492537753bc68640d4a0d403861387296bcbMark Wagner        // SUGGEST_COLUMN_TEXT_1 comes 3 after mDatabaseCursor.getColumnCount().
222f114492537753bc68640d4a0d403861387296bcbMark Wagner        private final int INTENT_DATA_COLUMN = 0;
223f114492537753bc68640d4a0d403861387296bcbMark Wagner        private final int INTENT_ACTION_COLUMN = 1;
224f114492537753bc68640d4a0d403861387296bcbMark Wagner        private final int INTENT_EXTRA_DATA_COLUMN = 2;
225f114492537753bc68640d4a0d403861387296bcbMark Wagner        private final int INTENT_TEXT_COLUMN = 3;
226f114492537753bc68640d4a0d403861387296bcbMark Wagner
227f114492537753bc68640d4a0d403861387296bcbMark Wagner
228f114492537753bc68640d4a0d403861387296bcbMark Wagner        public int getColumnCount() {
229f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mColumnCount + mVirtualColumns.length;
230f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
231f114492537753bc68640d4a0d403861387296bcbMark Wagner
232f114492537753bc68640d4a0d403861387296bcbMark Wagner        public int getColumnIndex(String columnName) {
233f114492537753bc68640d4a0d403861387296bcbMark Wagner            for (int i = 0; i < mVirtualColumns.length; i++) {
234f114492537753bc68640d4a0d403861387296bcbMark Wagner                if (mVirtualColumns[i].equals(columnName)) {
235f114492537753bc68640d4a0d403861387296bcbMark Wagner                    return mColumnCount + i;
236f114492537753bc68640d4a0d403861387296bcbMark Wagner                }
237f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
238f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mDatabaseCursor.getColumnIndex(columnName);
239f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
240f114492537753bc68640d4a0d403861387296bcbMark Wagner
241f114492537753bc68640d4a0d403861387296bcbMark Wagner        public String [] getColumnNames() {
242f114492537753bc68640d4a0d403861387296bcbMark Wagner            String [] x = mDatabaseCursor.getColumnNames();
243f114492537753bc68640d4a0d403861387296bcbMark Wagner            String [] y = new String [x.length + mVirtualColumns.length];
244f114492537753bc68640d4a0d403861387296bcbMark Wagner
245f114492537753bc68640d4a0d403861387296bcbMark Wagner            for (int i = 0; i < x.length; i++) {
246f114492537753bc68640d4a0d403861387296bcbMark Wagner                y[i] = x[i];
247f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
248f114492537753bc68640d4a0d403861387296bcbMark Wagner
249f114492537753bc68640d4a0d403861387296bcbMark Wagner            for (int i = 0; i < mVirtualColumns.length; i++) {
250f114492537753bc68640d4a0d403861387296bcbMark Wagner                y[x.length + i] = mVirtualColumns[i];
251f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
252f114492537753bc68640d4a0d403861387296bcbMark Wagner
253f114492537753bc68640d4a0d403861387296bcbMark Wagner            return y;
254f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
255f114492537753bc68640d4a0d403861387296bcbMark Wagner
256f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean moveToPosition(int position) {
257f114492537753bc68640d4a0d403861387296bcbMark Wagner            if (position >= 0 && position < mRows.size()) {
258f114492537753bc68640d4a0d403861387296bcbMark Wagner                mCurrentRow = position;
259f114492537753bc68640d4a0d403861387296bcbMark Wagner                mDatabaseCursor.moveToPosition(mRows.get(position).mRowNumber);
260f114492537753bc68640d4a0d403861387296bcbMark Wagner                return true;
261f114492537753bc68640d4a0d403861387296bcbMark Wagner            } else {
262f114492537753bc68640d4a0d403861387296bcbMark Wagner                return false;
263f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
264f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
265f114492537753bc68640d4a0d403861387296bcbMark Wagner
266f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean move(int offset) {
267f114492537753bc68640d4a0d403861387296bcbMark Wagner            return moveToPosition(mCurrentRow + offset);
268f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
269f114492537753bc68640d4a0d403861387296bcbMark Wagner
270f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean moveToFirst() {
271f114492537753bc68640d4a0d403861387296bcbMark Wagner            return moveToPosition(0);
272f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
273f114492537753bc68640d4a0d403861387296bcbMark Wagner
274f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean moveToLast() {
275f114492537753bc68640d4a0d403861387296bcbMark Wagner            return moveToPosition(mRows.size() - 1);
276f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
277f114492537753bc68640d4a0d403861387296bcbMark Wagner
278f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean moveToNext() {
279f114492537753bc68640d4a0d403861387296bcbMark Wagner            return moveToPosition(mCurrentRow + 1);
280f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
281f114492537753bc68640d4a0d403861387296bcbMark Wagner
282f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean moveToPrevious() {
283f114492537753bc68640d4a0d403861387296bcbMark Wagner            return moveToPosition(mCurrentRow - 1);
284f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
285f114492537753bc68640d4a0d403861387296bcbMark Wagner
286f114492537753bc68640d4a0d403861387296bcbMark Wagner        public String getString(int column) {
287c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner            // if we're returning one of the columns in the underlying database column
288c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner            // then do so here
289f114492537753bc68640d4a0d403861387296bcbMark Wagner            if (column < mColumnCount) {
290f114492537753bc68640d4a0d403861387296bcbMark Wagner                return mDatabaseCursor.getString(column);
291f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
292f114492537753bc68640d4a0d403861387296bcbMark Wagner
293c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner            // otherwise we're returning one of the synthetic columns.
294c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner            // the constants like INTENT_DATA_COLUMN are offsets relative to
295c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner            // mColumnCount.
296f114492537753bc68640d4a0d403861387296bcbMark Wagner            Row row = mRows.get(mCurrentRow);
297f114492537753bc68640d4a0d403861387296bcbMark Wagner            switch (column - mColumnCount) {
298f114492537753bc68640d4a0d403861387296bcbMark Wagner                case INTENT_DATA_COLUMN:
299c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner                    Uri.Builder b = Uri.parse("content://mms-sms/search").buildUpon();
300c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                    b = b.appendQueryParameter("pattern", row.getSnippet());
301c27b5dc04d496dc4176bea034498bec4e68045faMark Wagner                    Uri u = b.build();
302f114492537753bc68640d4a0d403861387296bcbMark Wagner                    return u.toString();
303f114492537753bc68640d4a0d403861387296bcbMark Wagner                case INTENT_ACTION_COLUMN:
304f114492537753bc68640d4a0d403861387296bcbMark Wagner                    return Intent.ACTION_SEARCH;
305f114492537753bc68640d4a0d403861387296bcbMark Wagner                case INTENT_EXTRA_DATA_COLUMN:
306c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                    return row.getSnippet();
307f114492537753bc68640d4a0d403861387296bcbMark Wagner                case INTENT_TEXT_COLUMN:
308c6ec8c45d3c414aca13a0298ccc5bfa6ee871aa1Mark Wagner                    return row.getSnippet();
309f114492537753bc68640d4a0d403861387296bcbMark Wagner                default:
310f114492537753bc68640d4a0d403861387296bcbMark Wagner                    return null;
311f114492537753bc68640d4a0d403861387296bcbMark Wagner            }
312f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
313f114492537753bc68640d4a0d403861387296bcbMark Wagner
314f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void close() {
315f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.close();
316f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
317f114492537753bc68640d4a0d403861387296bcbMark Wagner
318f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
319f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.copyStringToBuffer(columnIndex, buffer);
320f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
321f114492537753bc68640d4a0d403861387296bcbMark Wagner
322f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void deactivate() {
323f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.deactivate();
324f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
325f114492537753bc68640d4a0d403861387296bcbMark Wagner
326f114492537753bc68640d4a0d403861387296bcbMark Wagner        public byte[] getBlob(int columnIndex) {
327f114492537753bc68640d4a0d403861387296bcbMark Wagner            return null;
328f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
329f114492537753bc68640d4a0d403861387296bcbMark Wagner
330f114492537753bc68640d4a0d403861387296bcbMark Wagner        public int getColumnIndexOrThrow(String columnName)
331f114492537753bc68640d4a0d403861387296bcbMark Wagner                throws IllegalArgumentException {
332f114492537753bc68640d4a0d403861387296bcbMark Wagner            return 0;
333f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
334f114492537753bc68640d4a0d403861387296bcbMark Wagner
335f114492537753bc68640d4a0d403861387296bcbMark Wagner        public String getColumnName(int columnIndex) {
336f114492537753bc68640d4a0d403861387296bcbMark Wagner            return null;
337f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
338f114492537753bc68640d4a0d403861387296bcbMark Wagner
339f114492537753bc68640d4a0d403861387296bcbMark Wagner        public double getDouble(int columnIndex) {
340f114492537753bc68640d4a0d403861387296bcbMark Wagner            return 0;
341f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
342f114492537753bc68640d4a0d403861387296bcbMark Wagner
343f114492537753bc68640d4a0d403861387296bcbMark Wagner        public Bundle getExtras() {
344903d973ca7093ce0574feca4f58e114a0c11e099Mark Wagner            return Bundle.EMPTY;
345f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
346f114492537753bc68640d4a0d403861387296bcbMark Wagner
347f114492537753bc68640d4a0d403861387296bcbMark Wagner        public float getFloat(int columnIndex) {
348f114492537753bc68640d4a0d403861387296bcbMark Wagner            return 0;
349f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
350f114492537753bc68640d4a0d403861387296bcbMark Wagner
351f114492537753bc68640d4a0d403861387296bcbMark Wagner        public int getInt(int columnIndex) {
352f114492537753bc68640d4a0d403861387296bcbMark Wagner            return 0;
353f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
354f114492537753bc68640d4a0d403861387296bcbMark Wagner
355f114492537753bc68640d4a0d403861387296bcbMark Wagner        public long getLong(int columnIndex) {
356f114492537753bc68640d4a0d403861387296bcbMark Wagner            return 0;
357f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
358f114492537753bc68640d4a0d403861387296bcbMark Wagner
359f114492537753bc68640d4a0d403861387296bcbMark Wagner        public int getPosition() {
360f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mCurrentRow;
361f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
362f114492537753bc68640d4a0d403861387296bcbMark Wagner
363f114492537753bc68640d4a0d403861387296bcbMark Wagner        public short getShort(int columnIndex) {
364f114492537753bc68640d4a0d403861387296bcbMark Wagner            return 0;
365f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
366f114492537753bc68640d4a0d403861387296bcbMark Wagner
367f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean getWantsAllOnMoveCalls() {
368f114492537753bc68640d4a0d403861387296bcbMark Wagner            return false;
369f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
370f114492537753bc68640d4a0d403861387296bcbMark Wagner
371f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean isAfterLast() {
372f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mCurrentRow >= mRows.size();
373f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
374f114492537753bc68640d4a0d403861387296bcbMark Wagner
375f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean isBeforeFirst() {
376f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mCurrentRow < 0;
377f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
378f114492537753bc68640d4a0d403861387296bcbMark Wagner
379f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean isClosed() {
380f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mDatabaseCursor.isClosed();
381f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
382f114492537753bc68640d4a0d403861387296bcbMark Wagner
383f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean isFirst() {
384f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mCurrentRow == 0;
385f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
386f114492537753bc68640d4a0d403861387296bcbMark Wagner
387f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean isLast() {
388f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mCurrentRow == mRows.size() - 1;
389f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
39002c982b20c915fe8488d6a78946523a42a705170Vasu Nori
39102c982b20c915fe8488d6a78946523a42a705170Vasu Nori        public int getType(int columnIndex) {
39202c982b20c915fe8488d6a78946523a42a705170Vasu Nori            throw new UnsupportedOperationException();  // TODO revisit
39302c982b20c915fe8488d6a78946523a42a705170Vasu Nori        }
394f114492537753bc68640d4a0d403861387296bcbMark Wagner
395f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean isNull(int columnIndex) {
396f114492537753bc68640d4a0d403861387296bcbMark Wagner            return false;  // TODO revisit
397f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
398f114492537753bc68640d4a0d403861387296bcbMark Wagner
399f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void registerContentObserver(ContentObserver observer) {
400f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.registerContentObserver(observer);
401f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
402f114492537753bc68640d4a0d403861387296bcbMark Wagner
403f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void registerDataSetObserver(DataSetObserver observer) {
404f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.registerDataSetObserver(observer);
405f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
406f114492537753bc68640d4a0d403861387296bcbMark Wagner
407f114492537753bc68640d4a0d403861387296bcbMark Wagner        public boolean requery() {
408f114492537753bc68640d4a0d403861387296bcbMark Wagner            return false;
409f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
410f114492537753bc68640d4a0d403861387296bcbMark Wagner
411f114492537753bc68640d4a0d403861387296bcbMark Wagner        public Bundle respond(Bundle extras) {
412f114492537753bc68640d4a0d403861387296bcbMark Wagner            return mDatabaseCursor.respond(extras);
413f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
414f114492537753bc68640d4a0d403861387296bcbMark Wagner
415f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void setNotificationUri(ContentResolver cr, Uri uri) {
416f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.setNotificationUri(cr, uri);
417f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
418f114492537753bc68640d4a0d403861387296bcbMark Wagner
419469a45a0a453140087516b6fe32753ae19a194cbDianne Hackborn        public Uri getNotificationUri() {
420469a45a0a453140087516b6fe32753ae19a194cbDianne Hackborn            return mDatabaseCursor.getNotificationUri();
421469a45a0a453140087516b6fe32753ae19a194cbDianne Hackborn        }
422469a45a0a453140087516b6fe32753ae19a194cbDianne Hackborn
423f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void unregisterContentObserver(ContentObserver observer) {
424f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.unregisterContentObserver(observer);
425f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
426f114492537753bc68640d4a0d403861387296bcbMark Wagner
427f114492537753bc68640d4a0d403861387296bcbMark Wagner        public void unregisterDataSetObserver(DataSetObserver observer) {
428f114492537753bc68640d4a0d403861387296bcbMark Wagner            mDatabaseCursor.unregisterDataSetObserver(observer);
429f114492537753bc68640d4a0d403861387296bcbMark Wagner        }
430c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang    }
431c0c4420878eff51ce95cda9062cb3a1da6b671c8Wei Huang}
432