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