1 /* 2 * Copyright (C) 2011 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 17 package android.support.v4.widget; 18 19 import android.app.SearchManager; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.os.Build; 23 import android.view.View; 24 import android.widget.TextView; 25 26 /** 27 * Helper for accessing features in {@link android.widget.SearchView} 28 * introduced after API level 4 in a backwards compatible fashion. 29 */ 30 public class SearchViewCompat { 31 32 interface SearchViewCompatImpl { newSearchView(Context context)33 View newSearchView(Context context); setSearchableInfo(View searchView, ComponentName searchableComponent)34 void setSearchableInfo(View searchView, ComponentName searchableComponent); setImeOptions(View searchView, int imeOptions)35 void setImeOptions(View searchView, int imeOptions); setInputType(View searchView, int inputType)36 void setInputType(View searchView, int inputType); newOnQueryTextListener(OnQueryTextListenerCompat listener)37 Object newOnQueryTextListener(OnQueryTextListenerCompat listener); setOnQueryTextListener(Object searchView, Object listener)38 void setOnQueryTextListener(Object searchView, Object listener); newOnCloseListener(OnCloseListenerCompat listener)39 Object newOnCloseListener(OnCloseListenerCompat listener); setOnCloseListener(Object searchView, Object listener)40 void setOnCloseListener(Object searchView, Object listener); getQuery(View searchView)41 CharSequence getQuery(View searchView); setQuery(View searchView, CharSequence query, boolean submit)42 void setQuery(View searchView, CharSequence query, boolean submit); setQueryHint(View searchView, CharSequence hint)43 void setQueryHint(View searchView, CharSequence hint); setIconified(View searchView, boolean iconify)44 void setIconified(View searchView, boolean iconify); isIconified(View searchView)45 boolean isIconified(View searchView); setSubmitButtonEnabled(View searchView, boolean enabled)46 void setSubmitButtonEnabled(View searchView, boolean enabled); isSubmitButtonEnabled(View searchView)47 boolean isSubmitButtonEnabled(View searchView); setQueryRefinementEnabled(View searchView, boolean enable)48 void setQueryRefinementEnabled(View searchView, boolean enable); isQueryRefinementEnabled(View searchView)49 boolean isQueryRefinementEnabled(View searchView); setMaxWidth(View searchView, int maxpixels)50 void setMaxWidth(View searchView, int maxpixels); 51 } 52 53 static class SearchViewCompatStubImpl implements SearchViewCompatImpl { 54 55 @Override newSearchView(Context context)56 public View newSearchView(Context context) { 57 return null; 58 } 59 60 @Override setSearchableInfo(View searchView, ComponentName searchableComponent)61 public void setSearchableInfo(View searchView, ComponentName searchableComponent) { 62 } 63 64 @Override setImeOptions(View searchView, int imeOptions)65 public void setImeOptions(View searchView, int imeOptions) { 66 } 67 68 @Override setInputType(View searchView, int inputType)69 public void setInputType(View searchView, int inputType) { 70 } 71 72 @Override newOnQueryTextListener(OnQueryTextListenerCompat listener)73 public Object newOnQueryTextListener(OnQueryTextListenerCompat listener) { 74 return null; 75 } 76 77 @Override setOnQueryTextListener(Object searchView, Object listener)78 public void setOnQueryTextListener(Object searchView, Object listener) { 79 } 80 81 @Override newOnCloseListener(OnCloseListenerCompat listener)82 public Object newOnCloseListener(OnCloseListenerCompat listener) { 83 return null; 84 } 85 86 @Override setOnCloseListener(Object searchView, Object listener)87 public void setOnCloseListener(Object searchView, Object listener) { 88 } 89 90 @Override getQuery(View searchView)91 public CharSequence getQuery(View searchView) { 92 return null; 93 } 94 95 @Override setQuery(View searchView, CharSequence query, boolean submit)96 public void setQuery(View searchView, CharSequence query, boolean submit) { 97 } 98 99 @Override setQueryHint(View searchView, CharSequence hint)100 public void setQueryHint(View searchView, CharSequence hint) { 101 } 102 103 @Override setIconified(View searchView, boolean iconify)104 public void setIconified(View searchView, boolean iconify) { 105 } 106 107 @Override isIconified(View searchView)108 public boolean isIconified(View searchView) { 109 return true; 110 } 111 112 @Override setSubmitButtonEnabled(View searchView, boolean enabled)113 public void setSubmitButtonEnabled(View searchView, boolean enabled) { 114 } 115 116 @Override isSubmitButtonEnabled(View searchView)117 public boolean isSubmitButtonEnabled(View searchView) { 118 return false; 119 } 120 121 @Override setQueryRefinementEnabled(View searchView, boolean enable)122 public void setQueryRefinementEnabled(View searchView, boolean enable) { 123 } 124 125 @Override isQueryRefinementEnabled(View searchView)126 public boolean isQueryRefinementEnabled(View searchView) { 127 return false; 128 } 129 130 @Override setMaxWidth(View searchView, int maxpixels)131 public void setMaxWidth(View searchView, int maxpixels) { 132 } 133 } 134 135 static class SearchViewCompatHoneycombImpl extends SearchViewCompatStubImpl { 136 137 @Override newSearchView(Context context)138 public View newSearchView(Context context) { 139 return SearchViewCompatHoneycomb.newSearchView(context); 140 } 141 142 @Override setSearchableInfo(View searchView, ComponentName searchableComponent)143 public void setSearchableInfo(View searchView, ComponentName searchableComponent) { 144 SearchViewCompatHoneycomb.setSearchableInfo(searchView, searchableComponent); 145 } 146 147 @Override newOnQueryTextListener(final OnQueryTextListenerCompat listener)148 public Object newOnQueryTextListener(final OnQueryTextListenerCompat listener) { 149 return SearchViewCompatHoneycomb.newOnQueryTextListener( 150 new SearchViewCompatHoneycomb.OnQueryTextListenerCompatBridge() { 151 @Override 152 public boolean onQueryTextSubmit(String query) { 153 return listener.onQueryTextSubmit(query); 154 } 155 @Override 156 public boolean onQueryTextChange(String newText) { 157 return listener.onQueryTextChange(newText); 158 } 159 }); 160 } 161 162 @Override setOnQueryTextListener(Object searchView, Object listener)163 public void setOnQueryTextListener(Object searchView, Object listener) { 164 SearchViewCompatHoneycomb.setOnQueryTextListener(searchView, listener); 165 } 166 167 @Override newOnCloseListener(final OnCloseListenerCompat listener)168 public Object newOnCloseListener(final OnCloseListenerCompat listener) { 169 return SearchViewCompatHoneycomb.newOnCloseListener( 170 new SearchViewCompatHoneycomb.OnCloseListenerCompatBridge() { 171 @Override 172 public boolean onClose() { 173 return listener.onClose(); 174 } 175 }); 176 } 177 178 @Override 179 public void setOnCloseListener(Object searchView, Object listener) { 180 SearchViewCompatHoneycomb.setOnCloseListener(searchView, listener); 181 } 182 183 @Override 184 public CharSequence getQuery(View searchView) { 185 return SearchViewCompatHoneycomb.getQuery(searchView); 186 } 187 188 @Override 189 public void setQuery(View searchView, CharSequence query, boolean submit) { 190 SearchViewCompatHoneycomb.setQuery(searchView, query, submit); 191 } 192 193 @Override 194 public void setQueryHint(View searchView, CharSequence hint) { 195 SearchViewCompatHoneycomb.setQueryHint(searchView, hint); 196 } 197 198 @Override 199 public void setIconified(View searchView, boolean iconify) { 200 SearchViewCompatHoneycomb.setIconified(searchView, iconify); 201 } 202 203 @Override 204 public boolean isIconified(View searchView) { 205 return SearchViewCompatHoneycomb.isIconified(searchView); 206 } 207 208 @Override 209 public void setSubmitButtonEnabled(View searchView, boolean enabled) { 210 SearchViewCompatHoneycomb.setSubmitButtonEnabled(searchView, enabled); 211 } 212 213 @Override 214 public boolean isSubmitButtonEnabled(View searchView) { 215 return SearchViewCompatHoneycomb.isSubmitButtonEnabled(searchView); 216 } 217 218 @Override 219 public void setQueryRefinementEnabled(View searchView, boolean enable) { 220 SearchViewCompatHoneycomb.setQueryRefinementEnabled(searchView, enable); 221 } 222 223 @Override 224 public boolean isQueryRefinementEnabled(View searchView) { 225 return SearchViewCompatHoneycomb.isQueryRefinementEnabled(searchView); 226 } 227 228 @Override 229 public void setMaxWidth(View searchView, int maxpixels) { 230 SearchViewCompatHoneycomb.setMaxWidth(searchView, maxpixels); 231 } 232 } 233 234 static class SearchViewCompatIcsImpl extends SearchViewCompatHoneycombImpl { 235 236 @Override 237 public View newSearchView(Context context) { 238 return SearchViewCompatIcs.newSearchView(context); 239 } 240 241 @Override 242 public void setImeOptions(View searchView, int imeOptions) { 243 SearchViewCompatIcs.setImeOptions(searchView, imeOptions); 244 } 245 246 @Override 247 public void setInputType(View searchView, int inputType) { 248 SearchViewCompatIcs.setInputType(searchView, inputType); 249 } 250 } 251 252 private static final SearchViewCompatImpl IMPL; 253 254 static { 255 if (Build.VERSION.SDK_INT >= 14) { // ICS 256 IMPL = new SearchViewCompatIcsImpl(); 257 } else if (Build.VERSION.SDK_INT >= 11) { // Honeycomb 258 IMPL = new SearchViewCompatHoneycombImpl(); 259 } else { 260 IMPL = new SearchViewCompatStubImpl(); 261 } 262 } 263 264 private SearchViewCompat(Context context) { 265 /* Hide constructor */ 266 } 267 268 /** 269 * Creates a new SearchView. 270 * 271 * @param context The Context the view is running in. 272 * @return A SearchView instance if the class is present on the current 273 * platform, null otherwise. 274 */ 275 public static View newSearchView(Context context) { 276 return IMPL.newSearchView(context); 277 } 278 279 /** 280 * Sets the SearchableInfo for this SearchView. Properties in the SearchableInfo are used 281 * to display labels, hints, suggestions, create intents for launching search results screens 282 * and controlling other affordances such as a voice button. 283 * 284 * @param searchView The SearchView to operate on. 285 * @param searchableComponent The application component whose 286 * {@link android.app.SearchableInfo} should be loaded and applied to 287 * the SearchView. 288 */ 289 public static void setSearchableInfo(View searchView, ComponentName searchableComponent) { 290 IMPL.setSearchableInfo(searchView, searchableComponent); 291 } 292 293 /** 294 * Sets the IME options on the query text field. This is a no-op if 295 * called on pre-{@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} 296 * platforms. 297 * 298 * @see TextView#setImeOptions(int) 299 * @param searchView The SearchView to operate on. 300 * @param imeOptions the options to set on the query text field 301 */ 302 public static void setImeOptions(View searchView, int imeOptions) { 303 IMPL.setImeOptions(searchView, imeOptions); 304 } 305 306 /** 307 * Sets the input type on the query text field. This is a no-op if 308 * called on pre-{@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} 309 * platforms. 310 * 311 * @see TextView#setInputType(int) 312 * @param searchView The SearchView to operate on. 313 * @param inputType the input type to set on the query text field 314 */ 315 public static void setInputType(View searchView, int inputType) { 316 IMPL.setInputType(searchView, inputType); 317 } 318 319 /** 320 * Sets a listener for user actions within the SearchView. 321 * 322 * @param searchView The SearchView in which to register the listener. 323 * @param listener the listener object that receives callbacks when the user performs 324 * actions in the SearchView such as clicking on buttons or typing a query. 325 */ 326 public static void setOnQueryTextListener(View searchView, OnQueryTextListenerCompat listener) { 327 IMPL.setOnQueryTextListener(searchView, listener.mListener); 328 } 329 330 /** 331 * Callbacks for changes to the query text. 332 */ 333 public static abstract class OnQueryTextListenerCompat { 334 final Object mListener; 335 336 public OnQueryTextListenerCompat() { 337 mListener = IMPL.newOnQueryTextListener(this); 338 } 339 340 /** 341 * Called when the user submits the query. This could be due to a key press on the 342 * keyboard or due to pressing a submit button. 343 * The listener can override the standard behavior by returning true 344 * to indicate that it has handled the submit request. Otherwise return false to 345 * let the SearchView handle the submission by launching any associated intent. 346 * 347 * @param query the query text that is to be submitted 348 * 349 * @return true if the query has been handled by the listener, false to let the 350 * SearchView perform the default action. 351 */ 352 public boolean onQueryTextSubmit(String query) { 353 return false; 354 } 355 356 /** 357 * Called when the query text is changed by the user. 358 * 359 * @param newText the new content of the query text field. 360 * 361 * @return false if the SearchView should perform the default action of showing any 362 * suggestions if available, true if the action was handled by the listener. 363 */ 364 public boolean onQueryTextChange(String newText) { 365 return false; 366 } 367 } 368 369 /** 370 * Sets a listener to inform when the user closes the SearchView. 371 * 372 * @param searchView The SearchView in which to register the listener. 373 * @param listener the listener to call when the user closes the SearchView. 374 */ 375 public static void setOnCloseListener(View searchView, OnCloseListenerCompat listener) { 376 IMPL.setOnCloseListener(searchView, listener.mListener); 377 } 378 379 /** 380 * Callback for closing the query UI. 381 */ 382 public static abstract class OnCloseListenerCompat { 383 final Object mListener; 384 385 public OnCloseListenerCompat() { 386 mListener = IMPL.newOnCloseListener(this); 387 } 388 389 /** 390 * The user is attempting to close the SearchView. 391 * 392 * @return true if the listener wants to override the default behavior of clearing the 393 * text field and dismissing it, false otherwise. 394 */ 395 public boolean onClose() { 396 return false; 397 } 398 } 399 400 /** 401 * Returns the query string currently in the text field. 402 * 403 * @param searchView The SearchView to operate on. 404 * 405 * @return the query string 406 */ 407 public static CharSequence getQuery(View searchView) { 408 return IMPL.getQuery(searchView); 409 } 410 411 /** 412 * Sets a query string in the text field and optionally submits the query as well. 413 * 414 * @param searchView The SearchView to operate on. 415 * @param query the query string. This replaces any query text already present in the 416 * text field. 417 * @param submit whether to submit the query right now or only update the contents of 418 * text field. 419 */ 420 public static void setQuery(View searchView, CharSequence query, boolean submit) { 421 IMPL.setQuery(searchView, query, submit); 422 } 423 424 /** 425 * Sets the hint text to display in the query text field. This overrides any hint specified 426 * in the SearchableInfo. 427 * 428 * @param searchView The SearchView to operate on. 429 * @param hint the hint text to display 430 */ 431 public static void setQueryHint(View searchView, CharSequence hint) { 432 IMPL.setQueryHint(searchView, hint); 433 } 434 435 /** 436 * Iconifies or expands the SearchView. Any query text is cleared when iconified. This is 437 * a temporary state and does not override the default iconified state set by 438 * setIconifiedByDefault(boolean). If the default state is iconified, then 439 * a false here will only be valid until the user closes the field. And if the default 440 * state is expanded, then a true here will only clear the text field and not close it. 441 * 442 * @param searchView The SearchView to operate on. 443 * @param iconify a true value will collapse the SearchView to an icon, while a false will 444 * expand it. 445 */ 446 public static void setIconified(View searchView, boolean iconify) { 447 IMPL.setIconified(searchView, iconify); 448 } 449 450 /** 451 * Returns the current iconified state of the SearchView. 452 * 453 * @param searchView The SearchView to operate on. 454 * @return true if the SearchView is currently iconified, false if the search field is 455 * fully visible. 456 */ 457 public static boolean isIconified(View searchView) { 458 return IMPL.isIconified(searchView); 459 } 460 461 /** 462 * Enables showing a submit button when the query is non-empty. In cases where the SearchView 463 * is being used to filter the contents of the current activity and doesn't launch a separate 464 * results activity, then the submit button should be disabled. 465 * 466 * @param searchView The SearchView to operate on. 467 * @param enabled true to show a submit button for submitting queries, false if a submit 468 * button is not required. 469 */ 470 public static void setSubmitButtonEnabled(View searchView, boolean enabled) { 471 IMPL.setSubmitButtonEnabled(searchView, enabled); 472 } 473 474 /** 475 * Returns whether the submit button is enabled when necessary or never displayed. 476 * 477 * @param searchView The SearchView to operate on. 478 * @return whether the submit button is enabled automatically when necessary 479 */ 480 public static boolean isSubmitButtonEnabled(View searchView) { 481 return IMPL.isSubmitButtonEnabled(searchView); 482 } 483 484 /** 485 * Specifies if a query refinement button should be displayed alongside each suggestion 486 * or if it should depend on the flags set in the individual items retrieved from the 487 * suggestions provider. Clicking on the query refinement button will replace the text 488 * in the query text field with the text from the suggestion. This flag only takes effect 489 * if a SearchableInfo has been specified with {@link #setSearchableInfo(View, ComponentName)} 490 * and not when using a custom adapter. 491 * 492 * @param searchView The SearchView to operate on. 493 * @param enable true if all items should have a query refinement button, false if only 494 * those items that have a query refinement flag set should have the button. 495 * 496 * @see SearchManager#SUGGEST_COLUMN_FLAGS 497 * @see SearchManager#FLAG_QUERY_REFINEMENT 498 */ 499 public static void setQueryRefinementEnabled(View searchView, boolean enable) { 500 IMPL.setQueryRefinementEnabled(searchView, enable); 501 } 502 503 /** 504 * Returns whether query refinement is enabled for all items or only specific ones. 505 * @param searchView The SearchView to operate on. 506 * @return true if enabled for all items, false otherwise. 507 */ 508 public static boolean isQueryRefinementEnabled(View searchView) { 509 return IMPL.isQueryRefinementEnabled(searchView); 510 } 511 512 /** 513 * Makes the view at most this many pixels wide 514 * @param searchView The SearchView to operate on. 515 */ 516 public static void setMaxWidth(View searchView, int maxpixels) { 517 IMPL.setMaxWidth(searchView, maxpixels); 518 } 519 } 520