Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java

Issue 2816733003: 🔍 Update how shared preferences are handled by the widget (Closed)
Patch Set: Ugh eclipse Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.searchwidget; 5 package org.chromium.chrome.browser.searchwidget;
6 6
7 import android.app.PendingIntent; 7 import android.app.PendingIntent;
8 import android.appwidget.AppWidgetManager; 8 import android.appwidget.AppWidgetManager;
9 import android.appwidget.AppWidgetProvider; 9 import android.appwidget.AppWidgetProvider;
10 import android.content.ComponentName; 10 import android.content.ComponentName;
11 import android.content.Context; 11 import android.content.Context;
12 import android.content.Intent; 12 import android.content.Intent;
13 import android.content.SharedPreferences; 13 import android.content.SharedPreferences;
14 import android.net.Uri; 14 import android.net.Uri;
15 import android.os.Bundle; 15 import android.os.Bundle;
16 import android.support.v4.app.ActivityOptionsCompat; 16 import android.support.v4.app.ActivityOptionsCompat;
17 import android.text.TextUtils; 17 import android.text.TextUtils;
18 import android.view.View;
18 import android.widget.RemoteViews; 19 import android.widget.RemoteViews;
19 20
20 import org.chromium.base.ContextUtils; 21 import org.chromium.base.ContextUtils;
21 import org.chromium.base.Log; 22 import org.chromium.base.Log;
22 import org.chromium.base.ThreadUtils; 23 import org.chromium.base.ThreadUtils;
23 import org.chromium.base.library_loader.LibraryLoader; 24 import org.chromium.base.library_loader.LibraryLoader;
24 import org.chromium.chrome.R; 25 import org.chromium.chrome.R;
25 import org.chromium.chrome.browser.IntentHandler; 26 import org.chromium.chrome.browser.IntentHandler;
26 import org.chromium.chrome.browser.init.AsyncInitializationActivity;
27 import org.chromium.chrome.browser.search_engines.TemplateUrlService; 27 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
28 import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListene r; 28 import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListene r;
29 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl ServiceObserver; 29 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl ServiceObserver;
30 30
31 /** 31 /**
32 * Widget that lets the user search using the default search engine in Chrome. 32 * Widget that lets the user search using their default search engine.
33 *
33 * Because this is a BroadcastReceiver, it dies immediately after it runs. A ne w one is created 34 * Because this is a BroadcastReceiver, it dies immediately after it runs. A ne w one is created
34 * for each new broadcast. 35 * for each new broadcast.
35 */ 36 */
36 public class SearchWidgetProvider extends AppWidgetProvider { 37 public class SearchWidgetProvider extends AppWidgetProvider {
37 /** Monitors the TemplateUrlService for changes, updating the widget when ne cessary. */ 38 /** Monitors the TemplateUrlService for changes, updating the widget when ne cessary. */
38 private static final class SearchWidgetTemplateUrlServiceObserver 39 private static final class SearchWidgetTemplateUrlServiceObserver
39 implements LoadListener, TemplateUrlServiceObserver { 40 implements LoadListener, TemplateUrlServiceObserver {
40 @Override 41 @Override
41 public void onTemplateUrlServiceLoaded() { 42 public void onTemplateUrlServiceLoaded() {
42 TemplateUrlService.getInstance().unregisterLoadListener(this); 43 TemplateUrlService.getInstance().unregisterLoadListener(this);
43 updateCachedEngineName(); 44 updateCachedEngineName();
44 } 45 }
45 46
46 @Override 47 @Override
47 public void onTemplateURLServiceChanged() { 48 public void onTemplateURLServiceChanged() {
48 updateCachedEngineName(); 49 updateCachedEngineName();
49 } 50 }
50 } 51 }
51 52
52 private static final String ACTION_START_TEXT_QUERY = 53 private static final String ACTION_START_TEXT_QUERY =
53 "org.chromium.chrome.browser.searchwidget.START_TEXT_QUERY"; 54 "org.chromium.chrome.browser.searchwidget.START_TEXT_QUERY";
54 private static final String ACTION_START_VOICE_QUERY = 55 private static final String ACTION_START_VOICE_QUERY =
55 "org.chromium.chrome.browser.searchwidget.START_VOICE_QUERY"; 56 "org.chromium.chrome.browser.searchwidget.START_VOICE_QUERY";
56 private static final String ACTION_UPDATE_ALL_WIDGETS = 57 private static final String ACTION_UPDATE_ALL_WIDGETS =
57 "org.chromium.chrome.browser.searchwidget.UPDATE_ALL_WIDGETS"; 58 "org.chromium.chrome.browser.searchwidget.UPDATE_ALL_WIDGETS";
58 59
59 static final String EXTRA_START_VOICE_SEARCH = 60 static final String EXTRA_START_VOICE_SEARCH =
60 "org.chromium.chrome.browser.searchwidget.START_VOICE_SEARCH"; 61 "org.chromium.chrome.browser.searchwidget.START_VOICE_SEARCH";
61 62
63 private static final String PREF_IS_VOICE_SEARCH_AVAILABLE =
64 "org.chromium.chrome.browser.searchwidget.IS_VOICE_SEARCH_AVAILABLE" ;
62 private static final String PREF_SEARCH_ENGINE_SHORTNAME = 65 private static final String PREF_SEARCH_ENGINE_SHORTNAME =
63 "org.chromium.chrome.browser.searchwidget.SEARCH_ENGINE_SHORTNAME"; 66 "org.chromium.chrome.browser.searchwidget.SEARCH_ENGINE_SHORTNAME";
64 static final String PREF_USE_HERB_TAB = "org.chromium.chrome.browser.searchw idget.USE_HERB_TAB";
65 67
66 private static final String TAG = "searchwidget"; 68 private static final String TAG = "searchwidget";
67 private static final Object OBSERVER_LOCK = new Object(); 69 private static final Object OBSERVER_LOCK = new Object();
68 70
69 private static SearchWidgetTemplateUrlServiceObserver sObserver; 71 private static SearchWidgetTemplateUrlServiceObserver sObserver;
70 private static String sCachedSearchEngineName;
71 72
72 /** 73 /**
73 * Creates the singleton instance of the observer that will monitor for sear ch engine changes. 74 * Creates the singleton instance of the observer that will monitor for sear ch engine changes.
74 * The native library and the browser process must have been fully loaded be fore calling this, 75 * The native library and the browser process must have been fully loaded be fore calling this.
75 * after {@link AsyncInitializationActivity#finishNativeInitialization}.
76 */ 76 */
77 public static void initialize() { 77 public static void initialize() {
78 ThreadUtils.assertOnUiThread(); 78 ThreadUtils.assertOnUiThread();
79 assert LibraryLoader.isInitialized(); 79 assert LibraryLoader.isInitialized();
80 80
81 // Set up an observer to monitor for changes. 81 // Set up an observer to monitor for changes.
82 synchronized (OBSERVER_LOCK) { 82 synchronized (OBSERVER_LOCK) {
83 if (sObserver != null) return; 83 if (sObserver != null) return;
84 sObserver = new SearchWidgetTemplateUrlServiceObserver(); 84 sObserver = new SearchWidgetTemplateUrlServiceObserver();
85 85
86 TemplateUrlService service = TemplateUrlService.getInstance(); 86 TemplateUrlService service = TemplateUrlService.getInstance();
87 service.registerLoadListener(sObserver);
87 service.addObserver(sObserver); 88 service.addObserver(sObserver);
88 if (!service.isLoaded()) { 89 if (!service.isLoaded()) service.load();
89 service.registerLoadListener(sObserver);
90 service.load();
91 }
92 } 90 }
93 updateCachedEngineName(); 91 }
92
93 /** Nukes all cached information and forces all widgets to start with a blan k slate. */
94 public static void reset() {
95 SharedPreferences.Editor editor = ContextUtils.getAppSharedPreferences() .edit();
96 editor.remove(PREF_IS_VOICE_SEARCH_AVAILABLE);
97 editor.remove(PREF_SEARCH_ENGINE_SHORTNAME);
98 editor.apply();
99 updateAllWidgets();
94 } 100 }
95 101
96 @Override 102 @Override
97 public void onReceive(Context context, Intent intent) { 103 public void onReceive(Context context, Intent intent) {
98 if (IntentHandler.isIntentChromeOrFirstParty(intent)) { 104 if (IntentHandler.isIntentChromeOrFirstParty(intent)) {
99 if (ACTION_START_TEXT_QUERY.equals(intent.getAction())) { 105 if (ACTION_START_TEXT_QUERY.equals(intent.getAction())) {
100 startSearchActivity(context, false); 106 startSearchActivity(context, false);
101 return;
102 } else if (ACTION_START_VOICE_QUERY.equals(intent.getAction())) { 107 } else if (ACTION_START_VOICE_QUERY.equals(intent.getAction())) {
103 startSearchActivity(context, true); 108 startSearchActivity(context, true);
104 return; 109 } else if (ACTION_UPDATE_ALL_WIDGETS.equals(intent.getAction())) {
110 performUpdate(context);
105 } 111 }
106 } else if (ACTION_UPDATE_ALL_WIDGETS.equals(intent.getAction())) {
107 performUpdate(context);
108 return; 112 return;
109 } 113 }
110 super.onReceive(context, intent); 114 super.onReceive(context, intent);
111 } 115 }
112 116
113 private void startSearchActivity(Context context, boolean startVoiceSearch) { 117 private void startSearchActivity(Context context, boolean startVoiceSearch) {
114 Log.d(TAG, "Launching SearchActivity: VOICE=" + startVoiceSearch); 118 Log.d(TAG, "Launching SearchActivity: VOICE=" + startVoiceSearch);
115 119
116 // Launch the SearchActivity. 120 // Launch the SearchActivity.
117 Intent searchIntent = new Intent(); 121 Intent searchIntent = new Intent();
118 searchIntent.setClassName(context, SearchActivity.class.getName()); 122 searchIntent.setClass(context, SearchActivity.class);
119 searchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 123 searchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
120 searchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); 124 searchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
121 searchIntent.putExtra(EXTRA_START_VOICE_SEARCH, startVoiceSearch); 125 searchIntent.putExtra(EXTRA_START_VOICE_SEARCH, startVoiceSearch);
122 126
123 Bundle optionsBundle; 127 Bundle optionsBundle =
124 optionsBundle =
125 ActivityOptionsCompat.makeCustomAnimation(context, R.anim.activi ty_open_enter, 0) 128 ActivityOptionsCompat.makeCustomAnimation(context, R.anim.activi ty_open_enter, 0)
126 .toBundle(); 129 .toBundle();
127 context.startActivity(searchIntent, optionsBundle); 130 context.startActivity(searchIntent, optionsBundle);
128 } 131 }
129 132
130 @Override 133 @Override
131 public void onUpdate(Context context, AppWidgetManager manager, int[] ids) { 134 public void onUpdate(Context context, AppWidgetManager manager, int[] ids) {
132 performUpdate(context, ids); 135 performUpdate(context, ids);
133 super.onUpdate(context, manager, ids);
134 } 136 }
135 137
136 private void performUpdate(Context context) { 138 private static void performUpdate(Context context) {
137 AppWidgetManager manager = AppWidgetManager.getInstance(context); 139 AppWidgetManager manager = AppWidgetManager.getInstance(context);
138 performUpdate(context, getAllSearchWidgetIds(manager)); 140 performUpdate(context, getAllSearchWidgetIds(manager));
139 } 141 }
140 142
141 private void performUpdate(Context context, int[] ids) { 143 private static void performUpdate(Context context, int[] ids) {
142 for (int id : ids) updateWidget(context, id); 144 if (ids.length == 0) return;
145
146 AppWidgetManager manager = AppWidgetManager.getInstance(context);
147 SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
148 boolean isVoiceSearchAvailable = prefs.getBoolean(PREF_IS_VOICE_SEARCH_A VAILABLE, true);
149 String engineName = prefs.getString(PREF_SEARCH_ENGINE_SHORTNAME, null);
150
151 for (int id : ids) {
152 RemoteViews views = createWidgetViews(context, id, engineName, isVoi ceSearchAvailable);
153 manager.updateAppWidget(id, views);
154 }
143 } 155 }
144 156
145 private void updateWidget(Context context, int id) { 157 private static RemoteViews createWidgetViews(
146 AppWidgetManager manager = AppWidgetManager.getInstance(context); 158 Context context, int id, String engineName, boolean isVoiceSearchAva ilable) {
147 RemoteViews views = 159 RemoteViews views =
148 new RemoteViews(context.getPackageName(), R.layout.search_widget _template); 160 new RemoteViews(context.getPackageName(), R.layout.search_widget _template);
149 161
150 // Clicking on the widget fires an Intent back at this BroadcastReceiver , allowing control 162 // Clicking on the widget fires an Intent back at this BroadcastReceiver , allowing control
151 // over how the Activity is animated when it starts up. 163 // over how the Activity is animated when it starts up.
152 Intent textIntent = createStartQueryIntent(context, ACTION_START_TEXT_QU ERY, id); 164 Intent textIntent = createStartQueryIntent(context, ACTION_START_TEXT_QU ERY, id);
153 views.setOnClickPendingIntent(R.id.text_container, 165 views.setOnClickPendingIntent(R.id.text_container,
154 PendingIntent.getBroadcast( 166 PendingIntent.getBroadcast(
155 context, 0, textIntent, PendingIntent.FLAG_UPDATE_CURREN T)); 167 context, 0, textIntent, PendingIntent.FLAG_UPDATE_CURREN T));
156 168
157 Intent voiceIntent = createStartQueryIntent(context, ACTION_START_VOICE_ QUERY, id); 169 // If voice search is available, clicking on the microphone triggers a v oice query.
158 views.setOnClickPendingIntent(R.id.microphone_icon, 170 if (isVoiceSearchAvailable) {
159 PendingIntent.getBroadcast( 171 Intent voiceIntent = createStartQueryIntent(context, ACTION_START_VO ICE_QUERY, id);
160 context, 0, voiceIntent, PendingIntent.FLAG_UPDATE_CURRE NT)); 172 views.setOnClickPendingIntent(R.id.microphone_icon,
173 PendingIntent.getBroadcast(
174 context, 0, voiceIntent, PendingIntent.FLAG_UPDATE_C URRENT));
175 views.setViewVisibility(R.id.microphone_icon, View.VISIBLE);
176 } else {
177 views.setViewVisibility(R.id.microphone_icon, View.GONE);
178 }
161 179
162 // Update what string is displayed by the widget. 180 // Update what string is displayed by the widget.
163 String engineName = getCachedEngineName();
164 String text = TextUtils.isEmpty(engineName) 181 String text = TextUtils.isEmpty(engineName)
165 ? context.getString(R.string.search_widget_default) 182 ? context.getString(R.string.search_widget_default)
166 : context.getString(R.string.search_with_product, engineName); 183 : context.getString(R.string.search_with_product, engineName);
167 views.setTextViewText(R.id.title, text); 184 views.setTextViewText(R.id.title, text);
168 185
169 manager.updateAppWidget(id, views); 186 return views;
170 } 187 }
171 188
172 /** Force all widgets to update their state. */ 189 /** Caches whether or not a voice search is possible. */
173 static void updateAllWidgets() { 190 static void updateCachedVoiceSearchAvailability(boolean isVoiceSearchAvailab le) {
174 Intent intent = new Intent(ACTION_UPDATE_ALL_WIDGETS); 191 SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
175 intent.setPackage(ContextUtils.getApplicationContext().getPackageName()) ; 192 if (prefs.getBoolean(PREF_IS_VOICE_SEARCH_AVAILABLE, true) != isVoiceSea rchAvailable) {
176 ContextUtils.getApplicationContext().sendBroadcast(intent); 193 prefs.edit().putBoolean(PREF_IS_VOICE_SEARCH_AVAILABLE, isVoiceSearc hAvailable).apply();
194 updateAllWidgets();
195 }
177 } 196 }
178 197
179 /** Updates the name of the user's default search engine that is cached in S haredPreferences. */ 198 /**
180 static void updateCachedEngineName() { 199 * Updates the name of the user's default search engine that is cached in Sh aredPreferences.
200 * Caching it in SharedPreferences prevents us from having to load the nativ e library and the
201 * TemplateUrlService whenever the widget is updated.
202 */
203 private static void updateCachedEngineName() {
181 assert LibraryLoader.isInitialized(); 204 assert LibraryLoader.isInitialized();
182 205
183 // Getting an instance of the TemplateUrlService requires that the nativ e library be 206 // Getting an instance of the TemplateUrlService requires that the nativ e library be
184 // loaded, but the TemplateUrlService itself needs to be initialized. 207 // loaded, but the TemplateUrlService itself needs to be initialized.
185 TemplateUrlService service = TemplateUrlService.getInstance(); 208 TemplateUrlService service = TemplateUrlService.getInstance();
186 if (!service.isLoaded()) return; 209 assert service.isLoaded();
210 String engineName = service.getDefaultSearchEngineTemplateUrl().getShort Name();
187 211
188 String engineName = service.getDefaultSearchEngineTemplateUrl().getShort Name(); 212 SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
189 if (!TextUtils.equals(sCachedSearchEngineName, engineName)) { 213 if (!TextUtils.equals(prefs.getString(PREF_SEARCH_ENGINE_SHORTNAME, null ), engineName)) {
190 sCachedSearchEngineName = engineName; 214 prefs.edit().putString(PREF_SEARCH_ENGINE_SHORTNAME, engineName).app ly();
191
192 SharedPreferences.Editor editor = ContextUtils.getAppSharedPreferenc es().edit();
193 editor.putString(PREF_SEARCH_ENGINE_SHORTNAME, engineName);
194 editor.apply();
195
196 updateAllWidgets(); 215 updateAllWidgets();
197 } 216 }
198 } 217 }
199 218
200 /** 219 /** Get the IDs of all existing search widgets. */
201 * Returns the cached name of the user's default search engine. Caching it in SharedPreferences
202 * prevents us from having to load the native library and the TemplateUrlSer vice.
203 *
204 * @return The cached name of the user's default search engine.
205 */
206 private static String getCachedEngineName() {
207 if (sCachedSearchEngineName != null) return sCachedSearchEngineName;
208
209 SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
210 sCachedSearchEngineName = prefs.getString(PREF_SEARCH_ENGINE_SHORTNAME, null);
211 return sCachedSearchEngineName;
212 }
213
214 /** Get the IDs of all of Chrome's search widgets. */
215 private static int[] getAllSearchWidgetIds(AppWidgetManager manager) { 220 private static int[] getAllSearchWidgetIds(AppWidgetManager manager) {
216 return manager.getAppWidgetIds(new ComponentName( 221 return manager.getAppWidgetIds(new ComponentName(
217 ContextUtils.getApplicationContext(), SearchWidgetProvider.class .getName())); 222 ContextUtils.getApplicationContext(), SearchWidgetProvider.class .getName()));
218 } 223 }
219 224
220 /** Creates a trusted Intent that lets the user begin performing queries. */ 225 /** Creates a trusted Intent that lets the user begin performing queries. */
221 private Intent createStartQueryIntent(Context context, String action, int wi dgetId) { 226 private static Intent createStartQueryIntent(Context context, String action, int widgetId) {
222 Intent intent = new Intent(action, Uri.parse(String.valueOf(widgetId))); 227 Intent intent = new Intent(action, Uri.parse(String.valueOf(widgetId)));
223 intent.setClass(context, getClass()); 228 intent.setClass(context, SearchWidgetProvider.class);
224 IntentHandler.addTrustedIntentExtras(intent); 229 IntentHandler.addTrustedIntentExtras(intent);
225 return intent; 230 return intent;
226 } 231 }
232
233 /** Immediately updates all widgets. */
234 private static void updateAllWidgets() {
235 performUpdate(ContextUtils.getApplicationContext());
236 }
227 } 237 }
OLDNEW
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698