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 19516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwoodimport com.android.quicksearchbox.util.NamedTaskExecutor; 202353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringertimport com.android.quicksearchbox.util.Util; 212353e9c002c45c0adc8a979a49ff317cae5838b8Bjorn Bringert 22fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.app.PendingIntent; 233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.app.SearchManager; 24227180196cf8d92172cbb62f8ddaacf864be28e7Bjorn Bringertimport android.app.SearchableInfo; 253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.ComponentName; 263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.ContentResolver; 273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.Context; 28fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.content.Intent; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.pm.ActivityInfo; 306d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringertimport android.content.pm.PackageInfo; 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.content.pm.PackageManager; 3209552c760ad82eb90795e98de96c65005d6ebafcMathew Inwoodimport android.content.pm.PackageManager.NameNotFoundException; 33cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringertimport android.content.pm.PathPermission; 34cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringertimport android.content.pm.ProviderInfo; 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.database.Cursor; 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Drawable; 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.net.Uri; 38fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.os.Bundle; 39e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport android.os.Handler; 40fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.speech.RecognizerIntent; 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 43227180196cf8d92172cbb62f8ddaacf864be28e7Bjorn Bringertimport java.util.Arrays; 44227180196cf8d92172cbb62f8ddaacf864be28e7Bjorn Bringert 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Represents a single suggestion source, e.g. Contacts. 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 4849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringertpublic class SearchableSource extends AbstractSource { 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 50b5fc08b7f16a32d3865f44b7f26d8aaa5304a2adBjorn Bringert private static final boolean DBG = false; 510484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static final String TAG = "QSB.SearchableSource"; 523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 53fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // TODO: This should be exposed or moved to android-common, see http://b/issue?id=2440614 54fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // The extra key used in an intent to the speech recognizer for in-app voice search. 55fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private static final String EXTRA_CALLING_PACKAGE = "calling_package"; 56fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final SearchableInfo mSearchable; 583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 5962adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert private final String mName; 6062adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert 613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final ActivityInfo mActivityInfo; 623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 636d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert private final int mVersionCode; 646d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert 653e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Cached label for the activity 663e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private CharSequence mLabel = null; 673e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Cached icon for the activity 693e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private Drawable.ConstantState mSourceIcon = null; 703e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 7109552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood private Uri mSuggestUriBase; 7209552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood 73516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood public SearchableSource(Context context, SearchableInfo searchable, Handler uiThread, 74516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood NamedTaskExecutor iconLoader) throws NameNotFoundException { 75516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood super(context, uiThread, iconLoader); 763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert ComponentName componentName = searchable.getSearchActivity(); 775229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood if (DBG) Log.d(TAG, "created Searchable for " + componentName); 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 } 85e1fc4581ebab65220a82bcdb3272b4eb85453837Bjorn Bringert 8677909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert public SearchableInfo getSearchableInfo() { 87fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSearchable; 88fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 89fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 90cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert /** 91cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * Checks if the current process can read the suggestion provider in this source. 92cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert */ 93cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert public boolean canRead() { 94cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String authority = mSearchable.getSuggestAuthority(); 95cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (authority == null) { 9681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert // TODO: maybe we should have a way to distinguish between having suggestions 9781a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert // and being readable. 9881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert return true; 99cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 100cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert 101cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Uri.Builder uriBuilder = new Uri.Builder() 102cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert .scheme(ContentResolver.SCHEME_CONTENT) 103cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert .authority(authority); 104cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // if content path provided, insert it now 105cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String contentPath = mSearchable.getSuggestPath(); 106cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (contentPath != null) { 107cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert uriBuilder.appendEncodedPath(contentPath); 108cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 109cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // append standard suggestion query path 110cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert uriBuilder.appendEncodedPath(SearchManager.SUGGEST_URI_PATH_QUERY); 111cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Uri uri = uriBuilder.build(); 112cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return canRead(uri); 113cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 114cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert 115cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert /** 116cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * Checks if the current process can read the given content URI. 117cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * 118cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert * TODO: Shouldn't this be a PackageManager / Context / ContentResolver method? 119cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert */ 120cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert private boolean canRead(Uri uri) { 12149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert ProviderInfo provider = getContext().getPackageManager().resolveContentProvider( 122cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert uri.getAuthority(), 0); 123cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (provider == null) { 124cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert Log.w(TAG, getName() + " has bad suggestion authority " + uri.getAuthority()); 125cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 126cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 127cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String readPermission = provider.readPermission; 128cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (readPermission == null) { 129cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // No permission required to read anything in the content provider 130cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return true; 131cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 132cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert int pid = android.os.Process.myPid(); 133cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert int uid = android.os.Process.myUid(); 13449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert if (getContext().checkPermission(readPermission, pid, uid) 135cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert == PackageManager.PERMISSION_GRANTED) { 136cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // We have permission to read everything in the content provider 137cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return true; 138cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 139cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert PathPermission[] pathPermissions = provider.pathPermissions; 140cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (pathPermissions == null || pathPermissions.length == 0) { 141cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // We don't have the readPermission, and there are no pathPermissions 142cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (DBG) Log.d(TAG, "Missing " + readPermission); 143cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 144cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 145cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String path = uri.getPath(); 146cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert for (PathPermission perm : pathPermissions) { 147cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert String pathReadPermission = perm.getReadPermission(); 148cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (pathReadPermission != null 149cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert && perm.match(path) 15049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert && getContext().checkPermission(pathReadPermission, pid, uid) 151cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert == PackageManager.PERMISSION_GRANTED) { 152cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert // We have the path permission 153cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return true; 154cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 155cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 156cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert if (DBG) Log.d(TAG, "Missing " + readPermission + " and no path permission applies"); 157cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert return false; 158cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert } 159cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert 16081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert public ComponentName getIntentComponent() { 1613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSearchActivity(); 1623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1633e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1646d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert public int getVersionCode() { 1656d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert return mVersionCode; 1666d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert } 1676d5cbd67f7a5f824babb5c892b0f30bfd9f4ff23Bjorn Bringert 168f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert public String getName() { 16962adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert return mName; 170d32d6753347e872aa5d9d6e9015ed7f24db3e362Bjorn Bringert } 171d32d6753347e872aa5d9d6e9015ed7f24db3e362Bjorn Bringert 17249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert @Override 17349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert protected String getIconPackage() { 17449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert // Get icons from the package containing the suggestion provider, if any 17549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert String iconPackage = mSearchable.getSuggestPackage(); 17649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert if (iconPackage != null) { 17749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return iconPackage; 17849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert } else { 17949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert // Fall back to the package containing the searchable activity 18049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return mSearchable.getSearchActivity().getPackageName(); 18149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert } 1823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public CharSequence getLabel() { 1853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mLabel == null) { 1863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Load label lazily 18749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert mLabel = mActivityInfo.loadLabel(getContext().getPackageManager()); 1883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mLabel; 1903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 1925691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert public CharSequence getHint() { 1935691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert return getText(mSearchable.getHintId()); 1945691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert } 1955691f9062b2a558ba39c700d65bc522d397ebc75Bjorn Bringert 1963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public int getQueryThreshold() { 1973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSuggestThreshold(); 1983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2008d9d845323514c34bb07d6eb91146a975324fcedBjorn Bringert public CharSequence getSettingsDescription() { 201fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return getText(mSearchable.getSettingsDescriptionId()); 2023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Drawable getSourceIcon() { 2053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (mSourceIcon == null) { 206e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert Drawable icon = loadSourceIcon(); 207e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert if (icon == null) { 208e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert icon = getContext().getResources().getDrawable(R.drawable.corpus_icon_default); 209e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert } 2103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Can't share Drawable instances, save constant state instead. 2113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mSourceIcon = (icon != null) ? icon.getConstantState() : null; 2123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // Optimization, return the Drawable the first time 2133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return icon; 2143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return (mSourceIcon != null) ? mSourceIcon.newDrawable() : null; 2163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 218e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert private Drawable loadSourceIcon() { 219e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert int iconRes = getSourceIconResource(); 220e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert if (iconRes == 0) return null; 221e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert PackageManager pm = getContext().getPackageManager(); 222e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert return pm.getDrawable(mActivityInfo.packageName, iconRes, 223e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert mActivityInfo.applicationInfo); 224e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert } 225e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert 2263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Uri getSourceIconUri() { 227d32d6753347e872aa5d9d6e9015ed7f24db3e362Bjorn Bringert int resourceId = getSourceIconResource(); 228e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert if (resourceId == 0) { 229e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert return Util.getResourceUri(getContext(), R.drawable.corpus_icon_default); 230e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert } else { 231e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert return Util.getResourceUri(getContext(), mActivityInfo.applicationInfo, resourceId); 232e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert } 2333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 2353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private int getSourceIconResource() { 236e46ac8349b012ec2c649d4e20bc835fec9ec681fBjorn Bringert return mActivityInfo.getIconResource(); 2373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 2383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 239fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public boolean voiceSearchEnabled() { 240fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return mSearchable.getVoiceSearchEnabled(); 241fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 242fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 243fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert public Intent createVoiceSearchIntent(Bundle appData) { 244fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (mSearchable.getVoiceSearchLaunchWebSearch()) { 24549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return createVoiceWebSearchIntent(appData); 246fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { 247fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return createVoiceAppSearchIntent(appData); 248fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 249fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return null; 250fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 251fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 252fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert /** 253fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Create and return an Intent that can launch the voice search activity, perform a specific 254fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * voice transcription, and forward the results to the searchable activity. 255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * 256fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * This code is copied from SearchDialog 257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * 258fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * @return A completely-configured intent ready to send to the voice search activity 259fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert */ 260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private Intent createVoiceAppSearchIntent(Bundle appData) { 261fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert ComponentName searchActivity = mSearchable.getSearchActivity(); 262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 263fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // create the necessary intent to set up a search-and-forward operation 264fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // in the voice search system. We have to keep the bundle separate, 265fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // because it becomes immutable once it enters the PendingIntent 266fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Intent queryIntent = new Intent(Intent.ACTION_SEARCH); 267fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert queryIntent.setComponent(searchActivity); 268fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert PendingIntent pending = PendingIntent.getActivity( 269fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT); 270fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 271fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Now set up the bundle that will be inserted into the pending intent 272fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // when it's time to do the search. We always build it here (even if empty) 273fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // because the voice search activity will always need to insert "QUERY" into 274fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // it anyway. 275fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Bundle queryExtras = new Bundle(); 276fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (appData != null) { 277fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert queryExtras.putBundle(SearchManager.APP_DATA, appData); 278fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 279fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 280fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Now build the intent to launch the voice search. Add all necessary 281fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // extras to launch the voice recognizer, and then all the necessary extras 282fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // to forward the results to the searchable activity 283fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 284fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 285fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 286fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Add all of the configuration options supplied by the searchable's metadata 287fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String languageModel = getString(mSearchable.getVoiceLanguageModeId()); 288fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (languageModel == null) { 289fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM; 290fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 291fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String prompt = getString(mSearchable.getVoicePromptTextId()); 292fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert String language = getString(mSearchable.getVoiceLanguageId()); 293fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert int maxResults = mSearchable.getVoiceMaxResults(); 294fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (maxResults <= 0) { 295fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert maxResults = 1; 296fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 297fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 298fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel); 299fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt); 300fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); 301fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults); 302fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(EXTRA_CALLING_PACKAGE, 303fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert searchActivity == null ? null : searchActivity.toShortString()); 304fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 305fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert // Add the values that configure forwarding the results 306fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending); 307fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras); 308fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 309fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return voiceIntent; 310fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 311fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 312cd1e3ba5f7c3f5242345ff6f674281e3d6366e24Mathew Inwood public SourceResult getSuggestions(String query, int queryLimit, boolean onlySource) { 3133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert try { 31449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert Cursor cursor = getSuggestions(getContext(), mSearchable, query, queryLimit); 3153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, toString() + "[" + query + "] returned."); 31649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return new CursorBackedSourceResult(this, query, cursor); 3173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } catch (RuntimeException ex) { 3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.e(TAG, toString() + "[" + query + "] failed", ex); 31949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return new CursorBackedSourceResult(this, query); 3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3213e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 32394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney public SuggestionCursor refreshShortcut(String shortcutId, String extraData) { 32494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Cursor cursor = null; 32594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney try { 32649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert cursor = getValidationCursor(getContext(), mSearchable, shortcutId, extraData); 32794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (DBG) Log.d(TAG, toString() + "[" + shortcutId + "] returned."); 32894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (cursor != null && cursor.getCount() > 0) { 32994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney cursor.moveToFirst(); 33094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 33149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return new CursorBackedSourceResult(this, null, cursor); 33294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } catch (RuntimeException ex) { 33394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Log.e(TAG, toString() + "[" + shortcutId + "] failed", ex); 33494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (cursor != null) { 33594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney cursor.close(); 33694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 33794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // TODO: Should we delete the shortcut even if the failure is temporary? 33894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return null; 33994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 34094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 34194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 34209552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood public String getSuggestUri() { 34309552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood Uri uri = getSuggestUriBase(mSearchable); 34409552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood if (uri == null) return null; 34509552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood return uri.toString(); 34609552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood } 34709552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood 34809552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood private synchronized Uri getSuggestUriBase(SearchableInfo searchable) { 3493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (searchable == null) { 3503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return null; 3513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 35209552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood if (mSuggestUriBase == null) { 3533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 35409552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood String authority = searchable.getSuggestAuthority(); 35509552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood if (authority == null) { 35609552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood return null; 35709552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood } 3583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 35909552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood Uri.Builder uriBuilder = new Uri.Builder() 36009552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood .scheme(ContentResolver.SCHEME_CONTENT) 36109552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood .authority(authority); 3623e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 36309552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood // if content path provided, insert it now 36409552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood final String contentPath = searchable.getSuggestPath(); 36509552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood if (contentPath != null) { 36609552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood uriBuilder.appendEncodedPath(contentPath); 36709552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood } 36809552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood 36909552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood // append standard suggestion query path 37009552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); 37109552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood mSuggestUriBase = uriBuilder.build(); 3723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 37309552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood return mSuggestUriBase; 37409552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood } 3753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 37609552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood /** 37709552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood * This is a copy of {@link SearchManager#getSuggestions(SearchableInfo, String)}. 37809552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood */ 37909552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood private Cursor getSuggestions(Context context, SearchableInfo searchable, String query, 38009552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood int queryLimit) { 38109552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood 38209552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood Uri base = getSuggestUriBase(searchable); 38309552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood if (base == null) return null; 38409552c760ad82eb90795e98de96c65005d6ebafcMathew Inwood Uri.Builder uriBuilder = base.buildUpon(); 3853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3863e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // get the query selection, may be null 3873e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String selection = searchable.getSuggestSelection(); 3883e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // inject query, either as selection args or inline 3893e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert String[] selArgs = null; 3903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (selection != null) { // use selection if provided 3913e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert selArgs = new String[] { query }; 3923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } else { // no selection, use REST pattern 3933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert uriBuilder.appendPath(query); 3943e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 3953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3963e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert uriBuilder.appendQueryParameter("limit", String.valueOf(queryLimit)); 3973e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 3983e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Uri uri = uriBuilder.build(); 3993e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4003e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert // finally, make the query 4013e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) { 4023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert Log.d(TAG, "query(" + uri + ",null," + selection + "," 4033e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert + Arrays.toString(selArgs) + ",null)"); 4043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 405e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood Cursor c = context.getContentResolver().query(uri, null, selection, selArgs, null); 406e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (DBG) Log.d(TAG, "Got cursor from " + mName + ": " + c); 407e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return c; 4083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4093e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 41094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney private static Cursor getValidationCursor(Context context, SearchableInfo searchable, 41194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney String shortcutId, String extraData) { 41294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney String authority = searchable.getSuggestAuthority(); 41394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (authority == null) { 41494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return null; 41594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 41694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 41794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Uri.Builder uriBuilder = new Uri.Builder() 41894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .scheme(ContentResolver.SCHEME_CONTENT) 41994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .authority(authority); 42094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 42194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // if content path provided, insert it now 42294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney final String contentPath = searchable.getSuggestPath(); 42394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (contentPath != null) { 42494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney uriBuilder.appendEncodedPath(contentPath); 42594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 42694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 42794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // append the shortcut path and id 42894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_SHORTCUT); 42994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney uriBuilder.appendPath(shortcutId); 43094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 43194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney Uri uri = uriBuilder 43294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .appendQueryParameter(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, extraData) 43394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney .build(); 43494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 43594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney if (DBG) Log.d(TAG, "Requesting refresh " + uri); 43694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney // finally, make the query 43794e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney return context.getContentResolver().query(uri, null, null, null, null); 43894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney } 43994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney 44053aab8c4459f45664d04ec882d67094c52b78695Bjorn Bringert public int getMaxShortcuts(Config config) { 44153aab8c4459f45664d04ec882d67094c52b78695Bjorn Bringert return config.getMaxShortcuts(getName()); 4423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 444f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert public boolean includeInAll() { 445f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert return true; 446f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert } 447f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert 4483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public boolean queryAfterZeroResults() { 4493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.queryAfterZeroResults(); 4503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4523e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getDefaultIntentAction() { 45393bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert String action = mSearchable.getSuggestIntentAction(); 45493bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert if (action != null) return action; 45593bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert return Intent.ACTION_SEARCH; 4563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 4583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public String getDefaultIntentData() { 4593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mSearchable.getSuggestIntentData(); 4603e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 4613e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 462fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private CharSequence getText(int id) { 463fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert if (id == 0) return null; 46449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert return getContext().getPackageManager().getText(mActivityInfo.packageName, id, 465fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert mActivityInfo.applicationInfo); 466fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 467fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert 468fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert private String getString(int id) { 469fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert CharSequence text = getText(id); 470fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert return text == null ? null : text.toString(); 471fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert } 4723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 473