CursorBackedSuggestionCursor.java revision 883c1bf364e38c5b133afb55f8493a14b65f4dd4
13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/*
23e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project
33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License.
63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at
73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and
143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License.
153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */
163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox;
183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager;
203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.Cursor;
21fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.database.DataSetObserver;
223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.net.Uri;
233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log;
243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
25fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertpublic abstract class CursorBackedSuggestionCursor extends AbstractSuggestionCursor {
263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
27cef2c4c9d54f513babd74801dbed5cbf709b9b79Bjorn Bringert    private static final boolean DBG = false;
283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected static final String TAG = "QSB.CursorBackedSuggestionCursor";
293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
30883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert    public static final String SUGGEST_COLUMN_LOG_TYPE = "suggest_log_type";
31883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert
323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /** The suggestions, or {@code null} if the suggestions query failed. */
333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected final Cursor mCursor;
343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
35fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /** Column index of {@link SearchManager#SUGGEST_COLUMN_FORMAT} in @{link mCursor}. */
363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private final int mFormatCol;
373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
38fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /** Column index of {@link SearchManager#SUGGEST_COLUMN_TEXT_1} in @{link mCursor}. */
393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private final int mText1Col;
403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
41fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /** Column index of {@link SearchManager#SUGGEST_COLUMN_TEXT_2} in @{link mCursor}. */
423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private final int mText2Col;
433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
44fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /** Column index of {@link SearchManager#SUGGEST_COLUMN_ICON_1} in @{link mCursor}. */
453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private final int mIcon1Col;
463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
47fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /** Column index of {@link SearchManager#SUGGEST_COLUMN_ICON_1} in @{link mCursor}. */
483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private final int mIcon2Col;
493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
50fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /** Column index of {@link SearchManager#SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}
5194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney     * in @{link mCursor}.
5294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney     **/
5394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    private final int mRefreshSpinnerCol;
5494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney
553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /** True if this result has been closed. */
563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private boolean mClosed = false;
573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public CursorBackedSuggestionCursor(String userQuery, Cursor cursor) {
593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        super(userQuery);
603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mCursor = cursor;
613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mFormatCol = getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mText1Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mText2Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mIcon1Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mIcon2Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
6694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        mRefreshSpinnerCol = getColumnIndex(SearchManager.SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING);
673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
69fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public abstract Source getSuggestionSource();
703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
71fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public String getSuggestionLogType() {
72883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert        return getStringOrNull(SUGGEST_COLUMN_LOG_TYPE);
733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public void close() {
76185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        if (DBG) Log.d(TAG, "close()");
773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mClosed) {
78185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert            throw new IllegalStateException("Double close()");
793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        mClosed = true;
813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mCursor != null) {
827a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            try {
837a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert                mCursor.close();
847a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            } catch (RuntimeException ex) {
857a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert                // all operations on cross-process cursors can throw random exceptions
867a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert                Log.e(TAG, "close() failed, ", ex);
877a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            }
883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    @Override
923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void finalize() {
933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (!mClosed) {
943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            Log.e(TAG, "LEAK! Finalized without being closed: " + toString());
953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            close();
963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public int getCount() {
1003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mClosed) {
1013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            throw new IllegalStateException("getCount() after close()");
1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mCursor == null) return 0;
1047a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        try {
1057a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            return mCursor.getCount();
1067a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        } catch (RuntimeException ex) {
1077a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            // all operations on cross-process cursors can throw random exceptions
1087a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            Log.e(TAG, "getCount() failed, ", ex);
1097a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            return 0;
1107a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        }
1113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public void moveTo(int pos) {
1143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mClosed) {
1153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            throw new IllegalStateException("moveTo(" + pos + ") after close()");
1163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1177a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        try {
1187a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            if (!mCursor.moveToPosition(pos)) {
1197a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert                Log.e(TAG, "moveToPosition(" + pos + ") failed, count=" + getCount());
1207a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            }
1217a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        } catch (RuntimeException ex) {
1227a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            // all operations on cross-process cursors can throw random exceptions
1237a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            Log.e(TAG, "moveToPosition() failed, ", ex);
1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public int getPosition() {
1283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mClosed) {
1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            throw new IllegalStateException("getPosition after close()");
1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1317a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        try {
1327a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            return mCursor.getPosition();
1337a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        } catch (RuntimeException ex) {
1347a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            // all operations on cross-process cursors can throw random exceptions
1357a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            Log.e(TAG, "getPosition() failed, ", ex);
1367a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            return -1;
1377a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        }
1383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getShortcutId() {
1413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
1423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getSuggestionFormat() {
1453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(mFormatCol);
1463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getSuggestionText1() {
1493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(mText1Col);
1503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getSuggestionText2() {
1533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(mText2Col);
1543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getSuggestionIcon1() {
1573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(mIcon1Col);
1583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getSuggestionIcon2() {
1613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(mIcon2Col);
1623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
16494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    public boolean isSpinnerWhileRefreshing() {
16594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        return "true".equals(getStringOrNull(mRefreshSpinnerCol));
16694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    }
16794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney
1683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
1693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Gets the intent action for the current suggestion.
1703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
171fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public String getSuggestionIntentAction() {
17204a180b52fb4100a2f3747e795fb5d26e3207a4aBjorn Bringert        return getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
1733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
1763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Gets the query for the current suggestion.
1773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
178fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public String getSuggestionQuery() {
1793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(SearchManager.SUGGEST_COLUMN_QUERY);
1803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1821e938ea2f5edefab446b9562b316bc5dc72adebbBryan Mawhinney    public String getSuggestionIntentDataString() {
1833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         // use specific data if supplied, or default data if supplied
1843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         String data = getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_DATA);
1853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         if (data == null) {
186fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert             data = getSuggestionSource().getDefaultIntentData();
1873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         }
1883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         // then, if an ID was provided, append it.
1893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         if (data != null) {
1903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert             String id = getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
1913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert             if (id != null) {
1923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                 data = data + "/" + Uri.encode(id);
1933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert             }
1943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         }
1953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert         return data;
1963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     }
1973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
1993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * Gets the intent extra data for the current suggestion.
2003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
20194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    public String getSuggestionIntentExtraData() {
2023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
2033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
206fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the index of a column in {@link #mCursor} by name.
2073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     *
2083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * @return The index, or {@code -1} if the column was not found.
2093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
2103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected int getColumnIndex(String colName) {
2113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mCursor == null) return -1;
2127a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        try {
2137a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            return mCursor.getColumnIndex(colName);
2147a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        } catch (RuntimeException ex) {
2157a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            // all operations on cross-process cursors can throw random exceptions
2167a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            Log.e(TAG, "getColumnIndex() failed, ", ex);
2177a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            return -1;
2187a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        }
2193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
222fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the string value of a column in {@link #mCursor} by column index.
2233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     *
2243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * @param col Column index.
2253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * @return The string value, or {@code null}.
2263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
2273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected String getStringOrNull(int col) {
2283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mCursor == null) return null;
2293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (col == -1) {
2303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            return null;
2313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
2323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        try {
2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            return mCursor.getString(col);
2347a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert        } catch (RuntimeException ex) {
2357a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            // all operations on cross-process cursors can throw random exceptions
2367a1f40b4189a7435fe7177e759fde9fd2d032574Bjorn Bringert            Log.e(TAG, "getString() failed, ", ex);
2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            return null;
2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
2393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    /**
242fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the string value of a column in {@link #mCursor} by column name.
2433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     *
2443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * @param colName Column name.
2453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     * @return The string value, or {@code null}.
2463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert     */
2473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected String getStringOrNull(String colName) {
2483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        int col = getColumnIndex(colName);
2493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return getStringOrNull(col);
2503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private String makeKeyComponent(String str) {
2533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return str == null ? "" : str;
2543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
2563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    public String getSuggestionKey() {
2573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        String action = makeKeyComponent(getSuggestionIntentAction());
2583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        String data = makeKeyComponent(getSuggestionIntentDataString());
2593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        String query = makeKeyComponent(getSuggestionQuery());
2603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        // calculating accurate size of string builder avoids an allocation vs starting with
2613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        // the default size and having to expand.
2623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        int size = action.length() + 2 + data.length() + query.length();
2633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return new StringBuilder(size)
2643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                .append(action)
2653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                .append('#')
2663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                .append(data)
2673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                .append('#')
2683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                .append(query)
2693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert                .toString();
2703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
271fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
272fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public void registerDataSetObserver(DataSetObserver observer) {
273fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        // We don't watch Cursor-backed SuggestionCursors for changes
274fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
275fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
276fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public void unregisterDataSetObserver(DataSetObserver observer) {
277fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        // We don't watch Cursor-backed SuggestionCursors for changes
278fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
2793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert}
280