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