CursorBackedSuggestionCursor.java revision 94e8a2be78530170f50e7895a558bf8011bbf8e8
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.content.ComponentName; 213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Context; 223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Intent; 233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.Cursor; 243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.Rect; 253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.net.Uri; 263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Bundle; 2794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinneyimport android.os.Looper; 283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.view.KeyEvent; 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.net.URISyntaxException; 323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic abstract class CursorBackedSuggestionCursor extends AbstractSourceSuggestionCursor { 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public static final String SUGGEST_COLUMN_SECONDARY_INTENT = "suggestion_secondary_intent"; 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public static final String TARGET_RECT_KEY = "target_rect"; 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 38cef2c4c9d54f513babd74801dbed5cbf709b9b79Bjorn Bringert private static final boolean DBG = false; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected static final String TAG = "QSB.CursorBackedSuggestionCursor"; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** The suggestions, or {@code null} if the suggestions query failed. */ 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected final Cursor mCursor; 433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Column index of {@link SearchManager.SUGGEST_COLUMN_FORMAT} in @{link mCursor}. */ 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final int mFormatCol; 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Column index of {@link SearchManager.SUGGEST_COLUMN_TEXT_1} in @{link mCursor}. */ 483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final int mText1Col; 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Column index of {@link SearchManager.SUGGEST_COLUMN_TEXT_2} in @{link mCursor}. */ 513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final int mText2Col; 523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Column index of {@link SearchManager.SUGGEST_COLUMN_ICON_1} in @{link mCursor}. */ 543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final int mIcon1Col; 553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** Column index of {@link SearchManager.SUGGEST_COLUMN_ICON_1} in @{link mCursor}. */ 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final int mIcon2Col; 583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney /** Column index of {@link SearchManager.SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING} 6094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney * in @{link mCursor}. 6194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney **/ 6294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney private final int mRefreshSpinnerCol; 6394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** True if this result has been closed. */ 653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private boolean mClosed = false; 663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public CursorBackedSuggestionCursor(String userQuery, Cursor cursor) { 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert super(userQuery); 693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mCursor = cursor; 703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mFormatCol = getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT); 713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mText1Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); 723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mText2Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); 733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mIcon1Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); 743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mIcon2Col = getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); 7594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney mRefreshSpinnerCol = getColumnIndex(SearchManager.SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING); 763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected String getDefaultIntentAction() { 793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getSource().getDefaultIntentAction(); 803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected String getDefaultIntentData() { 833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getSource().getDefaultIntentData(); 843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected boolean shouldRewriteQueryFromData() { 873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getSource().shouldRewriteQueryFromData(); 883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected boolean shouldRewriteQueryFromText() { 913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getSource().shouldRewriteQueryFromText(); 923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean isFailed() { 953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mCursor == null; 963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void close() { 99185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert if (DBG) Log.d(TAG, "close()"); 1003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 101185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert throw new IllegalStateException("Double close()"); 1023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mClosed = true; 1043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mCursor != null) { 1053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: all operations on cross-process cursors can throw random exceptions 1063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mCursor.close(); 1073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 1113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected void finalize() { 1123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (!mClosed) { 1133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.e(TAG, "LEAK! Finalized without being closed: " + toString()); 1143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert close(); 1153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public int getCount() { 1193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 1203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new IllegalStateException("getCount() after close()"); 1213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mCursor == null) return 0; 1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: all operations on cross-process cursors can throw random exceptions 1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mCursor.getCount(); 1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public void moveTo(int pos) { 1283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new IllegalStateException("moveTo(" + pos + ") after close()"); 1303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: all operations on cross-process cursors can throw random exceptions 1323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mCursor == null || pos < 0 || pos >= mCursor.getCount()) { 1333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new IndexOutOfBoundsException(pos + ", count=" + getCount()); 1343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: all operations on cross-process cursors can throw random exceptions 1363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mCursor.moveToPosition(pos); 1373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public int getPosition() { 1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mClosed) { 1413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throw new IllegalStateException("getPosition after close()"); 1423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mCursor.getPosition(); 1443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionDisplayQuery() { 1473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = getSuggestionQuery(); 1483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (query != null) { 1493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return query; 1503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (shouldRewriteQueryFromData()) { 1523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String data = getSuggestionIntentDataString(); 1533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (data != null) { 1543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return data; 1553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (shouldRewriteQueryFromText()) { 1583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String text1 = getSuggestionText1(); 1593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (text1 != null) { 1603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return text1; 1613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 1643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getShortcutId() { 1673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID); 1683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionFormat() { 1713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(mFormatCol); 1723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionText1() { 1753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(mText1Col); 1763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionText2() { 1793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(mText2Col); 1803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionIcon1() { 1833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(mIcon1Col); 1843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionIcon2() { 1873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(mIcon2Col); 1883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 19094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney public boolean isSpinnerWhileRefreshing() { 19194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return "true".equals(getStringOrNull(mRefreshSpinnerCol)); 19294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 19394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 1943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Intent getSuggestionIntent(Context context, Bundle appSearchData, 1953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int actionKey, String actionMsg) { 1963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String action = getSuggestionIntentAction(); 1973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Uri data = getSuggestionIntentData(); 1983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = getSuggestionQuery(); 1993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String userQuery = getUserQuery(); 2003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String extraData = getSuggestionIntentExtraData(); 2013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Now build the Intent 2033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Intent intent = new Intent(action); 2043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // We need CLEAR_TOP to avoid reusing an old task that has other activities 2063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // on top of the one we want. 2073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 2083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (data != null) { 2093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.setData(data); 2103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.USER_QUERY, userQuery); 2123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (query != null) { 2133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.QUERY, query); 2143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (extraData != null) { 2163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); 2173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (appSearchData != null) { 2193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.APP_DATA, appSearchData); 2203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { 2223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.ACTION_KEY, actionKey); 2233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.ACTION_MSG, actionMsg); 2243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: Use this to tell sources this comes form global search 2263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // The constants are currently hidden. 2273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // intent.putExtra(SearchManager.SEARCH_MODE, 2283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // SearchManager.MODE_GLOBAL_SEARCH_SUGGESTION); 2293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.setComponent(getSuggestionIntentComponent(context, intent)); 2303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return intent; 2313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Intent getSecondarySuggestionIntent(Context context, Bundle appSearchData, Rect target) { 2343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String intentString = getStringOrNull(SUGGEST_COLUMN_SECONDARY_INTENT); 2353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (intentString != null) { 2363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Intent intent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME); 2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (appSearchData != null) { 2393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(SearchManager.APP_DATA, appSearchData); 2403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: Do we need to pass action keys? 2423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: Should we try to use defaults such as getDefaultIntentData? 2433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.putExtra(TARGET_RECT_KEY, target); 2443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.setComponent(getSuggestionIntentComponent(context, intent)); 2453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return intent; 2463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (URISyntaxException e) { 2473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.w(TAG, "Unable to parse secondary intent " + intentString); 2483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 2513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 2543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Updates the intent with the component to which intents created 2553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * from the current suggestion should be sent. 2563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 2573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected ComponentName getSuggestionIntentComponent(Context context, Intent intent) { 2583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert ComponentName component = getSourceComponentName(); 2593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Limit intent resolution to the source package. 2603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert intent.setPackage(component.getPackageName()); 2613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert ComponentName resolvedComponent = intent.resolveActivity(context.getPackageManager()); 2623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (resolvedComponent != null) { 2633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // It's ok if the intent resolves to an activity in the same 2643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // package as component. We set the component explicitly to 2653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // avoid having to re-resolve, and to prevent race conditions. 2663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return resolvedComponent; 2673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { 2683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return component; 2693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean hasSecondaryIntent() { 2733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(SUGGEST_COLUMN_SECONDARY_INTENT) != null; 2743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 276782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public String getActionKeyMsg(int keyCode) { 277782dd228e78e9294692d639597f96c26283968bbBjorn Bringert String result = null; 278782dd228e78e9294692d639597f96c26283968bbBjorn Bringert String column = getSource().getSuggestActionMsgColumn(keyCode); 279782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (column != null) { 280782dd228e78e9294692d639597f96c26283968bbBjorn Bringert result = getStringOrNull(column); 281782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 282782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // If the cursor didn't give us a message, see if there's a single message defined 283782dd228e78e9294692d639597f96c26283968bbBjorn Bringert // for the actionkey (for all suggestions) 284782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (result == null) { 285782dd228e78e9294692d639597f96c26283968bbBjorn Bringert result = getSource().getSuggestActionMsg(keyCode); 286782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 287782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return result; 288782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 289782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 2903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 2913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the intent action for the current suggestion. 2923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 2933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected String getSuggestionIntentAction() { 2943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // use specific action if supplied, or default action if supplied, or fixed default 2953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String action = getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_ACTION); 2963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (action == null) { 2973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert action = getDefaultIntentAction(); 2983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (action == null) { 2993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert action = Intent.ACTION_SEARCH; 3003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return action; 3033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the query for the current suggestion. 3073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected String getSuggestionQuery() { 3093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(SearchManager.SUGGEST_COLUMN_QUERY); 3103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private String getSuggestionIntentDataString() { 3133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // use specific data if supplied, or default data if supplied 3143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String data = getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_DATA); 3153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (data == null) { 3163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert data = getDefaultIntentData(); 3173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // then, if an ID was provided, append it. 3193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (data != null) { 3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String id = getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); 3213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (id != null) { 3223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert data = data + "/" + Uri.encode(id); 3233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return data; 3263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the intent data for the current suggestion. 3303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected Uri getSuggestionIntentData() { 3323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String data = getSuggestionIntentDataString(); 3333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (data == null) ? null : Uri.parse(data); 3343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the intent extra data for the current suggestion. 3383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 33994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney public String getSuggestionIntentExtraData() { 3403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 3413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the index of a column in {@link mCursor} by name. 3453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @return The index, or {@code -1} if the column was not found. 3473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected int getColumnIndex(String colName) { 3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mCursor == null) return -1; 3503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: all operations on cross-process cursors can throw random exceptions 3513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mCursor.getColumnIndex(colName); 3523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3553e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the string value of a column in {@link mCursor} by column index. 3563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param col Column index. 3583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @return The string value, or {@code null}. 3593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected String getStringOrNull(int col) { 3613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mCursor == null) return null; 3623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (col == -1) { 3633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 3643e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 3663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // TODO: all operations on cross-process cursors can throw random exceptions 3673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mCursor.getString(col); 3683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (Exception e) { 3693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.e(TAG, 3703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert "unexpected error retrieving valid column from cursor, " 3713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert + "did the remote process die?", e); 3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 3733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Gets the string value of a column in {@link mCursor} by column name. 3783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 3793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param colName Column name. 3803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @return The string value, or {@code null}. 3813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert protected String getStringOrNull(String colName) { 3833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int col = getColumnIndex(colName); 3843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return getStringOrNull(col); 3853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private String makeKeyComponent(String str) { 3883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return str == null ? "" : str; 3893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getSuggestionKey() { 3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String action = makeKeyComponent(getSuggestionIntentAction()); 3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String data = makeKeyComponent(getSuggestionIntentDataString()); 3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String query = makeKeyComponent(getSuggestionQuery()); 3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // calculating accurate size of string builder avoids an allocation vs starting with 3963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // the default size and having to expand. 3973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int size = action.length() + 2 + data.length() + query.length(); 3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return new StringBuilder(size) 3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .append(action) 4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .append('#') 4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .append(data) 4023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .append('#') 4033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .append(query) 4043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .toString(); 4053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 407