SearchSupportFragment.java revision ee73a5bfd4d2460a93a9afb9d1bfce10ff875300
1/* This file is auto-generated from SearchFragment.java. DO NOT MODIFY. */ 2 3/* 4 * Copyright (C) 2014 The Android Open Source Project 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 * in compliance with the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software distributed under the License 12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 * or implied. See the License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16package android.support.v17.leanback.app; 17 18import android.support.v4.app.Fragment; 19import android.content.Intent; 20import android.graphics.drawable.Drawable; 21import android.os.Bundle; 22import android.os.Handler; 23import android.speech.SpeechRecognizer; 24import android.speech.RecognizerIntent; 25import android.support.v17.leanback.widget.ObjectAdapter; 26import android.support.v17.leanback.widget.ObjectAdapter.DataObserver; 27import android.support.v17.leanback.widget.OnItemClickedListener; 28import android.support.v17.leanback.widget.OnItemSelectedListener; 29import android.support.v17.leanback.widget.OnItemViewClickedListener; 30import android.support.v17.leanback.widget.OnItemViewSelectedListener; 31import android.support.v17.leanback.widget.Row; 32import android.support.v17.leanback.widget.RowPresenter; 33import android.support.v17.leanback.widget.SearchBar; 34import android.support.v17.leanback.widget.VerticalGridView; 35import android.support.v17.leanback.widget.Presenter.ViewHolder; 36import android.support.v17.leanback.widget.SpeechRecognitionCallback; 37import android.util.Log; 38import android.view.LayoutInflater; 39import android.view.View; 40import android.view.ViewGroup; 41import android.widget.FrameLayout; 42import android.support.v17.leanback.R; 43 44import java.util.ArrayList; 45import java.util.List; 46 47/** 48 * A fragment to handle searches. An application will supply an implementation 49 * of the {@link SearchResultProvider} interface to handle the search and return 50 * an {@link ObjectAdapter} containing the results. The results are rendered 51 * into a {@link RowsSupportFragment}, in the same way that they are in a {@link 52 * BrowseSupportFragment}. 53 * 54 * <p>If you do not supply a callback via 55 * {@link #setSpeechRecognitionCallback(SpeechRecognitionCallback)}, an internal speech 56 * recognizer will be used for which your application will need to request 57 * android.permission.RECORD_AUDIO. 58 * </p> 59 * <p> 60 * Speech recognition is automatically started when fragment is created, but 61 * not when fragment is restored from an instance state. Activity may manually 62 * call {@link #startRecognition()}, typically in onNewIntent(). 63 * </p> 64 */ 65public class SearchSupportFragment extends Fragment { 66 private static final String TAG = SearchSupportFragment.class.getSimpleName(); 67 private static final boolean DEBUG = false; 68 69 private static final String EXTRA_LEANBACK_BADGE_PRESENT = "LEANBACK_BADGE_PRESENT"; 70 private static final String ARG_PREFIX = SearchSupportFragment.class.getCanonicalName(); 71 private static final String ARG_QUERY = ARG_PREFIX + ".query"; 72 private static final String ARG_TITLE = ARG_PREFIX + ".title"; 73 74 private static final long SPEECH_RECOGNITION_DELAY_MS = 300; 75 76 private static final int RESULTS_CHANGED = 0x1; 77 private static final int QUERY_COMPLETE = 0x2; 78 79 /** 80 * Search API to be provided by the application. 81 */ 82 public static interface SearchResultProvider { 83 /** 84 * <p>Method invoked some time prior to the first call to onQueryTextChange to retrieve 85 * an ObjectAdapter that will contain the results to future updates of the search query.</p> 86 * 87 * <p>As results are retrieved, the application should use the data set notification methods 88 * on the ObjectAdapter to instruct the SearchSupportFragment to update the results.</p> 89 * 90 * @return ObjectAdapter The result object adapter. 91 */ 92 public ObjectAdapter getResultsAdapter(); 93 94 /** 95 * <p>Method invoked when the search query is updated.</p> 96 * 97 * <p>This is called as soon as the query changes; it is up to the application to add a 98 * delay before actually executing the queries if needed. 99 * 100 * <p>This method might not always be called before onQueryTextSubmit gets called, in 101 * particular for voice input. 102 * 103 * @param newQuery The current search query. 104 * @return whether the results changed as a result of the new query. 105 */ 106 public boolean onQueryTextChange(String newQuery); 107 108 /** 109 * Method invoked when the search query is submitted, either by dismissing the keyboard, 110 * pressing search or next on the keyboard or when voice has detected the end of the query. 111 * 112 * @param query The query entered. 113 * @return whether the results changed as a result of the query. 114 */ 115 public boolean onQueryTextSubmit(String query); 116 } 117 118 private final DataObserver mAdapterObserver = new DataObserver() { 119 @Override 120 public void onChanged() { 121 // onChanged() may be called multiple times e.g. the provider add 122 // rows to ArrayObjectAdapter one by one. 123 mHandler.removeCallbacks(mResultsChangedCallback); 124 mHandler.post(mResultsChangedCallback); 125 } 126 }; 127 128 private final Handler mHandler = new Handler(); 129 130 private final Runnable mResultsChangedCallback = new Runnable() { 131 @Override 132 public void run() { 133 if (DEBUG) Log.v(TAG, "results changed, new size " + mResultAdapter.size()); 134 if (mRowsSupportFragment != null 135 && mRowsSupportFragment.getAdapter() != mResultAdapter) { 136 if (!(mRowsSupportFragment.getAdapter() == null && mResultAdapter.size() == 0)) { 137 mRowsSupportFragment.setAdapter(mResultAdapter); 138 mRowsSupportFragment.setSelectedPosition(0); 139 } 140 } 141 mStatus |= RESULTS_CHANGED; 142 if ((mStatus & QUERY_COMPLETE) != 0) { 143 updateFocus(); 144 } 145 updateSearchBarNextFocusId(); 146 } 147 }; 148 149 /** 150 * Runs when a new provider is set AND when the fragment view is created. 151 */ 152 private final Runnable mSetSearchResultProvider = new Runnable() { 153 @Override 154 public void run() { 155 if (mRowsSupportFragment == null) { 156 // We'll retry once we have a rows fragment 157 return; 158 } 159 // Retrieve the result adapter 160 ObjectAdapter adapter = mProvider.getResultsAdapter(); 161 if (DEBUG) Log.v(TAG, "Got results adapter " + adapter); 162 if (adapter != mResultAdapter) { 163 boolean firstTime = mResultAdapter == null; 164 releaseAdapter(); 165 mResultAdapter = adapter; 166 if (mResultAdapter != null) { 167 mResultAdapter.registerObserver(mAdapterObserver); 168 } 169 if (DEBUG) Log.v(TAG, "mResultAdapter " + mResultAdapter + " size " + 170 (mResultAdapter == null ? 0 : mResultAdapter.size())); 171 // delay the first time to avoid setting a empty result adapter 172 // until we got first onChange() from the provider 173 if (!(firstTime && (mResultAdapter == null || mResultAdapter.size() == 0))) { 174 mRowsSupportFragment.setAdapter(mResultAdapter); 175 } 176 executePendingQuery(); 177 } 178 updateSearchBarNextFocusId(); 179 180 if (DEBUG) Log.v(TAG, "mAutoStartRecognition " + mAutoStartRecognition + 181 " mResultAdapter " + mResultAdapter + 182 " adapter " + mRowsSupportFragment.getAdapter()); 183 if (mAutoStartRecognition) { 184 mHandler.removeCallbacks(mStartRecognitionRunnable); 185 mHandler.postDelayed(mStartRecognitionRunnable, SPEECH_RECOGNITION_DELAY_MS); 186 } else { 187 updateFocus(); 188 } 189 } 190 }; 191 192 private final Runnable mStartRecognitionRunnable = new Runnable() { 193 @Override 194 public void run() { 195 mAutoStartRecognition = false; 196 mSearchBar.startRecognition(); 197 } 198 }; 199 200 private RowsSupportFragment mRowsSupportFragment; 201 private SearchBar mSearchBar; 202 private SearchResultProvider mProvider; 203 private String mPendingQuery = null; 204 205 private OnItemSelectedListener mOnItemSelectedListener; 206 private OnItemClickedListener mOnItemClickedListener; 207 private OnItemViewSelectedListener mOnItemViewSelectedListener; 208 private OnItemViewClickedListener mOnItemViewClickedListener; 209 private ObjectAdapter mResultAdapter; 210 private SpeechRecognitionCallback mSpeechRecognitionCallback; 211 212 private String mTitle; 213 private Drawable mBadgeDrawable; 214 private ExternalQuery mExternalQuery; 215 216 private SpeechRecognizer mSpeechRecognizer; 217 218 private int mStatus; 219 private boolean mAutoStartRecognition = true; 220 221 /** 222 * @param args Bundle to use for the arguments, if null a new Bundle will be created. 223 */ 224 public static Bundle createArgs(Bundle args, String query) { 225 return createArgs(args, query, null); 226 } 227 228 public static Bundle createArgs(Bundle args, String query, String title) { 229 if (args == null) { 230 args = new Bundle(); 231 } 232 args.putString(ARG_QUERY, query); 233 args.putString(ARG_TITLE, title); 234 return args; 235 } 236 237 /** 238 * Create a search fragment with a given search query. 239 * 240 * <p>You should only use this if you need to start the search fragment with a 241 * pre-filled query. 242 * 243 * @param query The search query to begin with. 244 * @return A new SearchSupportFragment. 245 */ 246 public static SearchSupportFragment newInstance(String query) { 247 SearchSupportFragment fragment = new SearchSupportFragment(); 248 Bundle args = createArgs(null, query); 249 fragment.setArguments(args); 250 return fragment; 251 } 252 253 @Override 254 public void onCreate(Bundle savedInstanceState) { 255 if (mAutoStartRecognition) { 256 mAutoStartRecognition = savedInstanceState == null; 257 } 258 super.onCreate(savedInstanceState); 259 } 260 261 @Override 262 public View onCreateView(LayoutInflater inflater, ViewGroup container, 263 Bundle savedInstanceState) { 264 View root = inflater.inflate(R.layout.lb_search_fragment, container, false); 265 266 FrameLayout searchFrame = (FrameLayout) root.findViewById(R.id.lb_search_frame); 267 mSearchBar = (SearchBar) searchFrame.findViewById(R.id.lb_search_bar); 268 mSearchBar.setSearchBarListener(new SearchBar.SearchBarListener() { 269 @Override 270 public void onSearchQueryChange(String query) { 271 if (DEBUG) Log.v(TAG, String.format("onSearchQueryChange %s %s", query, 272 null == mProvider ? "(null)" : mProvider)); 273 if (null != mProvider) { 274 retrieveResults(query); 275 } else { 276 mPendingQuery = query; 277 } 278 } 279 280 @Override 281 public void onSearchQuerySubmit(String query) { 282 if (DEBUG) Log.v(TAG, String.format("onSearchQuerySubmit %s", query)); 283 submitQuery(query); 284 } 285 286 @Override 287 public void onKeyboardDismiss(String query) { 288 if (DEBUG) Log.v(TAG, String.format("onKeyboardDismiss %s", query)); 289 queryComplete(); 290 } 291 }); 292 mSearchBar.setSpeechRecognitionCallback(mSpeechRecognitionCallback); 293 applyExternalQuery(); 294 295 readArguments(getArguments()); 296 if (null != mBadgeDrawable) { 297 setBadgeDrawable(mBadgeDrawable); 298 } 299 if (null != mTitle) { 300 setTitle(mTitle); 301 } 302 303 // Inject the RowsSupportFragment in the results container 304 if (getChildFragmentManager().findFragmentById(R.id.lb_results_frame) == null) { 305 mRowsSupportFragment = new RowsSupportFragment(); 306 getChildFragmentManager().beginTransaction() 307 .replace(R.id.lb_results_frame, mRowsSupportFragment).commit(); 308 } else { 309 mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager() 310 .findFragmentById(R.id.lb_results_frame); 311 } 312 mRowsSupportFragment.setOnItemViewSelectedListener(new OnItemViewSelectedListener() { 313 @Override 314 public void onItemSelected(ViewHolder itemViewHolder, Object item, 315 RowPresenter.ViewHolder rowViewHolder, Row row) { 316 int position = mRowsSupportFragment.getVerticalGridView().getSelectedPosition(); 317 if (DEBUG) Log.v(TAG, String.format("onItemSelected %d", position)); 318 mSearchBar.setVisibility(0 >= position ? View.VISIBLE : View.GONE); 319 if (null != mOnItemSelectedListener) { 320 mOnItemSelectedListener.onItemSelected(item, row); 321 } 322 if (null != mOnItemViewSelectedListener) { 323 mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item, 324 rowViewHolder, row); 325 } 326 } 327 }); 328 mRowsSupportFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() { 329 @Override 330 public void onItemClicked(ViewHolder itemViewHolder, Object item, 331 RowPresenter.ViewHolder rowViewHolder, Row row) { 332 int position = mRowsSupportFragment.getVerticalGridView().getSelectedPosition(); 333 if (DEBUG) Log.v(TAG, String.format("onItemClicked %d", position)); 334 if (null != mOnItemClickedListener) { 335 mOnItemClickedListener.onItemClicked(item, row); 336 } 337 if (null != mOnItemViewClickedListener) { 338 mOnItemViewClickedListener.onItemClicked(itemViewHolder, item, 339 rowViewHolder, row); 340 } 341 } 342 }); 343 mRowsSupportFragment.setExpand(true); 344 if (null != mProvider) { 345 onSetSearchResultProvider(); 346 } 347 return root; 348 } 349 350 private void resultsAvailable() { 351 if ((mStatus & QUERY_COMPLETE) != 0) { 352 focusOnResults(); 353 } 354 updateSearchBarNextFocusId(); 355 } 356 357 @Override 358 public void onStart() { 359 super.onStart(); 360 361 VerticalGridView list = mRowsSupportFragment.getVerticalGridView(); 362 int mContainerListAlignTop = 363 getResources().getDimensionPixelSize(R.dimen.lb_search_browse_rows_align_top); 364 list.setItemAlignmentOffset(0); 365 list.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED); 366 list.setWindowAlignmentOffset(mContainerListAlignTop); 367 list.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 368 list.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 369 } 370 371 @Override 372 public void onResume() { 373 super.onResume(); 374 if (mSpeechRecognitionCallback == null && null == mSpeechRecognizer) { 375 mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(getActivity()); 376 mSearchBar.setSpeechRecognizer(mSpeechRecognizer); 377 } 378 // Ensure search bar state consistency when using external recognizer 379 mSearchBar.stopRecognition(); 380 } 381 382 @Override 383 public void onPause() { 384 releaseRecognizer(); 385 super.onPause(); 386 } 387 388 @Override 389 public void onDestroy() { 390 releaseAdapter(); 391 super.onDestroy(); 392 } 393 394 private void releaseRecognizer() { 395 if (null != mSpeechRecognizer) { 396 mSearchBar.setSpeechRecognizer(null); 397 mSpeechRecognizer.destroy(); 398 mSpeechRecognizer = null; 399 } 400 } 401 402 /** 403 * Starts speech recognition. Typical use case is that 404 * activity receives onNewIntent() call when user clicks a MIC button. 405 * Note that SearchSupportFragment automatically starts speech recognition 406 * at first time created, there is no need to call startRecognition() 407 * when fragment is created. 408 */ 409 public void startRecognition() { 410 mSearchBar.startRecognition(); 411 } 412 413 /** 414 * Set the search provider that is responsible for returning results for the 415 * search query. 416 */ 417 public void setSearchResultProvider(SearchResultProvider searchResultProvider) { 418 if (mProvider != searchResultProvider) { 419 mProvider = searchResultProvider; 420 onSetSearchResultProvider(); 421 } 422 } 423 424 /** 425 * Sets an item selection listener for the results. 426 * 427 * @param listener The item selection listener to be invoked when an item in 428 * the search results is selected. 429 * @deprecated Use {@link #setOnItemViewSelectedListener(OnItemViewSelectedListener)} 430 */ 431 public void setOnItemSelectedListener(OnItemSelectedListener listener) { 432 mOnItemSelectedListener = listener; 433 } 434 435 /** 436 * Sets an item clicked listener for the results. 437 * 438 * @param listener The item clicked listener to be invoked when an item in 439 * the search results is clicked. 440 * @deprecated Use {@link #setOnItemViewClickedListener(OnItemViewClickedListener)} 441 */ 442 public void setOnItemClickedListener(OnItemClickedListener listener) { 443 mOnItemClickedListener = listener; 444 } 445 446 /** 447 * Sets an item selection listener for the results. 448 * 449 * @param listener The item selection listener to be invoked when an item in 450 * the search results is selected. 451 */ 452 public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) { 453 mOnItemViewSelectedListener = listener; 454 } 455 456 /** 457 * Sets an item clicked listener for the results. 458 * 459 * @param listener The item clicked listener to be invoked when an item in 460 * the search results is clicked. 461 */ 462 public void setOnItemViewClickedListener(OnItemViewClickedListener listener) { 463 mOnItemViewClickedListener = listener; 464 } 465 466 /** 467 * Sets the title string to be be shown in an empty search bar. The title 468 * may be placed in a call-to-action, such as "Search <i>title</i>" or 469 * "Speak to search <i>title</i>". 470 */ 471 public void setTitle(String title) { 472 mTitle = title; 473 if (null != mSearchBar) { 474 mSearchBar.setTitle(title); 475 } 476 } 477 478 /** 479 * Returns the title set in the search bar. 480 */ 481 public String getTitle() { 482 if (null != mSearchBar) { 483 return mSearchBar.getTitle(); 484 } 485 return null; 486 } 487 488 /** 489 * Sets the badge drawable that will be shown inside the search bar next to 490 * the title. 491 */ 492 public void setBadgeDrawable(Drawable drawable) { 493 mBadgeDrawable = drawable; 494 if (null != mSearchBar) { 495 mSearchBar.setBadgeDrawable(drawable); 496 } 497 } 498 499 /** 500 * Returns the badge drawable in the search bar. 501 */ 502 public Drawable getBadgeDrawable() { 503 if (null != mSearchBar) { 504 return mSearchBar.getBadgeDrawable(); 505 } 506 return null; 507 } 508 509 /** 510 * Display the completions shown by the IME. An application may provide 511 * a list of query completions that the system will show in the IME. 512 * 513 * @param completions A list of completions to show in the IME. Setting to 514 * null or empty will clear the list. 515 */ 516 public void displayCompletions(List<String> completions) { 517 mSearchBar.displayCompletions(completions); 518 } 519 520 /** 521 * Set this callback to have the fragment pass speech recognition requests 522 * to the activity rather than using an internal recognizer. 523 */ 524 public void setSpeechRecognitionCallback(SpeechRecognitionCallback callback) { 525 mSpeechRecognitionCallback = callback; 526 if (mSearchBar != null) { 527 mSearchBar.setSpeechRecognitionCallback(mSpeechRecognitionCallback); 528 } 529 if (callback != null) { 530 releaseRecognizer(); 531 } 532 } 533 534 /** 535 * Sets the text of the search query and optionally submits the query. Either 536 * {@link SearchResultProvider#onQueryTextChange onQueryTextChange} or 537 * {@link SearchResultProvider#onQueryTextSubmit onQueryTextSubmit} will be 538 * called on the provider if it is set. 539 * 540 * @param query The search query to set. 541 * @param submit Whether to submit the query. 542 */ 543 public void setSearchQuery(String query, boolean submit) { 544 if (DEBUG) Log.v(TAG, "setSearchQuery " + query + " submit " + submit); 545 if (query == null) { 546 return; 547 } 548 mExternalQuery = new ExternalQuery(query, submit); 549 applyExternalQuery(); 550 if (mAutoStartRecognition) { 551 mAutoStartRecognition = false; 552 mHandler.removeCallbacks(mStartRecognitionRunnable); 553 } 554 } 555 556 /** 557 * Sets the text of the search query based on the {@link RecognizerIntent#EXTRA_RESULTS} in 558 * the given intent, and optionally submit the query. If more than one result is present 559 * in the results list, the first will be used. 560 * 561 * @param intent Intent received from a speech recognition service. 562 * @param submit Whether to submit the query. 563 */ 564 public void setSearchQuery(Intent intent, boolean submit) { 565 ArrayList<String> matches = intent.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); 566 if (matches != null && matches.size() > 0) { 567 setSearchQuery(matches.get(0), submit); 568 } 569 } 570 571 /** 572 * Returns an intent that can be used to request speech recognition. 573 * Built from the base {@link RecognizerIntent#ACTION_RECOGNIZE_SPEECH} plus 574 * extras: 575 * 576 * <ul> 577 * <li>{@link RecognizerIntent#EXTRA_LANGUAGE_MODEL} set to 578 * {@link RecognizerIntent#LANGUAGE_MODEL_FREE_FORM}</li> 579 * <li>{@link RecognizerIntent#EXTRA_PARTIAL_RESULTS} set to true</li> 580 * <li>{@link RecognizerIntent#EXTRA_PROMPT} set to the search bar hint text</li> 581 * </ul> 582 * 583 * For handling the intent returned from the service, see 584 * {@link #setSearchQuery(Intent, boolean)}. 585 */ 586 public Intent getRecognizerIntent() { 587 Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 588 recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 589 RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 590 recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); 591 if (mSearchBar != null && mSearchBar.getHint() != null) { 592 recognizerIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, mSearchBar.getHint()); 593 } 594 recognizerIntent.putExtra(EXTRA_LEANBACK_BADGE_PRESENT, mBadgeDrawable != null); 595 return recognizerIntent; 596 } 597 598 private void retrieveResults(String searchQuery) { 599 if (DEBUG) Log.v(TAG, "retrieveResults " + searchQuery); 600 if (mProvider.onQueryTextChange(searchQuery)) { 601 mStatus &= ~QUERY_COMPLETE; 602 } 603 } 604 605 private void submitQuery(String query) { 606 queryComplete(); 607 if (null != mProvider) { 608 mProvider.onQueryTextSubmit(query); 609 } 610 } 611 612 private void queryComplete() { 613 if (DEBUG) Log.v(TAG, "queryComplete"); 614 mStatus |= QUERY_COMPLETE; 615 focusOnResults(); 616 } 617 618 private void updateSearchBarNextFocusId() { 619 if (mSearchBar == null || mResultAdapter == null) { 620 return; 621 } 622 final int viewId = (mResultAdapter.size() == 0 || mRowsSupportFragment == null || 623 mRowsSupportFragment.getVerticalGridView() == null) ? 0 : 624 mRowsSupportFragment.getVerticalGridView().getId(); 625 mSearchBar.setNextFocusDownId(viewId); 626 } 627 628 private void updateFocus() { 629 if (mResultAdapter != null && mResultAdapter.size() > 0 && 630 mRowsSupportFragment != null && mRowsSupportFragment.getAdapter() == mResultAdapter) { 631 focusOnResults(); 632 } else { 633 mSearchBar.requestFocus(); 634 } 635 } 636 637 private void focusOnResults() { 638 if (mRowsSupportFragment == null || 639 mRowsSupportFragment.getVerticalGridView() == null || 640 mResultAdapter.size() == 0) { 641 return; 642 } 643 if (mRowsSupportFragment.getVerticalGridView().requestFocus()) { 644 mStatus &= ~RESULTS_CHANGED; 645 } 646 } 647 648 private void onSetSearchResultProvider() { 649 mHandler.removeCallbacks(mSetSearchResultProvider); 650 mHandler.post(mSetSearchResultProvider); 651 } 652 653 private void releaseAdapter() { 654 if (mResultAdapter != null) { 655 mResultAdapter.unregisterObserver(mAdapterObserver); 656 mResultAdapter = null; 657 } 658 } 659 660 private void executePendingQuery() { 661 if (null != mPendingQuery && null != mResultAdapter) { 662 String query = mPendingQuery; 663 mPendingQuery = null; 664 retrieveResults(query); 665 } 666 } 667 668 private void applyExternalQuery() { 669 if (mExternalQuery == null || mSearchBar == null) { 670 return; 671 } 672 mSearchBar.setSearchQuery(mExternalQuery.mQuery); 673 if (mExternalQuery.mSubmit) { 674 submitQuery(mExternalQuery.mQuery); 675 } 676 mExternalQuery = null; 677 } 678 679 private void readArguments(Bundle args) { 680 if (null == args) { 681 return; 682 } 683 if (args.containsKey(ARG_QUERY)) { 684 setSearchQuery(args.getString(ARG_QUERY)); 685 } 686 687 if (args.containsKey(ARG_TITLE)) { 688 setTitle(args.getString(ARG_TITLE)); 689 } 690 } 691 692 private void setSearchQuery(String query) { 693 mSearchBar.setSearchQuery(query); 694 } 695 696 static class ExternalQuery { 697 String mQuery; 698 boolean mSubmit; 699 700 ExternalQuery(String query, boolean submit) { 701 mQuery = query; 702 mSubmit = submit; 703 } 704 } 705} 706