SearchableSource.java revision 2353e9c002c45c0adc8a979a49ff317cae5838b8
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 192353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringertimport com.android.quicksearchbox.util.Util; 202353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringert 21fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.app.PendingIntent; 223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager; 23227180196cf8d92172cbb62f8ddaacf864be28e7Bjorn Bringertimport android.app.SearchableInfo; 243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.ComponentName; 253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.ContentResolver; 263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Context; 27fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.content.Intent; 283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.pm.ActivityInfo; 296d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringertimport android.content.pm.PackageInfo; 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.pm.PackageManager; 31cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringertimport android.content.pm.PathPermission; 32cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringertimport android.content.pm.ProviderInfo; 333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.pm.PackageManager.NameNotFoundException; 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.Cursor; 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Drawable; 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.net.Uri; 37fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.os.Bundle; 38fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.speech.RecognizerIntent; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 41227180196cf8d92172cbb62f8ddaacf864be28e7Bjorn Bringertimport java.util.Arrays; 42227180196cf8d92172cbb62f8ddaacf864be28e7Bjorn Bringert 433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Represents a single suggestion source, e.g. Contacts. 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class SearchableSource implements Source { 483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final boolean DBG = true; 500484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static final String TAG = "QSB.SearchableSource"; 513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 52fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // TODO: This should be exposed or moved to android-common, see http://b/issue?id=2440614 53fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // The extra key used in an intent to the speech recognizer for in-app voice search. 54fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private static final String EXTRA_CALLING_PACKAGE = "calling_package"; 55fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final Context mContext; 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final SearchableInfo mSearchable; 593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 6062adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert private final String mName; 6162adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert 623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final ActivityInfo mActivityInfo; 633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 646d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert private final int mVersionCode; 656d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert 663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Cached label for the activity 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private CharSequence mLabel = null; 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Cached icon for the activity 703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private Drawable.ConstantState mSourceIcon = null; 713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final IconLoader mIconLoader; 733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public SearchableSource(Context context, SearchableInfo searchable) 753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert throws NameNotFoundException { 763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert ComponentName componentName = searchable.getSearchActivity(); 773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mContext = context; 783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSearchable = searchable; 7962adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert mName = componentName.flattenToShortString(); 806d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert PackageManager pm = context.getPackageManager(); 816d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert mActivityInfo = pm.getActivityInfo(componentName, 0); 826d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert PackageInfo pkgInfo = pm.getPackageInfo(componentName.getPackageName(), 0); 836d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert mVersionCode = pkgInfo.versionCode; 84e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert mIconLoader = createIconLoader(context, searchable.getSuggestPackage()); 85e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert } 86e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert 87fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected Context getContext() { 88fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mContext; 89fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 90fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 91fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert protected SearchableInfo getSearchableInfo() { 92fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSearchable; 93fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 94fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 95cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert /** 96cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * Checks if the current process can read the suggestion provider in this source. 97cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert */ 98cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert public boolean canRead() { 99cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String authority = mSearchable.getSuggestAuthority(); 100cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (authority == null) { 101cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Log.w(TAG, getName() + " has no searchSuggestAuthority"); 102cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 103cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 104cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert 105cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Uri.Builder uriBuilder = new Uri.Builder() 106cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert .scheme(ContentResolver.SCHEME_CONTENT) 107cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert .authority(authority); 108cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // if content path provided, insert it now 109cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String contentPath = mSearchable.getSuggestPath(); 110cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (contentPath != null) { 111cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert uriBuilder.appendEncodedPath(contentPath); 112cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 113cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // append standard suggestion query path 114cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert uriBuilder.appendEncodedPath(SearchManager.SUGGEST_URI_PATH_QUERY); 115cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Uri uri = uriBuilder.build(); 116cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return canRead(uri); 117cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 118cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert 119cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert /** 120cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * Checks if the current process can read the given content URI. 121cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * 122cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * TODO: Shouldn't this be a PackageManager / Context / ContentResolver method? 123cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert */ 124cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert private boolean canRead(Uri uri) { 125cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert ProviderInfo provider = mContext.getPackageManager().resolveContentProvider( 126cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert uri.getAuthority(), 0); 127cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (provider == null) { 128cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Log.w(TAG, getName() + " has bad suggestion authority " + uri.getAuthority()); 129cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 130cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 131cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String readPermission = provider.readPermission; 132cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (readPermission == null) { 133cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // No permission required to read anything in the content provider 134cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return true; 135cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 136cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert int pid = android.os.Process.myPid(); 137cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert int uid = android.os.Process.myUid(); 138cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (mContext.checkPermission(readPermission, pid, uid) 139cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert == PackageManager.PERMISSION_GRANTED) { 140cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // We have permission to read everything in the content provider 141cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return true; 142cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 143cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert PathPermission[] pathPermissions = provider.pathPermissions; 144cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (pathPermissions == null || pathPermissions.length == 0) { 145cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // We don't have the readPermission, and there are no pathPermissions 146cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (DBG) Log.d(TAG, "Missing " + readPermission); 147cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 148cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 149cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String path = uri.getPath(); 150cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert for (PathPermission perm : pathPermissions) { 151cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String pathReadPermission = perm.getReadPermission(); 152cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (pathReadPermission != null 153cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert && perm.match(path) 154cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert && mContext.checkPermission(pathReadPermission, pid, uid) 155cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert == PackageManager.PERMISSION_GRANTED) { 156cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // We have the path permission 157cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return true; 158cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 159cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 160cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (DBG) Log.d(TAG, "Missing " + readPermission + " and no path permission applies"); 161cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 162cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 163cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert 164e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert private IconLoader createIconLoader(Context context, String providerPackage) { 165e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert if (providerPackage == null) return null; 166e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert try { 167e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert return new CachingIconLoader(new PackageIconLoader(context, providerPackage)); 168e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert } catch (PackageManager.NameNotFoundException ex) { 169e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert Log.e(TAG, "Suggestion provider package not found: " + providerPackage); 170e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert return null; 171e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert } 1723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public ComponentName getComponentName() { 1753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSearchActivity(); 1763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1786d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert public int getVersionCode() { 1796d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert return mVersionCode; 1806d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert } 1816d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert 182f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert public String getName() { 18362adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert return mName; 184d32d6753347e872aa5d9d6e9015ed7f24db3e362Bjorn Bringert } 185d32d6753347e872aa5d9d6e9015ed7f24db3e362Bjorn Bringert 1863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Drawable getIcon(String drawableId) { 187e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert return mIconLoader == null ? null : mIconLoader.getIcon(drawableId); 1883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Uri getIconUri(String drawableId) { 191e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert return mIconLoader == null ? null : mIconLoader.getIconUri(drawableId); 1923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public CharSequence getLabel() { 1953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mLabel == null) { 1963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Load label lazily 1973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mLabel = mActivityInfo.loadLabel(mContext.getPackageManager()); 1983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mLabel; 2003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2025691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert public CharSequence getHint() { 2035691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert return getText(mSearchable.getHintId()); 2045691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } 2055691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert 2063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public int getQueryThreshold() { 2073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSuggestThreshold(); 2083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2108d9d845323514c34bb07d6eb91146a975324fcedBjorn Bringert public CharSequence getSettingsDescription() { 211fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getText(mSearchable.getSettingsDescriptionId()); 2123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Drawable getSourceIcon() { 2153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mSourceIcon == null) { 2163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Load icon lazily 2173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int iconRes = getSourceIconResource(); 2183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert PackageManager pm = mContext.getPackageManager(); 2193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Drawable icon = pm.getDrawable(mActivityInfo.packageName, iconRes, 2203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mActivityInfo.applicationInfo); 2213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Can't share Drawable instances, save constant state instead. 2223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSourceIcon = (icon != null) ? icon.getConstantState() : null; 2233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Optimization, return the Drawable the first time 2243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return icon; 2253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (mSourceIcon != null) ? mSourceIcon.newDrawable() : null; 2273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Uri getSourceIconUri() { 230d32d6753347e872aa5d9d6e9015ed7f24db3e362Bjorn Bringert int resourceId = getSourceIconResource(); 2312353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringert return Util.getResourceUri(getContext(), mActivityInfo.applicationInfo, resourceId); 2323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private int getSourceIconResource() { 2353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int icon = mActivityInfo.getIconResource(); 2363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (icon != 0) ? icon : android.R.drawable.sym_def_app_icon; 2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 239fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public boolean voiceSearchEnabled() { 240fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSearchable.getVoiceSearchEnabled(); 241fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 242fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 243fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // TODO: not all apps handle ACTION_SEARCH properly, e.g. ApplicationsProvider. 244fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Maybe we should add a flag to searchable, so that QSB can hide the search button? 245fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public Intent createSearchIntent(String query, Bundle appData) { 246fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Intent intent = new Intent(Intent.ACTION_SEARCH); 247fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert intent.setComponent(getComponentName()); 248fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 249fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // We need CLEAR_TOP to avoid reusing an old task that has other activities 250fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // on top of the one we want. 251fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 252fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert intent.putExtra(SearchManager.USER_QUERY, query); 253fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert intent.putExtra(SearchManager.QUERY, query); 254fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (appData != null) { 255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert intent.putExtra(SearchManager.APP_DATA, appData); 256fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return intent; 258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 259fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public Intent createVoiceSearchIntent(Bundle appData) { 261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (mSearchable.getVoiceSearchLaunchWebSearch()) { 262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return WebCorpus.createVoiceWebSearchIntent(appData); 263fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { 264fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return createVoiceAppSearchIntent(appData); 265fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 266fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return null; 267fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 268fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 269fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert /** 270fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Create and return an Intent that can launch the voice search activity, perform a specific 271fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * voice transcription, and forward the results to the searchable activity. 272fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * 273fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * This code is copied from SearchDialog 274fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * 275fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * @return A completely-configured intent ready to send to the voice search activity 276fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert */ 277fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Intent createVoiceAppSearchIntent(Bundle appData) { 278fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert ComponentName searchActivity = mSearchable.getSearchActivity(); 279fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 280fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // create the necessary intent to set up a search-and-forward operation 281fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // in the voice search system. We have to keep the bundle separate, 282fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // because it becomes immutable once it enters the PendingIntent 283fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Intent queryIntent = new Intent(Intent.ACTION_SEARCH); 284fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert queryIntent.setComponent(searchActivity); 285fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert PendingIntent pending = PendingIntent.getActivity( 286fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT); 287fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 288fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Now set up the bundle that will be inserted into the pending intent 289fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // when it's time to do the search. We always build it here (even if empty) 290fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // because the voice search activity will always need to insert "QUERY" into 291fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // it anyway. 292fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Bundle queryExtras = new Bundle(); 293fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (appData != null) { 294fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert queryExtras.putBundle(SearchManager.APP_DATA, appData); 295fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 296fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 297fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Now build the intent to launch the voice search. Add all necessary 298fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // extras to launch the voice recognizer, and then all the necessary extras 299fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // to forward the results to the searchable activity 300fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 301fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 302fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 303fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Add all of the configuration options supplied by the searchable's metadata 304fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String languageModel = getString(mSearchable.getVoiceLanguageModeId()); 305fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (languageModel == null) { 306fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM; 307fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 308fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String prompt = getString(mSearchable.getVoicePromptTextId()); 309fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String language = getString(mSearchable.getVoiceLanguageId()); 310fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert int maxResults = mSearchable.getVoiceMaxResults(); 311fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (maxResults <= 0) { 312fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert maxResults = 1; 313fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 314fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 315fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel); 316fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt); 317fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); 318fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults); 319fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(EXTRA_CALLING_PACKAGE, 320fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert searchActivity == null ? null : searchActivity.toShortString()); 321fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 322fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Add the values that configure forwarding the results 323fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending); 324fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras); 325fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 326fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return voiceIntent; 327fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 328fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 329fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public SourceResult getSuggestions(String query, int queryLimit) { 3303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 3313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Cursor cursor = getSuggestions(mContext, mSearchable, query, queryLimit); 3323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, toString() + "[" + query + "] returned."); 333fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return new CursorBackedSourceResult(query, cursor); 3343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (RuntimeException ex) { 3353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.e(TAG, toString() + "[" + query + "] failed", ex); 336fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return new CursorBackedSourceResult(query); 3373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 34094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney public SuggestionCursor refreshShortcut(String shortcutId, String extraData) { 34194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Cursor cursor = null; 34294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney try { 34394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney cursor = getValidationCursor(mContext, mSearchable, shortcutId, extraData); 34494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (DBG) Log.d(TAG, toString() + "[" + shortcutId + "] returned."); 34594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (cursor != null && cursor.getCount() > 0) { 34694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney cursor.moveToFirst(); 34794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 348fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return new CursorBackedSourceResult(null, cursor); 34994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } catch (RuntimeException ex) { 35094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Log.e(TAG, toString() + "[" + shortcutId + "] failed", ex); 35194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (cursor != null) { 35294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney cursor.close(); 35394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 35494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // TODO: Should we delete the shortcut even if the failure is temporary? 35594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return null; 35694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 35794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 35894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 359fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private class CursorBackedSourceResult extends CursorBackedSuggestionCursor 360fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert implements SourceResult { 361fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 362fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public CursorBackedSourceResult(String userQuery) { 363fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert this(userQuery, null); 364fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 365fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 366fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public CursorBackedSourceResult(String userQuery, Cursor cursor) { 367fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert super(userQuery, cursor); 368fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 369fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 370fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public Source getSource() { 371fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return SearchableSource.this; 372fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 373fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 374fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert @Override 375fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public Source getSuggestionSource() { 376fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return SearchableSource.this; 377fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 378fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 379883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert public boolean isSuggestionShortcut() { 380883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert return false; 381883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert } 382883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert 383bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert @Override 384bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert public String toString() { 385bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert return SearchableSource.this + "[" + getUserQuery() + "]"; 386bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert } 387bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert 388fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 389fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * This is a copy of {@link SearchManager#getSuggestions(SearchableInfo, String)}. 3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static Cursor getSuggestions(Context context, SearchableInfo searchable, String query, 3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert int queryLimit) { 3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (searchable == null) { 3963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 3973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String authority = searchable.getSuggestAuthority(); 4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (authority == null) { 4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 4023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Uri.Builder uriBuilder = new Uri.Builder() 4053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .scheme(ContentResolver.SCHEME_CONTENT) 4063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert .authority(authority); 4073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // if content path provided, insert it now 4093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert final String contentPath = searchable.getSuggestPath(); 4103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (contentPath != null) { 4113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert uriBuilder.appendEncodedPath(contentPath); 4123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // append standard suggestion query path 4153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); 4163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // get the query selection, may be null 4183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String selection = searchable.getSuggestSelection(); 4193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // inject query, either as selection args or inline 4203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String[] selArgs = null; 4213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (selection != null) { // use selection if provided 4223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert selArgs = new String[] { query }; 4233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { // no selection, use REST pattern 4243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert uriBuilder.appendPath(query); 4253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert uriBuilder.appendQueryParameter("limit", String.valueOf(queryLimit)); 4283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Uri uri = uriBuilder.build(); 4303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // finally, make the query 4323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 4333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "query(" + uri + ",null," + selection + "," 4343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert + Arrays.toString(selArgs) + ",null)"); 4353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return context.getContentResolver().query(uri, null, selection, selArgs, null); 4373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 43994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney private static Cursor getValidationCursor(Context context, SearchableInfo searchable, 44094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney String shortcutId, String extraData) { 44194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney String authority = searchable.getSuggestAuthority(); 44294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (authority == null) { 44394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return null; 44494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 44594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 44694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Uri.Builder uriBuilder = new Uri.Builder() 44794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .scheme(ContentResolver.SCHEME_CONTENT) 44894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .authority(authority); 44994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 45094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // if content path provided, insert it now 45194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney final String contentPath = searchable.getSuggestPath(); 45294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (contentPath != null) { 45394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney uriBuilder.appendEncodedPath(contentPath); 45494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 45594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 45694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // append the shortcut path and id 45794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_SHORTCUT); 45894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney uriBuilder.appendPath(shortcutId); 45994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 46094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Uri uri = uriBuilder 46194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .appendQueryParameter(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, extraData) 46294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .build(); 46394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 46494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (DBG) Log.d(TAG, "Requesting refresh " + uri); 46594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // finally, make the query 46694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return context.getContentResolver().query(uri, null, null, null, null); 46794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 46894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 4693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean isWebSuggestionSource() { 470ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert return false; 4713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean queryAfterZeroResults() { 4743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.queryAfterZeroResults(); 4753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean shouldRewriteQueryFromData() { 4783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.shouldRewriteQueryFromData(); 4793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean shouldRewriteQueryFromText() { 4823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.shouldRewriteQueryFromText(); 4833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert @Override 486abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert public boolean equals(Object o) { 487abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert if (o != null && o.getClass().equals(this.getClass())) { 488abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert SearchableSource s = (SearchableSource) o; 48962adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert return s.mName.equals(mName); 490abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert } 491abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert return false; 492abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert } 493abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert 494abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert @Override 495abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert public int hashCode() { 49662adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert return mName.hashCode(); 497abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert } 498abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert 499abd33f7f8d8e56348a8a87bb9e7af491d83ee833Bjorn Bringert @Override 5003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String toString() { 501f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert return "SearchableSource{component=" + getName() + "}"; 5023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getDefaultIntentAction() { 5053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSuggestIntentAction(); 5063e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getDefaultIntentData() { 5093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSuggestIntentData(); 5103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 5113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 512782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public String getSuggestActionMsg(int keyCode) { 513782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 514782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (actionKey == null) return null; 515782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return actionKey.getSuggestActionMsg(); 516782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 517782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 518782dd228e78e9294692d639597f96c26283968bbBjorn Bringert public String getSuggestActionMsgColumn(int keyCode) { 519782dd228e78e9294692d639597f96c26283968bbBjorn Bringert SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 520782dd228e78e9294692d639597f96c26283968bbBjorn Bringert if (actionKey == null) return null; 521782dd228e78e9294692d639597f96c26283968bbBjorn Bringert return actionKey.getSuggestActionMsgColumn(); 522782dd228e78e9294692d639597f96c26283968bbBjorn Bringert } 523782dd228e78e9294692d639597f96c26283968bbBjorn Bringert 524fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private CharSequence getText(int id) { 525fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (id == 0) return null; 526fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mContext.getPackageManager().getText(mActivityInfo.packageName, id, 527fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mActivityInfo.applicationInfo); 528fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 529fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 530fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private String getString(int id) { 531fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert CharSequence text = getText(id); 532fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return text == null ? null : text.toString(); 533fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 5343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 535