+ /**
+ * Private information regarding the latest voice search. If the Tab is not
+ * in voice search mode, this will be null.
+ */
+ private VoiceSearchData mVoiceSearchData;
+ /**
+ * Return whether the tab is in voice search mode.
+ */
+ public boolean isInVoiceSearchMode() {
+ return mVoiceSearchData != null;
+ }
+ /**
+ * Return true if the voice search Intent came with a String identifying
+ * that Google provided the Intent.
+ */
+ public boolean voiceSearchSourceIsGoogle() {
+ return mVoiceSearchData != null && mVoiceSearchData.mSourceIsGoogle;
+ }
+ /**
+ * Get the title to display for the current voice search page. If the Tab
+ * is not in voice search mode, return null.
+ */
+ public String getVoiceDisplayTitle() {
+ if (mVoiceSearchData == null) return null;
+ return mVoiceSearchData.mLastVoiceSearchTitle;
+ }
+ /**
+ * Get the latest array of voice search results, to be passed to the
+ * BrowserProvider. If the Tab is not in voice search mode, return null.
+ */
+ public ArrayList<String> getVoiceSearchResults() {
+ if (mVoiceSearchData == null) return null;
+ return mVoiceSearchData.mVoiceSearchResults;
+ }
+ /**
+ * Activate voice search mode.
+ * @param intent Intent which has the results to use, or an index into the
+ * results when reusing the old results.
+ */
+ /* package */ void activateVoiceSearchMode(Intent intent) {
+ int index = 0;
+ ArrayList<String> results = intent.getStringArrayListExtra(
+ RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_STRINGS);
+ if (results != null) {
+ ArrayList<String> urls = intent.getStringArrayListExtra(
+ RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_URLS);
+ ArrayList<String> htmls = intent.getStringArrayListExtra(
+ RecognizerResultsIntent.EXTRA_VOICE_SEARCH_RESULT_HTML);
+ ArrayList<String> baseUrls = intent.getStringArrayListExtra(
+ RecognizerResultsIntent
+ .EXTRA_VOICE_SEARCH_RESULT_HTML_BASE_URLS);
+ // This tab is now entering voice search mode for the first time, or
+ // a new voice search was done.
+ int size = results.size();
+ if (urls == null || size != urls.size()) {
+ throw new AssertionError("improper extras passed in Intent");
+ }
+ if (htmls == null || htmls.size() != size || baseUrls == null ||
+ (baseUrls.size() != size && baseUrls.size() != 1)) {
+ // If either of these arrays are empty/incorrectly sized, ignore
+ // them.
+ htmls = null;
+ baseUrls = null;
+ }
+ mVoiceSearchData = new VoiceSearchData(results, urls, htmls,
+ baseUrls);
+ mVoiceSearchData.mHeaders = intent.getParcelableArrayListExtra(
+ RecognizerResultsIntent
+ .EXTRA_VOICE_SEARCH_RESULT_HTTP_HEADERS);
+ mVoiceSearchData.mSourceIsGoogle = intent.getBooleanExtra(
+ VoiceSearchData.SOURCE_IS_GOOGLE, false);
+ mVoiceSearchData.mVoiceSearchIntent = new Intent(intent);
+ }
+ String extraData = intent.getStringExtra(
+ SearchManager.EXTRA_DATA_KEY);
+ if (extraData != null) {
+ index = Integer.parseInt(extraData);
+ if (index >= mVoiceSearchData.mVoiceSearchResults.size()) {
+ throw new AssertionError("index must be less than "
+ + "size of mVoiceSearchResults");
+ }
+ if (mVoiceSearchData.mSourceIsGoogle) {
+ Intent logIntent = new Intent(
+ LoggingEvents.ACTION_LOG_EVENT);
+ logIntent.putExtra(LoggingEvents.EXTRA_EVENT,
+ LoggingEvents.VoiceSearch.N_BEST_CHOOSE);
+ logIntent.putExtra(
+ LoggingEvents.VoiceSearch.EXTRA_N_BEST_CHOOSE_INDEX,
+ index);
+ mActivity.sendBroadcast(logIntent);
+ }
+ if (mVoiceSearchData.mVoiceSearchIntent != null) {
+ // Copy the Intent, so that each history item will have its own
+ // Intent, with different (or none) extra data.
+ Intent latest = new Intent(mVoiceSearchData.mVoiceSearchIntent);
+ latest.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
+ mVoiceSearchData.mVoiceSearchIntent = latest;
+ }
+ }
+ mVoiceSearchData.mLastVoiceSearchTitle
+ = mVoiceSearchData.mVoiceSearchResults.get(index);
+ if (mInForeground) {
+ mActivity.showVoiceTitleBar(mVoiceSearchData.mLastVoiceSearchTitle);
+ }
+ if (mVoiceSearchData.mVoiceSearchHtmls != null) {
+ // When index was found it was already ensured that it was valid
+ String uriString = mVoiceSearchData.mVoiceSearchHtmls.get(index);
+ if (uriString != null) {
+ Uri dataUri = Uri.parse(uriString);
+ if (RecognizerResultsIntent.URI_SCHEME_INLINE.equals(
+ dataUri.getScheme())) {
+ // If there is only one base URL, use it. If there are
+ // more, there will be one for each index, so use the base
+ // URL corresponding to the index.
+ String baseUrl = mVoiceSearchData.mVoiceSearchBaseUrls.get(
+ mVoiceSearchData.mVoiceSearchBaseUrls.size() > 1 ?
+ index : 0);
+ mVoiceSearchData.mLastVoiceSearchUrl = baseUrl;
+ mMainView.loadDataWithBaseURL(baseUrl,
+ uriString.substring(RecognizerResultsIntent
+ .URI_SCHEME_INLINE.length() + 1), "text/html",
+ "utf-8", baseUrl);
+ return;
+ }
+ }
+ }
+ mVoiceSearchData.mLastVoiceSearchUrl
+ = mVoiceSearchData.mVoiceSearchUrls.get(index);
+ if (null == mVoiceSearchData.mLastVoiceSearchUrl) {
+ mVoiceSearchData.mLastVoiceSearchUrl = mActivity.smartUrlFilter(
+ mVoiceSearchData.mLastVoiceSearchTitle);
+ }
+ Map<String, String> headers = null;
+ if (mVoiceSearchData.mHeaders != null) {
+ int bundleIndex = mVoiceSearchData.mHeaders.size() == 1 ? 0
+ : index;
+ Bundle bundle = mVoiceSearchData.mHeaders.get(bundleIndex);
+ if (bundle != null && !bundle.isEmpty()) {
+ Iterator<String> iter = bundle.keySet().iterator();
+ headers = new HashMap<String, String>();
+ while (iter.hasNext()) {
+ String key = iter.next();
+ headers.put(key, bundle.getString(key));
+ }
+ }
+ }
+ mMainView.loadUrl(mVoiceSearchData.mLastVoiceSearchUrl, headers);
+ }
+ /* package */ static class VoiceSearchData {
+ public VoiceSearchData(ArrayList<String> results,
+ ArrayList<String> urls, ArrayList<String> htmls,
+ ArrayList<String> baseUrls) {
+ mVoiceSearchResults = results;
+ mVoiceSearchUrls = urls;
+ mVoiceSearchHtmls = htmls;
+ mVoiceSearchBaseUrls = baseUrls;
+ }
+ /*
+ * ArrayList of suggestions to be displayed when opening the
+ * SearchManager
+ */
+ public ArrayList<String> mVoiceSearchResults;
+ /*
+ * ArrayList of urls, associated with the suggestions in
+ * mVoiceSearchResults.
+ */
+ public ArrayList<String> mVoiceSearchUrls;
+ /*
+ * ArrayList holding content to load for each item in
+ * mVoiceSearchResults.
+ */
+ public ArrayList<String> mVoiceSearchHtmls;
+ /*
+ * ArrayList holding base urls for the items in mVoiceSearchResults.
+ * If non null, this will either have the same size as
+ * mVoiceSearchResults or have a size of 1, in which case all will use
+ * the same base url
+ */
+ public ArrayList<String> mVoiceSearchBaseUrls;
+ /*
+ * The last url provided by voice search. Used for comparison to see if
+ * we are going to a page by some method besides voice search.
+ */
+ public String mLastVoiceSearchUrl;
+ /**
+ * The last title used for voice search. Needed to update the title bar
+ * when switching tabs.
+ */
+ public String mLastVoiceSearchTitle;
+ /**
+ * Whether the Intent which turned on voice search mode contained the
+ * String signifying that Google was the source.
+ */
+ public boolean mSourceIsGoogle;
+ /**
+ * List of headers to be passed into the WebView containing location
+ * information
+ */
+ public ArrayList<Bundle> mHeaders;
+ /**
+ * The Intent used to invoke voice search. Placed on the
+ * WebHistoryItem so that when coming back to a previous voice search
+ * page we can again activate voice search.
+ */
+ public Intent mVoiceSearchIntent;
+ /**
+ * String used to identify Google as the source of voice search.
+ */
+ public static String SOURCE_IS_GOOGLE
+ = "android.speech.extras.SOURCE_IS_GOOGLE";
+ }
+