diff options
| author | Leon Scroggins <scroggo@google.com> | 2010-01-28 15:12:40 -0500 |
|---|---|---|
| committer | Leon Scroggins <scroggo@google.com> | 2010-01-29 17:17:22 -0500 |
| commit | 58d56c6b5052faa86083965132cd51b1a9594d0e (patch) | |
| tree | ff12588ede5a3ae4eda6b1ddfb548820dc80da42 /src/com/android | |
| parent | e5073c271be740654469ea63b69bd4a505ca222c (diff) | |
| download | packages_apps_Browser-58d56c6b5052faa86083965132cd51b1a9594d0e.tar.gz packages_apps_Browser-58d56c6b5052faa86083965132cd51b1a9594d0e.tar.bz2 packages_apps_Browser-58d56c6b5052faa86083965132cd51b1a9594d0e.zip | |
Handle the voice search intent.
Once the voice search intent has been handled, the title bar
background changes to green, and touching it displays other voice
search possibilities.
Fixes http://b/issue?id=2390686
Diffstat (limited to 'src/com/android')
| -rw-r--r-- | src/com/android/browser/BrowserActivity.java | 98 | ||||
| -rw-r--r-- | src/com/android/browser/BrowserProvider.java | 94 | ||||
| -rw-r--r-- | src/com/android/browser/Tab.java | 121 | ||||
| -rw-r--r-- | src/com/android/browser/TitleBar.java | 37 |
4 files changed, 320 insertions, 30 deletions
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java index 90bacadd5..3f7c9e985 100644 --- a/src/com/android/browser/BrowserActivity.java +++ b/src/com/android/browser/BrowserActivity.java @@ -23,6 +23,8 @@ import android.app.SearchManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentProvider; +import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -381,9 +383,11 @@ public class BrowserActivity extends Activity // the tab will be close when exit. UrlData urlData = getUrlDataFromIntent(intent); + String action = intent.getAction(); final Tab t = mTabControl.createNewTab( - Intent.ACTION_VIEW.equals(intent.getAction()) && - intent.getData() != null, + (Intent.ACTION_VIEW.equals(action) && + intent.getData() != null) + || Tab.VoiceSearchData.VOICE_SEARCH_RESULTS.equals(action), intent.getStringExtra(Browser.EXTRA_APPLICATION_ID), urlData.mUrl); mTabControl.setCurrentTab(t); attachTabToContentView(t); @@ -410,7 +414,7 @@ public class BrowserActivity extends Activity waitForCredentials(); } } else { - urlData.loadIn(webView); + urlData.loadIn(t); } } else { // TabControl.restoreState() will create a new tab even if @@ -425,6 +429,24 @@ public class BrowserActivity extends Activity } } + /** + * Feed the previously stored results strings to the BrowserProvider so that + * the SearchDialog will show them instead of the standard searches. + * @param result String to show on the editable line of the SearchDialog. + */ + /* package */ void showVoiceSearchResults(String result) { + ContentProviderClient client = mResolver.acquireContentProviderClient( + Browser.BOOKMARKS_URI); + ContentProvider prov = client.getLocalContentProvider(); + BrowserProvider bp = (BrowserProvider) prov; + bp.setQueryResults(mTabControl.getCurrentTab().getVoiceSearchResults()); + client.release(); + + startSearch(result, false, + createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), + false); + } + @Override protected void onNewIntent(Intent intent) { Tab current = mTabControl.getCurrentTab(); @@ -448,10 +470,13 @@ public class BrowserActivity extends Activity // just resume the browser return; } + boolean activateVoiceSearch = Tab.VoiceSearchData.VOICE_SEARCH_RESULTS + .equals(action); if (Intent.ACTION_VIEW.equals(action) || Intent.ACTION_SEARCH.equals(action) || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action) - || Intent.ACTION_WEB_SEARCH.equals(action)) { + || Intent.ACTION_WEB_SEARCH.equals(action) + || activateVoiceSearch) { // If this was a search request (e.g. search query directly typed into the address bar), // pass it on to the default web search provider. if (handleWebSearchIntent(intent)) { @@ -465,7 +490,7 @@ public class BrowserActivity extends Activity final String appId = intent .getStringExtra(Browser.EXTRA_APPLICATION_ID); - if (Intent.ACTION_VIEW.equals(action) + if ((Intent.ACTION_VIEW.equals(action) || activateVoiceSearch) && !getPackageName().equals(appId) && (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { Tab appTab = mTabControl.getTabFromId(appId); @@ -485,14 +510,14 @@ public class BrowserActivity extends Activity if (current != appTab) { switchToTab(mTabControl.getTabIndex(appTab)); if (needsLoad) { - urlData.loadIn(appTab.getWebView()); + urlData.loadIn(appTab); } } else { // If the tab was the current tab, we have to attach // it to the view system again. attachTabToContentView(appTab); if (needsLoad) { - urlData.loadIn(appTab.getWebView()); + urlData.loadIn(appTab); } } return; @@ -541,7 +566,7 @@ public class BrowserActivity extends Activity } // Get rid of the subwindow if it exists dismissSubWindow(current); - urlData.loadIn(current.getWebView()); + urlData.loadIn(current); } } } @@ -571,6 +596,9 @@ public class BrowserActivity extends Activity String url = null; final String action = intent.getAction(); + if (Tab.VoiceSearchData.VOICE_SEARCH_RESULTS.equals(action)) { + return false; + } if (Intent.ACTION_VIEW.equals(action)) { Uri data = intent.getData(); if (data != null) url = data.toString(); @@ -622,7 +650,7 @@ public class BrowserActivity extends Activity } private UrlData getUrlDataFromIntent(Intent intent) { - String url = null; + String url = ""; Map<String, String> headers = null; if (intent != null) { final String action = intent.getAction(); @@ -673,9 +701,22 @@ public class BrowserActivity extends Activity } } } - return new UrlData(url, headers); + return new UrlData(url, headers, intent); } + /* package */ void showVoiceTitleBar(String title) { + mTitleBar.setInVoiceMode(true); + mFakeTitleBar.setInVoiceMode(true); + mTitleBar.setDisplayTitle(title); + mFakeTitleBar.setDisplayTitle(title); + } + /* package */ void revertVoiceTitleBar() { + mTitleBar.setInVoiceMode(false); + mFakeTitleBar.setInVoiceMode(false); + + mTitleBar.setDisplayTitle(mTitle); + mFakeTitleBar.setDisplayTitle(mTitle); + } /* package */ static String fixUrl(String inUrl) { // FIXME: Converting the url to lower case // duplicates functionality in smartUrlFilter(). @@ -1742,6 +1783,11 @@ public class BrowserActivity extends Activity WebView view = t.getWebView(); view.setEmbeddedTitleBar(mTitleBar); + if (t.isInVoiceSearchMode()) { + showVoiceTitleBar(t.getVoiceDisplayTitle()); + } else { + revertVoiceTitleBar(); + } // Request focus on the top window. t.getTopWindow().requestFocus(); } @@ -1803,7 +1849,7 @@ public class BrowserActivity extends Activity mTabControl.setCurrentTab(tab); attachTabToContentView(tab); if (!urlData.isEmpty()) { - urlData.loadIn(webview); + urlData.loadIn(tab); } return tab; } else { @@ -1811,10 +1857,10 @@ public class BrowserActivity extends Activity dismissSubWindow(currentTab); if (!urlData.isEmpty()) { // Load the given url. - urlData.loadIn(currentTab.getWebView()); + urlData.loadIn(currentTab); } + return currentTab; } - return currentTab; } private Tab openTab(String url) { @@ -1991,8 +2037,10 @@ public class BrowserActivity extends Activity mUrl = url; mTitle = title; - mTitleBar.setTitleAndUrl(title, url); - mFakeTitleBar.setTitleAndUrl(title, url); + // If we are in voice search mode, the title has already been set. + if (mTabControl.getCurrentTab().isInVoiceSearchMode()) return; + mTitleBar.setDisplayTitle(url); + mFakeTitleBar.setDisplayTitle(url); } /** @@ -3891,23 +3939,35 @@ public class BrowserActivity extends Activity private static class UrlData { final String mUrl; final Map<String, String> mHeaders; + final Intent mVoiceIntent; UrlData(String url) { this.mUrl = url; this.mHeaders = null; + this.mVoiceIntent = null; } - UrlData(String url, Map<String, String> headers) { + UrlData(String url, Map<String, String> headers, Intent intent) { this.mUrl = url; this.mHeaders = headers; + if (Tab.VoiceSearchData.VOICE_SEARCH_RESULTS.equals( + intent.getAction())) { + this.mVoiceIntent = intent; + } else { + this.mVoiceIntent = null; + } } boolean isEmpty() { - return mUrl == null || mUrl.length() == 0; + return mVoiceIntent == null && (mUrl == null || mUrl.length() == 0); } - public void loadIn(WebView webView) { - webView.loadUrl(mUrl, mHeaders); + public void loadIn(Tab t) { + if (mVoiceIntent != null) { + t.activateVoiceSearchMode(mVoiceIntent); + } else { + t.getWebView().loadUrl(mUrl, mHeaders); + } } }; diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java index 47477217c..bd6a723c1 100644 --- a/src/com/android/browser/BrowserProvider.java +++ b/src/com/android/browser/BrowserProvider.java @@ -53,6 +53,7 @@ import com.google.android.providers.GoogleSettings.Partner; import java.io.File; import java.io.FilenameFilter; +import java.util.ArrayList; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -718,16 +719,105 @@ public class BrowserProvider extends ContentProvider { } } + private static class ResultsCursor extends AbstractCursor { + // Array indices for RESULTS_COLUMNS + private static final int RESULT_ACTION_ID = 1; + private static final int RESULT_DATA_ID = 2; + private static final int RESULT_TEXT_ID = 3; + private static final int RESULT_ICON_ID = 4; + private static final int RESULT_EXTRA_ID = 5; + + private static final String[] RESULTS_COLUMNS = new String[] { + "_id", + SearchManager.SUGGEST_COLUMN_INTENT_ACTION, + SearchManager.SUGGEST_COLUMN_INTENT_DATA, + SearchManager.SUGGEST_COLUMN_TEXT_1, + SearchManager.SUGGEST_COLUMN_ICON_1, + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + }; + private final ArrayList<String> mResults; + public ResultsCursor(ArrayList<String> results) { + mResults = results; + } + public int getCount() { return mResults.size(); } + + public String[] getColumnNames() { + return RESULTS_COLUMNS; + } + + public String getString(int column) { + switch (column) { + case RESULT_ACTION_ID: + return Tab.VoiceSearchData.VOICE_SEARCH_RESULTS; + case RESULT_TEXT_ID: + // The data is used when the phone is in landscape mode. We + // still want to show the result string. + case RESULT_DATA_ID: + return mResults.get(mPos); + case RESULT_EXTRA_ID: + // The Intent's extra data will store the index into + // mResults so the BrowserActivity will know which result to + // use. + return Integer.toString(mPos); + case RESULT_ICON_ID: + return Integer.valueOf(R.drawable.magnifying_glass) + .toString(); + default: + return null; + } + } + public short getShort(int column) { + throw new UnsupportedOperationException(); + } + public int getInt(int column) { + throw new UnsupportedOperationException(); + } + public long getLong(int column) { + if ((mPos != -1) && column == 0) { + return mPos; // use row# as the _id + } + throw new UnsupportedOperationException(); + } + public float getFloat(int column) { + throw new UnsupportedOperationException(); + } + public double getDouble(int column) { + throw new UnsupportedOperationException(); + } + public boolean isNull(int column) { + throw new UnsupportedOperationException(); + } + } + + private ResultsCursor mResultsCursor; + + /** + * Provide a set of results to be returned to query, intended to be used + * by the SearchDialog when the BrowserActivity is in voice search mode. + * @param results Strings to display in the dropdown from the SearchDialog + */ + /* package */ void setQueryResults(ArrayList<String> results) { + if (results == null) { + mResultsCursor = null; + } else { + mResultsCursor = new ResultsCursor(results); + } + } + @Override public Cursor query(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sortOrder) throws IllegalStateException { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - int match = URI_MATCHER.match(url); if (match == -1) { throw new IllegalArgumentException("Unknown URL"); } + if (match == URI_MATCH_SUGGEST && mResultsCursor != null) { + Cursor results = mResultsCursor; + mResultsCursor = null; + return results; + } + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); if (match == URI_MATCH_SUGGEST || match == URI_MATCH_BOOKMARKS_SUGGEST) { String suggestSelection; diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java index 22c828677..0a54eeef3 100644 --- a/src/com/android/browser/Tab.java +++ b/src/com/android/browser/Tab.java @@ -17,14 +17,17 @@ package com.android.browser; import java.io.File; +import java.util.ArrayList; import java.util.LinkedList; import java.util.Vector; import android.app.AlertDialog; +import android.app.SearchManager; import android.content.ContentResolver; import android.content.ContentValues; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; +import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; @@ -133,6 +136,117 @@ class Tab { // ------------------------------------------------------------------------- + /** + * 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; + } + /** + * 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) { + ArrayList<String> results = intent.getStringArrayListExtra( + "result_strings"); + ArrayList<String> urls = intent.getStringArrayListExtra( + "result_urls"); + if (results != null) { + // This tab is now entering voice search mode for the first time, or + // a new voice search was done. + if (urls == null || results.size() != urls.size()) { + throw new AssertionError("improper extras passed in Intent"); + } + mVoiceSearchData = new VoiceSearchData(results, urls); + } else { + String extraData = intent.getStringExtra( + SearchManager.EXTRA_DATA_KEY); + if (extraData != null) { + mVoiceSearchData.mLastVoiceSearchIndex + = Integer.parseInt(extraData); + if (mVoiceSearchData.mLastVoiceSearchIndex + >= mVoiceSearchData.mVoiceSearchResults.size()) { + throw new AssertionError("index must be less than " + + " size of mVoiceSearchResults"); + } + } + } + mVoiceSearchData.mLastVoiceSearchTitle + = mVoiceSearchData.mVoiceSearchResults.get(mVoiceSearchData. + mLastVoiceSearchIndex); + if (mInForeground) { + mActivity.showVoiceTitleBar(mVoiceSearchData.mLastVoiceSearchTitle); + } + mVoiceSearchData.mLastVoiceSearchUrl + = mVoiceSearchData.mVoiceSearchUrls.get(mVoiceSearchData. + mLastVoiceSearchIndex); + mMainView.loadUrl(mVoiceSearchData.mLastVoiceSearchUrl); + } + /* package */ static class VoiceSearchData { + /** + * Intent action for a voice search. Will be replaced with a global + * variable. + */ + public static final String VOICE_SEARCH_RESULTS + = "android.speech.action.VOICE_SEARCH_RESULTS"; + + public VoiceSearchData(ArrayList<String> results, + ArrayList<String> urls) { + mVoiceSearchResults = results; + mVoiceSearchUrls = urls; + mLastVoiceSearchIndex = 0; + } + /* + * 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; + /* + * 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. Only + * meaningful in voice search mode. + */ + public String mLastVoiceSearchUrl; + /** + * The last title used for voice search. Needed to update the title bar + * when switching tabs. + */ + public String mLastVoiceSearchTitle; + /* + * The index into mVoiceSearchResults and mVoiceSearchUrls of the last + * voice search performed. Stored so it can be used to index into + * mVoiceSearchUrls to determine the url in getUrlDataFromIntent. + */ + public int mLastVoiceSearchIndex; + } + // Container class for the next error dialog that needs to be displayed private class ErrorDialog { public final int mTitle; @@ -209,6 +323,13 @@ class Tab { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { mInLoad = true; + if (mVoiceSearchData != null + && !url.equals(mVoiceSearchData.mLastVoiceSearchUrl)) { + mVoiceSearchData = null; + if (mInForeground) { + mActivity.revertVoiceTitleBar(); + } + } // We've started to load a new page. If there was a pending message // to save a screenshot then we will now take the new page and save diff --git a/src/com/android/browser/TitleBar.java b/src/com/android/browser/TitleBar.java index a9da7c0e0..743af9b0c 100644 --- a/src/com/android/browser/TitleBar.java +++ b/src/com/android/browser/TitleBar.java @@ -67,6 +67,8 @@ public class TitleBar extends LinearLayout { private MyHandler mHandler; private Intent mVoiceSearchIntent; private boolean mInVoiceMode; + private Drawable mVoiceModeBackground; + private Drawable mNormalBackground; private static int LONG_PRESS = 1; @@ -110,6 +112,9 @@ public class TitleBar extends LinearLayout { } mStopDrawable = resources.getDrawable(R.drawable.ic_btn_stop_v2); mBookmarkDrawable = mRtButton.getDrawable(); + mVoiceModeBackground = resources.getDrawable( + R.drawable.textfield_voice_search); + mNormalBackground = mTitleBg.getBackground(); } private class MyHandler extends Handler { @@ -186,7 +191,12 @@ public class TitleBar extends LinearLayout { mRtButton.setPressed(false); } else if (mTitleBg.isPressed()) { mHandler.removeMessages(LONG_PRESS); - mBrowserActivity.onSearchRequested(); + if (mInVoiceMode) { + mBrowserActivity.showVoiceSearchResults( + mTitle.getText().toString()); + } else { + mBrowserActivity.onSearchRequested(); + } mTitleBg.setPressed(false); } break; @@ -222,13 +232,20 @@ public class TitleBar extends LinearLayout { /* package */ void setInVoiceMode(boolean inVoiceMode) { if (mInVoiceMode == inVoiceMode) return; mInVoiceMode = inVoiceMode && mVoiceSearchIntent != null; + Drawable rightButtonDrawable, titleDrawable; if (mInVoiceMode) { - mRtButton.setImageDrawable(mVoiceDrawable); - } else if (mInLoad) { - mRtButton.setImageDrawable(mStopDrawable); + rightButtonDrawable = mVoiceDrawable; + titleDrawable = mVoiceModeBackground; } else { - mRtButton.setImageDrawable(mBookmarkDrawable); + titleDrawable = mNormalBackground; + if (mInLoad) { + rightButtonDrawable = mStopDrawable; + } else { + rightButtonDrawable = mBookmarkDrawable; + } } + mTitleBg.setBackgroundDrawable(titleDrawable); + mRtButton.setImageDrawable(rightButtonDrawable); } /** @@ -275,13 +292,15 @@ public class TitleBar extends LinearLayout { } /** - * Update the title and url. + * Update the text displayed in the title bar. + * @param title String to display. If null, the loading string will be + * shown. */ - /* package */ void setTitleAndUrl(CharSequence title, CharSequence url) { - if (url == null) { + /* package */ void setDisplayTitle(String title) { + if (title == null) { mTitle.setText(R.string.title_bar_loading); } else { - mTitle.setText(url.toString()); + mTitle.setText(title); } } |
