SearchWidgetProvider.java revision 9ad03a750a66b26441a19ff54b6057729c145eae
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.quicksearchbox; 18 19import com.android.quicksearchbox.ui.SearchSourceSelector; 20import com.android.quicksearchbox.ui.SuggestionViewFactory; 21 22import android.app.PendingIntent; 23import android.app.SearchManager; 24import android.appwidget.AppWidgetManager; 25import android.appwidget.AppWidgetProvider; 26import android.content.ComponentName; 27import android.content.Context; 28import android.content.Intent; 29import android.net.Uri; 30import android.os.Bundle; 31import android.speech.RecognizerIntent; 32import android.util.Log; 33import android.view.KeyEvent; 34import android.view.View; 35import android.widget.RemoteViews; 36 37/** 38 * Search widget provider. 39 * 40 */ 41public class SearchWidgetProvider extends AppWidgetProvider { 42 43 private static final boolean DBG = true; 44 private static final String TAG = "QSB.SearchWidgetProvider"; 45 46 private static final boolean SHOW_SHORTCUT_IN_WIDGET = false; 47 48 private static final String ACTION_UPDATE_SEARCH_WIDGETS = 49 "com.android.quicksearchbox.UPDATE_SEARCH_WIDGETS"; 50 51 private static final String WIDGET_SEARCH_SOURCE = "launcher-search"; 52 private static final String WIDGET_SEARCH_SHORTCUT_SOURCE = "launcher-search-shortcut"; 53 54 // TODO: Expose SearchManager.SOURCE instead. 55 private static final String SOURCE = "source"; 56 57 /** 58 * Updates all search widgets. 59 */ 60 public static void updateSearchWidgets(Context context) { 61 Intent intent = new Intent(ACTION_UPDATE_SEARCH_WIDGETS); 62 intent.setComponent(myComponentName(context)); 63 if (DBG) Log.d(TAG, "Broadcasting " + intent); 64 context.sendBroadcast(intent); 65 } 66 67 /** 68 * Gets the component name for this app widget provider. 69 */ 70 private static ComponentName myComponentName(Context context) { 71 return new ComponentName(context, SearchWidgetProvider.class); 72 } 73 74 @Override 75 public void onReceive(Context context, Intent intent) { 76 String action = intent.getAction(); 77 if (ACTION_UPDATE_SEARCH_WIDGETS.equals(action)) { 78 // We requested the update. Find the widgets and update them. 79 AppWidgetManager manager = AppWidgetManager.getInstance(context); 80 int[] appWidgetIds = manager.getAppWidgetIds(myComponentName(context)); 81 onUpdate(context, manager, appWidgetIds); 82 } else { 83 // Handle actions requested by the widget host. 84 super.onReceive(context, intent); 85 } 86 } 87 88 @Override 89 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 90 updateSearchWidgets(context, appWidgetManager, appWidgetIds); 91 } 92 93 /** 94 * Updates a set of search widgets. 95 */ 96 private void updateSearchWidgets(Context context, AppWidgetManager appWidgetManager, 97 int[] appWidgetIds) { 98 if (DBG) Log.d(TAG, "updateSearchWidgets()"); 99 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.search_widget); 100 101 Bundle widgetAppData = new Bundle(); 102 widgetAppData.putString(SOURCE, WIDGET_SEARCH_SOURCE); 103 104 // Source selector 105 bindSourceSelector(context, views, widgetAppData); 106 107 // Text field 108 Intent qsbIntent = new Intent(Intent.ACTION_MAIN); 109 qsbIntent.setClass(context, SearchActivity.class); 110 qsbIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 111 qsbIntent.putExtra(SearchManager.APP_DATA, widgetAppData); 112 PendingIntent textPendingIntent = PendingIntent.getActivity(context, 0, qsbIntent, 0); 113 views.setOnClickPendingIntent(R.id.search_widget_text, textPendingIntent); 114 115 // Voice search button. Only shown if voice search is available. 116 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); 117 voiceSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 118 voiceSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 119 RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); 120 // TODO: Does VoiceSearch actually look at APP_DATA? 121 voiceSearchIntent.putExtra(SearchManager.APP_DATA, widgetAppData); 122 if (voiceSearchIntent.resolveActivity(context.getPackageManager()) != null) { 123 PendingIntent voicePendingIntent = 124 PendingIntent.getActivity(context, 0, voiceSearchIntent, 0); 125 views.setOnClickPendingIntent(R.id.search_widget_voice_btn, voicePendingIntent); 126 views.setViewVisibility(R.id.search_widget_voice_btn, View.VISIBLE); 127 } else { 128 views.setViewVisibility(R.id.search_widget_voice_btn, View.GONE); 129 } 130 131 // Shortcuts 132 if (SHOW_SHORTCUT_IN_WIDGET) { 133 bindShortcuts(context, views); 134 } 135 136 appWidgetManager.updateAppWidget(appWidgetIds, views); 137 } 138 139 private void bindShortcuts(Context context, RemoteViews views) { 140 ShortcutRepository shortcutRepo = getShortcutRepository(context); 141 SuggestionCursor shortcuts = shortcutRepo.getShortcutsForQuery(""); 142 try { 143 if (shortcuts != null && shortcuts.getCount() > 0) { 144 shortcuts.moveTo(0); 145 RemoteViews shortcutView = new RemoteViews(context.getPackageName(), 146 R.layout.widget_suggestion); 147 bindRemoteViewSuggestion(context, shortcutView, shortcuts); 148 views.addView(R.id.widget_shortcuts, shortcutView); 149 views.setViewVisibility(R.id.widget_shortcuts, View.VISIBLE); 150 } else { 151 if (DBG) Log.d(TAG, "No shortcuts, hiding drop-down."); 152 views.setViewVisibility(R.id.widget_shortcuts, View.GONE); 153 } 154 } finally { 155 if (shortcuts != null) { 156 shortcuts.close(); 157 } 158 } 159 } 160 161 private void bindSourceSelector(Context context, RemoteViews views, Bundle widgetAppData) { 162 // TODO: Get the last source selected by the user? 163 ComponentName currentSource = null; 164 // We don't call setSearchSource(), since we want the source selector to always open QSB, 165 // regardless of which source is clicked. 166 Uri sourceIconUri = getSourceIconUri(context, currentSource); 167 views.setImageViewUri(SearchSourceSelector.ICON_VIEW_ID, sourceIconUri); 168 Intent intent = SearchSourceSelector.createIntent(currentSource, "", widgetAppData); 169 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 170 views.setOnClickPendingIntent(SearchSourceSelector.ICON_VIEW_ID, pendingIntent); 171 } 172 173 private Uri getSourceIconUri(Context context, ComponentName source) { 174 if (source == null) { 175 return getSuggestionViewFactory(context).getGlobalSearchIconUri(); 176 } 177 return getSources(context).getSourceByComponentName(source).getSourceIconUri(); 178 } 179 180 private void bindRemoteViewSuggestion(Context context, RemoteViews views, 181 SuggestionCursor suggestion) { 182 CharSequence text1 = suggestion.getSuggestionFormattedText1(); 183 CharSequence text2 = suggestion.getSuggestionFormattedText2(); 184 Uri icon1 = suggestion.getIconUri(suggestion.getSuggestionIcon1()); 185 if (icon1 == null) { 186 icon1 = suggestion.getSourceIconUri(); 187 } 188 Uri icon2 = suggestion.getIconUri(suggestion.getSuggestionIcon2()); 189 PendingIntent pendingIntent = getWidgetSuggestionIntent(context, suggestion); 190 if (DBG) { 191 Log.d(TAG, "Adding shortcut to widget: text1=" + text1 + ",text2=" + text2 192 + ",icon1=" + icon1 + ",icon2=" + icon2); 193 Log.d(TAG, " intent=" + pendingIntent); 194 } 195 setText1(views, text1); 196 setIcon1(views, icon1); 197 setPendingIntent(views, pendingIntent); 198 } 199 200 private PendingIntent getWidgetSuggestionIntent(Context context, SuggestionCursor suggestion) { 201 Bundle widgetAppData = new Bundle(); 202 widgetAppData.putString(SOURCE, WIDGET_SEARCH_SHORTCUT_SOURCE); 203 Intent intent = suggestion.getSuggestionIntent(context, widgetAppData, 204 KeyEvent.KEYCODE_UNKNOWN, null); 205 return PendingIntent.getActivity(context, 0, intent, 0); 206 } 207 208 private void setText1(RemoteViews views, CharSequence text) { 209 views.setCharSequence(R.id.text1, "setText", text); 210 } 211 212 private void setIcon1(RemoteViews views, Uri icon) { 213 views.setImageViewUri(R.id.icon1, icon); 214 } 215 216 private void setPendingIntent(RemoteViews views, PendingIntent pendingIntent) { 217 views.setOnClickPendingIntent(R.id.widget_suggestion, pendingIntent); 218 } 219 220 private QsbApplication getQsbApplication(Context context) { 221 return (QsbApplication) context.getApplicationContext(); 222 } 223 224 private SourceLookup getSources(Context context) { 225 return getQsbApplication(context).getSources(); 226 } 227 228 private ShortcutRepository getShortcutRepository(Context context) { 229 return getQsbApplication(context).getShortcutRepository(); 230 } 231 232 private SuggestionViewFactory getSuggestionViewFactory(Context context) { 233 return getQsbApplication(context).getSuggestionViewFactory(); 234 } 235 236} 237