diff options
Diffstat (limited to 'src/com/android/browser')
17 files changed, 36 insertions, 1972 deletions
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java index ee308f9..e3b620a 100644 --- a/src/com/android/browser/BaseUi.java +++ b/src/com/android/browser/BaseUi.java @@ -493,11 +493,6 @@ public abstract class BaseUi implements UI { } @Override - public void registerDropdownChangeListener(DropdownChangeListener d) { - mNavigationBar.registerDropdownChangeListener(d); - } - - @Override public void showComboView(ComboViews startingView, Bundle extras) { Intent intent = new Intent(mActivity, ComboViewActivity.class); intent.putExtra(ComboViewActivity.EXTRA_INITIAL_VIEW, startingView.name()); diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java index 0b8191a..2369554 100644 --- a/src/com/android/browser/BrowserSettings.java +++ b/src/com/android/browser/BrowserSettings.java @@ -146,10 +146,6 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, if (sInitialized) { syncSharedSettings(); } - - if (mController != null && (mSearchEngine instanceof InstantSearchEngine)) { - ((InstantSearchEngine) mSearchEngine).setController(mController); - } } public void startManagingSettings(WebSettings settings) { @@ -355,9 +351,6 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, if (PREF_SEARCH_ENGINE.equals(key)) { updateSearchEngine(false); } - if (PREF_USE_INSTANT_SEARCH.equals(key)) { - updateSearchEngine(true); - } if (PREF_FULLSCREEN.equals(key)) { if (mController.getUi() != null) { mController.getUi().setFullscreen(useFullscreen()); @@ -426,10 +419,6 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, mSearchEngine.close(); } mSearchEngine = SearchEngines.get(mContext, searchEngineName); - - if (mController != null && (mSearchEngine instanceof InstantSearchEngine)) { - ((InstantSearchEngine) mSearchEngine).setController(mController); - } } } @@ -794,10 +783,6 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, return HomeProvider.MOST_VISITED.equals(getHomePage()); } - public boolean useInstantSearch() { - return mPrefs.getBoolean(PREF_USE_INSTANT_SEARCH, false); - } - public boolean useFullscreen() { return mPrefs.getBoolean(PREF_FULLSCREEN, false); } diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java index 9402a77..2a57edf 100644 --- a/src/com/android/browser/Controller.java +++ b/src/com/android/browser/Controller.java @@ -80,7 +80,6 @@ import android.widget.Toast; import com.android.browser.IntentHandler.UrlData; import com.android.browser.UI.ComboViews; -import com.android.browser.UI.DropdownChangeListener; import com.android.browser.provider.BrowserProvider; import com.android.browser.provider.BrowserProvider2.Thumbnails; import com.android.browser.provider.SnapshotProvider.Snapshots; @@ -2744,11 +2743,6 @@ public class Controller mActivity.startActivityForResult(intent, AUTOFILL_SETUP); } - @Override - public void registerDropdownChangeListener(DropdownChangeListener d) { - mUi.registerDropdownChangeListener(d); - } - public boolean onSearchRequested() { mUi.editUrl(false); return true; diff --git a/src/com/android/browser/InstantSearchEngine.java b/src/com/android/browser/InstantSearchEngine.java deleted file mode 100644 index 7176c0a..0000000 --- a/src/com/android/browser/InstantSearchEngine.java +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.browser; - -import com.android.browser.Controller; -import com.android.browser.R; -import com.android.browser.UI.DropdownChangeListener; -import com.android.browser.provider.BrowserProvider; -import com.android.browser.search.SearchEngine; - -import android.app.SearchManager; -import android.content.Context; -import android.database.AbstractCursor; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; -import android.util.LruCache; -import android.webkit.SearchBox; -import android.webkit.WebView; - -import java.util.Collections; -import java.util.List; - -public class InstantSearchEngine implements SearchEngine, DropdownChangeListener { - private static final String TAG = "Browser.InstantSearchEngine"; - private static final boolean DBG = false; - - private Controller mController; - private SearchBox mSearchBox; - private final BrowserSearchboxListener mListener = new BrowserSearchboxListener(); - private int mHeight; - - private String mInstantBaseUrl; - private final Context mContext; - // Used for startSearch( ) calls if for some reason instant - // is off, or no searchbox is present. - private final SearchEngine mWrapped; - - public InstantSearchEngine(Context context, SearchEngine wrapped) { - mContext = context.getApplicationContext(); - mWrapped = wrapped; - } - - public void setController(Controller controller) { - mController = controller; - } - - @Override - public String getName() { - return SearchEngine.GOOGLE; - } - - @Override - public CharSequence getLabel() { - return mContext.getResources().getString(R.string.instant_search_label); - } - - @Override - public void startSearch(Context context, String query, Bundle appData, String extraData) { - if (DBG) Log.d(TAG, "startSearch(" + query + ")"); - - switchSearchboxIfNeeded(); - - // If for some reason we are in a bad state, ensure that the - // user gets default search results at the very least. - if (mSearchBox == null || !isInstantPage()) { - mWrapped.startSearch(context, query, appData, extraData); - return; - } - - mSearchBox.setQuery(query); - mSearchBox.setVerbatim(true); - mSearchBox.onsubmit(null); - } - - private final class BrowserSearchboxListener extends SearchBox.SearchBoxListener { - /* - * The maximum number of out of order suggestions we accept - * before giving up the wait. - */ - private static final int MAX_OUT_OF_ORDER = 5; - - /* - * We wait for suggestions in increments of 600ms. This is primarily to - * guard against suggestions arriving out of order. - */ - private static final int WAIT_INCREMENT_MS = 600; - - /* - * A cache of suggestions received, keyed by the queries they were - * received for. - */ - private final LruCache<String, List<String>> mSuggestions = - new LruCache<String, List<String>>(20); - - /* - * The last set of suggestions received. We use this reduce UI flicker - * in case there is a delay in recieving suggestions. - */ - private List<String> mLatestSuggestion = Collections.emptyList(); - - @Override - public synchronized void onSuggestionsReceived(String query, List<String> suggestions) { - if (DBG) Log.d(TAG, "onSuggestionsReceived(" + query + ")"); - - if (!TextUtils.isEmpty(query)) { - mSuggestions.put(query, suggestions); - mLatestSuggestion = suggestions; - } - - notifyAll(); - } - - public synchronized List<String> tryWaitForSuggestions(String query) { - if (DBG) Log.d(TAG, "tryWait(" + query + ")"); - - int numWaitReturns = 0; - - // This slightly unusual waiting construct is used to safeguard - // to some extent against suggestions arriving out of order. We - // wait for upto 5 notifyAll( ) calls to check if we received - // suggestions for a given query. - while (mSuggestions.get(query) == null) { - try { - wait(WAIT_INCREMENT_MS); - ++numWaitReturns; - if (numWaitReturns > MAX_OUT_OF_ORDER) { - // We've waited too long for suggestions to be returned. - // return the last available suggestion. - break; - } - } catch (InterruptedException e) { - return Collections.emptyList(); - } - } - - List<String> suggestions = mSuggestions.get(query); - if (suggestions == null) { - return mLatestSuggestion; - } - - return suggestions; - } - - public synchronized void clear() { - mSuggestions.evictAll(); - } - } - - private WebView getCurrentWebview() { - if (mController != null) { - return mController.getTabControl().getCurrentTopWebView(); - } - - return null; - } - - /** - * Attaches the searchbox to the right browser page, i.e, the currently - * visible tab. - */ - private void switchSearchboxIfNeeded() { - final WebView current = getCurrentWebview(); - if (current == null) { - return; - } - - final SearchBox searchBox = current.getSearchBox(); - if (searchBox != mSearchBox) { - if (mSearchBox != null) { - mSearchBox.removeSearchBoxListener(mListener); - mListener.clear(); - } - mSearchBox = searchBox; - if (mSearchBox != null) { - mSearchBox.addSearchBoxListener(mListener); - } - } - } - - private boolean isInstantPage() { - final WebView current = getCurrentWebview(); - if (current == null) { - return false; - } - - final String currentUrl = mController.getCurrentTab().getUrl(); - - if (currentUrl != null) { - Uri uri = Uri.parse(currentUrl); - final String host = uri.getHost(); - final String path = uri.getPath(); - - // Is there a utility class that does this ? - if (path != null && host != null) { - return host.startsWith("www.google.") && - (path.startsWith("/search") || path.startsWith("/webhp")); - } - return false; - } - - return false; - } - - private void loadInstantPage() { - mController.getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - final WebView current = getCurrentWebview(); - if (current != null) { - current.loadUrl(getInstantBaseUrl()); - } - } - }); - } - - /** - * Queries for a given search term and returns a cursor containing - * suggestions ordered by best match. - */ - @Override - public Cursor getSuggestions(Context context, String query) { - if (DBG) Log.d(TAG, "getSuggestions(" + query + ")"); - if (query == null) { - return null; - } - - if (!isInstantPage()) { - loadInstantPage(); - } - - switchSearchboxIfNeeded(); - - mController.registerDropdownChangeListener(this); - - if (mSearchBox == null) { - return mWrapped.getSuggestions(context, query); - } - - mSearchBox.setDimensions(0, 0, 0, mHeight); - mSearchBox.onresize(null); - - if (TextUtils.isEmpty(query)) { - // To force the SRP to render an empty (no results) page. - mSearchBox.setVerbatim(true); - } else { - mSearchBox.setVerbatim(false); - } - mSearchBox.setQuery(query); - mSearchBox.onchange(null); - - // Don't bother waiting for suggestions for an empty query. We still - // set the query so that the SRP clears itself. - if (TextUtils.isEmpty(query)) { - return new SuggestionsCursor(Collections.<String>emptyList()); - } else { - return new SuggestionsCursor(mListener.tryWaitForSuggestions(query)); - } - } - - @Override - public boolean supportsSuggestions() { - return true; - } - - @Override - public void close() { - if (mController != null) { - mController.registerDropdownChangeListener(null); - } - if (mSearchBox != null) { - mSearchBox.removeSearchBoxListener(mListener); - } - mListener.clear(); - mWrapped.close(); - } - - @Override - public boolean supportsVoiceSearch() { - return false; - } - - @Override - public String toString() { - return "InstantSearchEngine {" + hashCode() + "}"; - } - - @Override - public boolean wantsEmptyQuery() { - return true; - } - - private int rescaleHeight(int height) { - final WebView current = getCurrentWebview(); - if (current == null) { - return 0; - } - - final float scale = current.getScale(); - if (scale != 0) { - return (int) (height / scale); - } - - return height; - } - - @Override - public void onNewDropdownDimensions(int height) { - final int rescaledHeight = rescaleHeight(height); - - if (rescaledHeight != mHeight) { - mHeight = rescaledHeight; - if (mSearchBox != null) { - mSearchBox.setDimensions(0, 0, 0, rescaledHeight); - mSearchBox.onresize(null); - } - } - } - - private String getInstantBaseUrl() { - if (mInstantBaseUrl == null) { - String url = mContext.getResources().getString(R.string.instant_base); - if (url.indexOf("{CID}") != -1) { - url = url.replace("{CID}", - BrowserProvider.getClientId(mContext.getContentResolver())); - } - mInstantBaseUrl = url; - } - - return mInstantBaseUrl; - } - - // Indices of the columns in the below arrays. - private static final int COLUMN_INDEX_ID = 0; - private static final int COLUMN_INDEX_QUERY = 1; - private static final int COLUMN_INDEX_ICON = 2; - private static final int COLUMN_INDEX_TEXT_1 = 3; - - private static final String[] COLUMNS_WITHOUT_DESCRIPTION = new String[] { - "_id", - SearchManager.SUGGEST_COLUMN_QUERY, - SearchManager.SUGGEST_COLUMN_ICON_1, - SearchManager.SUGGEST_COLUMN_TEXT_1, - }; - - private static class SuggestionsCursor extends AbstractCursor { - private final List<String> mSuggestions; - - public SuggestionsCursor(List<String> suggestions) { - mSuggestions = suggestions; - } - - @Override - public int getCount() { - return mSuggestions.size(); - } - - @Override - public String[] getColumnNames() { - return COLUMNS_WITHOUT_DESCRIPTION; - } - - private String format(String suggestion) { - if (TextUtils.isEmpty(suggestion)) { - return ""; - } - return suggestion; - } - - @Override - public String getString(int column) { - if (mPos >= 0 && mPos < mSuggestions.size()) { - if ((column == COLUMN_INDEX_QUERY) || (column == COLUMN_INDEX_TEXT_1)) { - return format(mSuggestions.get(mPos)); - } else if (column == COLUMN_INDEX_ICON) { - return String.valueOf(R.drawable.magnifying_glass); - } - } - return null; - } - - @Override - public double getDouble(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public float getFloat(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public int getInt(int column) { - if (column == COLUMN_INDEX_ID) { - return mPos; - } - throw new UnsupportedOperationException(); - } - - @Override - public long getLong(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public short getShort(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isNull(int column) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/src/com/android/browser/NavigationBarBase.java b/src/com/android/browser/NavigationBarBase.java index bfdd9a0..659169d 100644 --- a/src/com/android/browser/NavigationBarBase.java +++ b/src/com/android/browser/NavigationBarBase.java @@ -22,6 +22,8 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.speech.RecognizerResultsIntent; +import android.text.Editable; +import android.text.TextWatcher; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; @@ -30,15 +32,13 @@ import android.view.View.OnFocusChangeListener; import android.widget.ImageView; import android.widget.LinearLayout; -import com.android.browser.UI.DropdownChangeListener; import com.android.browser.UrlInputView.UrlInputListener; -import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher; import java.util.List; public class NavigationBarBase extends LinearLayout implements OnClickListener, UrlInputListener, OnFocusChangeListener, - TextChangeWatcher { + TextWatcher { protected BaseUi mBaseUi; protected TitleBar mTitleBar; @@ -70,7 +70,7 @@ public class NavigationBarBase extends LinearLayout implements mUrlInput.setUrlInputListener(this); mUrlInput.setOnFocusChangeListener(this); mUrlInput.setSelectAllOnFocus(true); - mUrlInput.addQueryTextWatcher(this); + mUrlInput.addTextChangedListener(this); } public void setTitleBar(TitleBar titleBar) { @@ -144,16 +144,6 @@ public class NavigationBarBase extends LinearLayout implements } } - // UrlInput text watcher - - @Override - public void onTextChanged(String newText) { - if (mUrlInput.hasFocus()) { - // clear voice mode when user types - setInVoiceMode(false, null); - } - } - // voicesearch public void setInVoiceMode(boolean voicemode, List<String> voiceResults) { @@ -166,7 +156,7 @@ public class NavigationBarBase extends LinearLayout implements } void clearCompletions() { - mUrlInput.setSuggestedText(null); + mUrlInput.dismissDropDown(); } // UrlInputListener implementation @@ -250,10 +240,6 @@ public class NavigationBarBase extends LinearLayout implements return super.dispatchKeyEventPreIme(evt); } - void registerDropdownChangeListener(DropdownChangeListener d) { - mUrlInput.registerDropdownChangeListener(d); - } - /** * called from the Ui when the user wants to edit * @param clearInput clear the input field @@ -287,4 +273,17 @@ public class NavigationBarBase extends LinearLayout implements public void onTabDataChanged(Tab tab) { } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (mUrlInput.hasFocus()) { + // clear voice mode when user types + setInVoiceMode(false, null); + } + } + + @Override + public void afterTextChanged(Editable s) { } } diff --git a/src/com/android/browser/NavigationBarTablet.java b/src/com/android/browser/NavigationBarTablet.java index ef29a49..04f372a 100644 --- a/src/com/android/browser/NavigationBarTablet.java +++ b/src/com/android/browser/NavigationBarTablet.java @@ -195,7 +195,7 @@ public class NavigationBarTablet extends NavigationBarBase { } private void clearOrClose() { - if (TextUtils.isEmpty(mUrlInput.getUserText())) { + if (TextUtils.isEmpty(mUrlInput.getText())) { // close mUrlInput.clearFocus(); } else { @@ -278,7 +278,7 @@ public class NavigationBarTablet extends NavigationBarBase { } protected void updateSearchMode(boolean userEdited) { - setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getUserText())); + setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getText())); } @Override diff --git a/src/com/android/browser/PreferenceKeys.java b/src/com/android/browser/PreferenceKeys.java index 15ccfe5..ecab008 100644 --- a/src/com/android/browser/PreferenceKeys.java +++ b/src/com/android/browser/PreferenceKeys.java @@ -81,7 +81,6 @@ public interface PreferenceKeys { // Keys for lab_preferences.xml // ---------------------- static final String PREF_ENABLE_QUICK_CONTROLS = "enable_quick_controls"; - static final String PREF_USE_INSTANT_SEARCH = "use_instant_search"; static final String PREF_FULLSCREEN = "fullscreen"; // ---------------------- diff --git a/src/com/android/browser/SuggestionsAdapter.java b/src/com/android/browser/SuggestionsAdapter.java index ca3754c..7400b5d 100644 --- a/src/com/android/browser/SuggestionsAdapter.java +++ b/src/com/android/browser/SuggestionsAdapter.java @@ -563,10 +563,6 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable, } - private boolean useInstant() { - return mSettings.useInstantSearch(); - } - public void clearCache() { mFilterResults = null; mSuggestResults = null; diff --git a/src/com/android/browser/UI.java b/src/com/android/browser/UI.java index a9cbd7b..2bd3754 100644 --- a/src/com/android/browser/UI.java +++ b/src/com/android/browser/UI.java @@ -140,11 +140,6 @@ public interface UI { boolean dispatchKey(int code, KeyEvent event); - public static interface DropdownChangeListener { - void onNewDropdownDimensions(int height); - } - void registerDropdownChangeListener(DropdownChangeListener d); - void showAutoLogin(Tab tab); void hideAutoLogin(Tab tab); diff --git a/src/com/android/browser/UiController.java b/src/com/android/browser/UiController.java index 9b48c46..e7a8953 100644 --- a/src/com/android/browser/UiController.java +++ b/src/com/android/browser/UiController.java @@ -23,7 +23,6 @@ import android.view.MenuItem; import android.webkit.WebView; import com.android.browser.UI.ComboViews; -import com.android.browser.UI.DropdownChangeListener; import java.util.List; @@ -92,8 +91,6 @@ public interface UiController { void updateMenuState(Tab tab, Menu menu); - void registerDropdownChangeListener(DropdownChangeListener d); - boolean onOptionsItemSelected(MenuItem item); SnapshotTab createNewSnapshotTab(long snapshotId, boolean setActive); diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java index 96ab864..3c0de30 100644 --- a/src/com/android/browser/UrlInputView.java +++ b/src/com/android/browser/UrlInputView.java @@ -19,27 +19,25 @@ package com.android.browser; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; -import android.database.DataSetObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.util.AttributeSet; import android.util.Patterns; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.AutoCompleteTextView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import com.android.browser.SuggestionsAdapter.CompletionListener; import com.android.browser.SuggestionsAdapter.SuggestItem; -import com.android.browser.UI.DropdownChangeListener; -import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher; -import com.android.browser.autocomplete.SuggestiveAutoCompleteTextView; import com.android.browser.search.SearchEngine; import com.android.browser.search.SearchEngineInfo; import com.android.browser.search.SearchEngines; @@ -51,9 +49,9 @@ import java.util.List; * url/search input view * handling suggestions */ -public class UrlInputView extends SuggestiveAutoCompleteTextView +public class UrlInputView extends AutoCompleteTextView implements OnEditorActionListener, - CompletionListener, OnItemClickListener, TextChangeWatcher { + CompletionListener, OnItemClickListener, TextWatcher { static final String TYPED = "browser-type"; static final String SUGGESTED = "browser-suggest"; @@ -76,7 +74,6 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView private boolean mLandscape; private boolean mIncognitoMode; private boolean mNeedsUpdate; - private DropdownChangeListener mDropdownListener; private int mState; private StateListener mStateListener; @@ -113,23 +110,8 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView setThreshold(1); setOnItemClickListener(this); mNeedsUpdate = false; - mDropdownListener = null; - addQueryTextWatcher(this); - - mAdapter.registerDataSetObserver(new DataSetObserver() { - @Override - public void onChanged() { - if (!isPopupShowing()) { - return; - } - dispatchChange(); - } + addTextChangedListener(this); - @Override - public void onInvalidated() { - dispatchChange(); - } - }); mState = StateListener.STATE_NORMAL; } @@ -225,7 +207,7 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView mAdapter.setLandscapeMode(mLandscape); if (isPopupShowing() && (getVisibility() == View.VISIBLE)) { setupDropDown(); - performFiltering(getUserText(), 0); + performFiltering(getText(), 0); } } @@ -256,21 +238,11 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (BrowserSettings.getInstance().useInstantSearch() && - (actionId == EditorInfo.IME_ACTION_NEXT)) { - // When instant is turned on AND the user chooses to complete - // using the tab key, then use the completion rather than the - // text that the user has typed. - finishInput(getText().toString(), null, TYPED); - } else { - finishInput(getUserText(), null, TYPED); - } - + finishInput(getText().toString(), null, TYPED); return true; } void forceFilter() { - performForcedFiltering(); showDropDown(); } @@ -365,19 +337,6 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView return mAdapter; } - private void dispatchChange() { - final Rect popupRect = new Rect(); - getPopupDrawableRect(popupRect); - - if (mDropdownListener != null) { - mDropdownListener.onNewDropdownDimensions(popupRect.height()); - } - } - - void registerDropdownChangeListener(DropdownChangeListener d) { - mDropdownListener = d; - } - /* * no-op to prevent scrolling of webview when embedded titlebar * gets edited @@ -388,10 +347,16 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView } @Override - public void onTextChanged(String newText) { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { if (StateListener.STATE_HIGHLIGHTED == mState) { changeState(StateListener.STATE_EDITED); } } + @Override + public void afterTextChanged(Editable s) { } + } diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java index b4afb6f..556e88d 100644 --- a/src/com/android/browser/XLargeUi.java +++ b/src/com/android/browser/XLargeUi.java @@ -130,9 +130,7 @@ public class XLargeUi extends BaseUi { @Override public void onResume() { super.onResume(); - if (!BrowserSettings.getInstance().useInstantSearch()) { - mNavBar.clearCompletions(); - } + mNavBar.clearCompletions(); } @Override diff --git a/src/com/android/browser/autocomplete/SuggestedSpan.java b/src/com/android/browser/autocomplete/SuggestedSpan.java deleted file mode 100644 index dc04cb2..0000000 --- a/src/com/android/browser/autocomplete/SuggestedSpan.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.browser.autocomplete; - -import android.os.Parcel; -import android.text.style.ForegroundColorSpan; - -/** - * Class used to mark the portion of text within {@link SuggestiveEditText} that is suggested. - */ -class SuggestedSpan extends ForegroundColorSpan { - - public SuggestedSpan(Parcel src) { - super(src); - } - - public SuggestedSpan(int color) { - super(color); - } - -} diff --git a/src/com/android/browser/autocomplete/SuggestedTextController.java b/src/com/android/browser/autocomplete/SuggestedTextController.java deleted file mode 100644 index 95dfcab..0000000 --- a/src/com/android/browser/autocomplete/SuggestedTextController.java +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.browser.autocomplete; - -import com.google.common.annotations.VisibleForTesting; - -import android.os.Parcel; -import android.os.Parcelable; -import android.text.Editable; -import android.text.Selection; -import android.text.SpanWatcher; -import android.text.Spannable; -import android.text.Spanned; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.util.Log; -import android.view.View; -import android.widget.EditText; - -import java.util.ArrayList; - -import junit.framework.Assert; - - -/** - * The query editor can show a suggestion, grayed out following the query that the user has - * entered so far. As the user types new characters, these should replace the grayed suggestion - * text. This class manages this logic, displaying the suggestion when the user entered text is a - * prefix of it, and hiding it otherwise. - * - * Note, the text in the text view will contain the entire suggestion, not just what the user - * entered. Instead of retrieving the text from the text view, {@link #getUserText()} should be - * called on this class. - */ -public class SuggestedTextController { - private static final boolean DBG = false; - private static final String TAG = "Browser.SuggestedTextController"; - - private final BufferTextWatcher mBufferTextWatcher = new BufferTextWatcher(); - private final BufferSpanWatcher mBufferSpanWatcher = new BufferSpanWatcher(); - private final ArrayList<TextChangeWatcher> mTextWatchers; - private final TextOwner mTextOwner; - private final StringBuffer mUserEntered; - private final SuggestedSpan mSuggested; - private String mSuggestedText; - private TextChangeAttributes mCurrentTextChange; - private boolean mSuspended = false; - - /** - * While this is non-null, any changes made to the cursor position or selection are ignored. Is - * stored the selection state at the moment when selection change processing was disabled. - */ - private BufferSelection mTextSelectionBeforeIgnoringChanges; - - public SuggestedTextController(final EditText textView, int color) { - this(new TextOwner() { - @Override - public Editable getText() { - return textView.getText(); - } - @Override - public void addTextChangedListener(TextWatcher watcher) { - textView.addTextChangedListener(watcher); - } - @Override - public void removeTextChangedListener(TextWatcher watcher) { - textView.removeTextChangedListener(watcher); - } - @Override - public void setText(String text) { - textView.setText(text); - } - }, color); - } - - private void initialize(String userText, int selStart, int selEnd, String suggested) { - Editable text = mTextOwner.getText(); - - if (userText == null) userText = ""; - String allText = userText; - int suggestedStart = allText.length(); - if (suggested != null && userText != null) { - if (suggested.startsWith(userText.toLowerCase())) { - allText = suggested; - } - } - - // allText is at this point either "userText" (not null) or - // "suggested" if thats not null and starts with userText. - text.replace(0, text.length(), allText); - Selection.setSelection(text, selStart, selEnd); - mUserEntered.replace(0, mUserEntered.length(), userText); - mSuggestedText = suggested; - if (suggestedStart < text.length()) { - text.setSpan(mSuggested, suggestedStart, text.length(), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } else { - text.removeSpan(mSuggested); - } - text.setSpan(mBufferSpanWatcher, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - mTextOwner.addTextChangedListener(mBufferTextWatcher); - if (DBG) checkInvariant(text); - } - - private void assertNotIgnoringSelectionChanges() { - if (mTextSelectionBeforeIgnoringChanges != null) { - throw new IllegalStateException( - "Illegal operation while cursor movement processing suspended"); - } - } - - public boolean isCursorHandlingSuspended() { - return mSuspended; - } - - public Parcelable saveInstanceState(Parcelable superState) { - assertNotIgnoringSelectionChanges(); - SavedState ss = new SavedState(superState); - Editable buffer = mTextOwner.getText(); - ss.mUserText = getUserText(); - ss.mSuggestedText = mSuggestedText; - ss.mSelStart = Selection.getSelectionStart(buffer); - ss.mSelEnd = Selection.getSelectionEnd(buffer); - return ss; - } - - public Parcelable restoreInstanceState(Parcelable state) { - assertNotIgnoringSelectionChanges(); - if (!(state instanceof SavedState)) return state; - SavedState ss = (SavedState) state; - if (DBG) { - Log.d(TAG, "restoreInstanceState t='" + ss.mUserText + "' suggestion='" + - ss.mSuggestedText + " sel=" + ss.mSelStart + ".." + ss.mSelEnd); - } - // remove our listeners so we don't get notifications while re-initialising - mTextOwner.getText().removeSpan(mBufferSpanWatcher); - mTextOwner.removeTextChangedListener(mBufferTextWatcher); - // and initialise will re-add the watchers - initialize(ss.mUserText, ss.mSelStart, ss.mSelEnd, ss.mSuggestedText); - notifyUserEnteredChanged(); - return ss.getSuperState(); - } - - /** - * Temporarily stop processing cursor movements and selection changes. While cursor movements - * are being ignored, the text in the buffer must NOT be changed; doing so will result in an - * {@link IllegalStateException} being thrown. - * - * To stop ignoring cursor movements, call - * {@link #resumeCursorMovementHandlingAndApplyChanges()}. - */ - public void suspendCursorMovementHandling() { - assertNotIgnoringSelectionChanges(); - Editable buffer = mTextOwner.getText(); - mTextSelectionBeforeIgnoringChanges = new BufferSelection(buffer); - mSuspended = true; - } - - /** - * Start responding to cursor movements and selection changes again. If the cursor or selection - * moved while it was being ignored, these changes will be processed now. - */ - public void resumeCursorMovementHandlingAndApplyChanges() { - Editable buffer = mTextOwner.getText(); - BufferSelection oldSelection = mTextSelectionBeforeIgnoringChanges; - mTextSelectionBeforeIgnoringChanges = null; - BufferSelection newSelection = new BufferSelection(buffer); - if (oldSelection.mStart != newSelection.mStart) { - mBufferSpanWatcher.onSpanChanged(buffer, Selection.SELECTION_START, - oldSelection.mStart, oldSelection.mStart, - newSelection.mStart, newSelection.mStart); - } - if (oldSelection.mEnd != newSelection.mEnd) { - mBufferSpanWatcher.onSpanChanged(buffer, Selection.SELECTION_END, - oldSelection.mEnd, oldSelection.mEnd, - newSelection.mEnd, newSelection.mEnd); - } - mSuspended = false; - } - - /** - * Sets the current suggested text. A portion of this will be added to the user entered text if - * that is a prefix of the suggestion. - */ - public void setSuggestedText(String text) { - assertNotIgnoringSelectionChanges(); - if (!TextUtils.equals(text, mSuggestedText)) { - if (DBG) Log.d(TAG, "setSuggestedText(" + text + ")"); - mSuggestedText = text; - if (mCurrentTextChange == null) { - mCurrentTextChange = new TextChangeAttributes(0, 0, 0); - Editable buffer = mTextOwner.getText(); - handleTextChanged(buffer); - } - } - } - - /** - * Gets the portion of displayed text that is not suggested. - */ - public String getUserText() { - assertNotIgnoringSelectionChanges(); - return mUserEntered.toString(); - } - - /** - * Sets the given text as if it has been entered by the user. - */ - public void setText(String text) { - assertNotIgnoringSelectionChanges(); - if (text == null) text = ""; - Editable buffer = mTextOwner.getText(); - buffer.removeSpan(mSuggested); - // this will cause a handleTextChanged call - buffer.replace(0, text.length(), text); - } - - public void addUserTextChangeWatcher(TextChangeWatcher watcher) { - mTextWatchers.add(watcher); - } - - private void handleTextChanged(Editable newText) { - // When we make changes to the buffer from within this function, it results in recursive - // calls to beforeTextChanges(), afterTextChanged(). We want to ignore the changes we're - // making ourself: - if (mCurrentTextChange.isHandled()) return; - mCurrentTextChange.setHandled(); - final int pos = mCurrentTextChange.mPos; - final int countBefore = mCurrentTextChange.mCountBefore; - final int countAfter = mCurrentTextChange.mCountAfter; - final int cursorPos = Selection.getSelectionEnd(newText); - if (DBG) { - Log.d(TAG, "pos=" + pos +"; countBefore=" + countBefore + "; countAfter=" + - countAfter + "; cursor=" + cursorPos); - } - mUserEntered.replace(pos, pos + countBefore, - newText.subSequence(pos, pos + countAfter).toString()); - if (DBG) Log.d(TAG, "User entered: '" + mUserEntered + "' all='" + newText + "'"); - final int userLen = mUserEntered.length(); - boolean haveSuggested = newText.getSpanStart(mSuggested) != -1; - if (mSuggestedText != null && - mSuggestedText.startsWith(mUserEntered.toString().toLowerCase())) { - if (haveSuggested) { - if (!mSuggestedText.equalsIgnoreCase(newText.toString())) { - if (countAfter > countBefore) { - // net insertion - int len = countAfter - countBefore; - newText.delete(pos + len, pos + len + len); - } else { - // net deletion - newText.replace(userLen, newText.length(), - mSuggestedText.substring(userLen)); - if (countBefore == 0) { - // no change to the text - likely just suggested change - Selection.setSelection(newText, cursorPos); - } - } - } - } else { - // no current suggested text - add it - newText.insert(userLen, mSuggestedText.substring(userLen)); - // keep the cursor at the end of the user entered text, if that where it was - // before. - if (cursorPos == userLen) { - Selection.setSelection(newText, userLen); - } - } - if (userLen == newText.length()) { - newText.removeSpan(mSuggested); - } else { - newText.setSpan(mSuggested, userLen, newText.length(), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } else { - if (newText.getSpanStart(mSuggested) != -1) { - newText.removeSpan(mSuggested); - newText.delete(mUserEntered.length(), newText.length()); - } - } - if (DBG) checkInvariant(newText); - mCurrentTextChange = null; - if (countBefore > 0 || countAfter > 0) { - notifyUserEnteredChanged(); - } - } - - private void notifyUserEnteredChanged() { - for (TextChangeWatcher watcher : mTextWatchers) { - watcher.onTextChanged(mUserEntered.toString()); - } - } - - /** - * Basic interface for being notified of changes to some text. - */ - public interface TextChangeWatcher { - void onTextChanged(String newText); - } - - /** - * Interface class to wrap required methods from {@link EditText}, or some other class used - * to test without needing an @{link EditText}. - */ - public interface TextOwner { - Editable getText(); - void addTextChangedListener(TextWatcher watcher); - void removeTextChangedListener(TextWatcher watcher); - void setText(String text); - } - - /** - * This class stores the parameters passed to {@link BufferTextWatcher#beforeTextChanged}, - * together with a flag indicating if this invocation has been dealt with yet. We need this - * information, together with the parameters passed to - * {@link BufferTextWatcher#afterTextChanged}, to restore our internal state when the buffer is - * edited. - * - * Since the changes we make from within {@link BufferTextWatcher#afterTextChanged} also trigger - * further recursive calls to {@link BufferTextWatcher#beforeTextChanged} and - * {@link BufferTextWatcher#afterTextChanged}, this class helps detect these recursive calls so - * they can be ignored. - */ - private static class TextChangeAttributes { - public final int mPos; - public final int mCountAfter; - public final int mCountBefore; - private boolean mHandled; - - public TextChangeAttributes(int pos, int countAfter, int countBefore) { - mPos = pos; - mCountAfter = countAfter; - mCountBefore = countBefore; - } - - public void setHandled() { - mHandled = true; - } - - public boolean isHandled() { - return mHandled; - } - } - - /** - * Encapsulates the state of the text selection (and cursor) within a text buffer. - */ - private static class BufferSelection { - final int mStart; - final int mEnd; - public BufferSelection(CharSequence text) { - mStart = Selection.getSelectionStart(text); - mEnd = Selection.getSelectionEnd(text); - } - @Override - public boolean equals(Object other) { - if (!(other instanceof BufferSelection)) return super.equals(other); - BufferSelection otherSel = (BufferSelection) other; - return this.mStart == otherSel.mStart && this.mEnd == otherSel.mEnd; - } - } - - private class BufferTextWatcher implements TextWatcher { - @Override - public void afterTextChanged(Editable newText) { - if (DBG) { - Log.d(TAG, "afterTextChanged('" + newText + "')"); - } - assertNotIgnoringSelectionChanges(); - handleTextChanged(newText); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - assertNotIgnoringSelectionChanges(); - if (mCurrentTextChange == null) { - mCurrentTextChange = new TextChangeAttributes(start, after, count); - } - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - } - - private class BufferSpanWatcher implements SpanWatcher { - @Override - public void onSpanAdded(Spannable text, Object what, int start, int end) { - } - - @Override - public void onSpanChanged( - Spannable text, Object what, int ostart, int oend, int nstart, int nend) { - if (mCurrentTextChange != null) return; - if (mTextSelectionBeforeIgnoringChanges != null) return; - if (what == Selection.SELECTION_END) { - if (DBG) Log.d(TAG, "cursor move to " + nend); - if (nend > mUserEntered.length()) { - mUserEntered.replace(0, mUserEntered.length(), text.toString()); - text.removeSpan(mSuggested); - } - if (DBG) checkInvariant(text); - } - } - - @Override - public void onSpanRemoved(Spannable text, Object what, int start, int end) { - } - } - - public static class SavedState extends View.BaseSavedState { - String mUserText; - String mSuggestedText; - int mSelStart; - int mSelEnd; - - public SavedState(Parcelable superState) { - super(superState); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeString(mUserText); - out.writeString(mSuggestedText); - out.writeInt(mSelStart); - out.writeInt(mSelEnd); - } - - @SuppressWarnings("hiding") - public static final Parcelable.Creator<SavedState> CREATOR - = new Parcelable.Creator<SavedState>() { - @Override - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - - private SavedState(Parcel in) { - super(in); - mUserText = in.readString(); - mSuggestedText = in.readString(); - mSelStart = in.readInt(); - mSelEnd = in.readInt(); - } - } - - /* - * The remaining functions are used for testing purposes only. - * ----------------------------------------------------------- - */ - - /** - * Verify that the internal state of this class is consistent. - */ - @VisibleForTesting - void checkInvariant(final Spannable s) { - int suggestedStart = s.getSpanStart(mSuggested); - int suggestedEnd = s.getSpanEnd(mSuggested); - int cursorPos = Selection.getSelectionEnd(s); - if (suggestedStart == -1 || suggestedEnd == -1) { - suggestedStart = suggestedEnd = s.length(); - } - String userEntered = getUserText(); - Log.d(TAG, "checkInvariant all='" + s + "' (len " + s.length() + ") sug=" - + suggestedStart + ".." + suggestedEnd + " cursor=" + cursorPos + - " ue='" + userEntered + "' (len " + userEntered.length() + ")"); - int suggestedLen = suggestedEnd - suggestedStart; - Assert.assertEquals("Sum of user and suggested text lengths doesn't match total length", - s.length(), userEntered.length() + suggestedLen); - Assert.assertEquals("End of user entered text doesn't match start of suggested", - suggestedStart, userEntered.length()); - Assert.assertTrue("user entered text does not match start of buffer", - userEntered.toString().equalsIgnoreCase( - s.subSequence(0, suggestedStart).toString())); - if (mSuggestedText != null && suggestedStart < s.length()) { - Assert.assertTrue("User entered is not a prefix of suggested", - mSuggestedText.startsWith(userEntered.toString().toLowerCase())); - Assert.assertTrue("Suggested text does not match buffer contents", - mSuggestedText.equalsIgnoreCase(s.toString().toLowerCase())); - } - if (mSuggestedText == null) { - Assert.assertEquals("Non-zero suggention length with null suggestion", 0, suggestedLen); - } else { - Assert.assertTrue("Suggestion text longer than suggestion (" + mSuggestedText.length() + - ">" + suggestedLen + ")", suggestedLen <= mSuggestedText.length()); - } - Assert.assertTrue("Cursor within suggested part", cursorPos <= suggestedStart); - } - - @VisibleForTesting - SuggestedTextController(TextOwner textOwner, int color) { - mUserEntered = new StringBuffer(); - mSuggested = new SuggestedSpan(color); - mTextOwner = textOwner; - mTextWatchers = new ArrayList<TextChangeWatcher>(); - initialize(null, 0, 0, null); - } -} diff --git a/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java b/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java deleted file mode 100644 index 50ba758..0000000 --- a/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.browser.autocomplete; - -import com.android.browser.BrowserSettings; -import com.android.browser.SuggestionsAdapter; -import com.android.browser.SuggestionsAdapter.SuggestItem; -import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher; -import com.android.internal.R; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.DataSetObserver; -import android.graphics.Rect; -import android.os.Parcelable; -import android.text.Editable; -import android.text.Html; -import android.text.Selection; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.AbsSavedState; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.inputmethod.CompletionInfo; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.AdapterView; -import android.widget.EditText; -import android.widget.Filter; -import android.widget.Filterable; -import android.widget.ListAdapter; -import android.widget.ListPopupWindow; -import android.widget.TextView; - - -/** - * This is a stripped down version of the framework AutoCompleteTextView - * class with added support for displaying completions in-place. Note that - * this cannot be implemented as a subclass of the above without making - * substantial changes to it and its descendants. - * - * @see android.widget.AutoCompleteTextView - */ -public class SuggestiveAutoCompleteTextView extends EditText implements Filter.FilterListener { - private static final boolean DEBUG = false; - private static final String TAG = "SuggestiveAutoCompleteTextView"; - - private CharSequence mHintText; - private TextView mHintView; - private int mHintResource; - - private SuggestionsAdapter mAdapter; - private Filter mFilter; - private int mThreshold; - - private ListPopupWindow mPopup; - private int mDropDownAnchorId; - - private AdapterView.OnItemClickListener mItemClickListener; - - private boolean mDropDownDismissedOnCompletion = true; - - private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; - - // Set to true when text is set directly and no filtering shall be performed - private boolean mBlockCompletion; - - // When set, an update in the underlying adapter will update the result list popup. - // Set to false when the list is hidden to prevent asynchronous updates to popup the list again. - private boolean mPopupCanBeUpdated = true; - - private PassThroughClickListener mPassThroughClickListener; - private PopupDataSetObserver mObserver; - private SuggestedTextController mController; - - public SuggestiveAutoCompleteTextView(Context context) { - this(context, null); - } - - public SuggestiveAutoCompleteTextView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.autoCompleteTextViewStyle); - } - - public SuggestiveAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - // The completions are always shown in the same color as the hint - // text. - mController = new SuggestedTextController(this, getHintTextColors().getDefaultColor()); - mPopup = new ListPopupWindow(context, attrs, - R.attr.autoCompleteTextViewStyle); - mPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW); - - TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.AutoCompleteTextView, defStyle, 0); - - mThreshold = a.getInt( - R.styleable.AutoCompleteTextView_completionThreshold, 2); - - mPopup.setListSelector(a.getDrawable(R.styleable.AutoCompleteTextView_dropDownSelector)); - mPopup.setVerticalOffset((int) - a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f)); - mPopup.setHorizontalOffset((int) - a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f)); - - // Get the anchor's id now, but the view won't be ready, so wait to actually get the - // view and store it in mDropDownAnchorView lazily in getDropDownAnchorView later. - // Defaults to NO_ID, in which case the getDropDownAnchorView method will simply return - // this TextView, as a default anchoring point. - mDropDownAnchorId = a.getResourceId( - R.styleable.AutoCompleteTextView_dropDownAnchor, View.NO_ID); - - // For dropdown width, the developer can specify a specific width, or MATCH_PARENT - // (for full screen width) or WRAP_CONTENT (to match the width of the anchored view). - mPopup.setWidth(a.getLayoutDimension( - R.styleable.AutoCompleteTextView_dropDownWidth, - ViewGroup.LayoutParams.WRAP_CONTENT)); - mPopup.setHeight(a.getLayoutDimension( - R.styleable.AutoCompleteTextView_dropDownHeight, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView, - R.layout.simple_dropdown_hint); - - mPopup.setOnItemClickListener(new DropDownItemClickListener()); - setCompletionHint(a.getText(R.styleable.AutoCompleteTextView_completionHint)); - - // Always turn on the auto complete input type flag, since it - // makes no sense to use this widget without it. - int inputType = getInputType(); - if ((inputType&EditorInfo.TYPE_MASK_CLASS) - == EditorInfo.TYPE_CLASS_TEXT) { - inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE; - setRawInputType(inputType); - } - - a.recycle(); - - setFocusable(true); - - mController.addUserTextChangeWatcher(new MyWatcher()); - - mPassThroughClickListener = new PassThroughClickListener(); - super.setOnClickListener(mPassThroughClickListener); - } - - @Override - public void setOnClickListener(OnClickListener listener) { - mPassThroughClickListener.mWrapped = listener; - } - - /** - * Private hook into the on click event, dispatched from {@link PassThroughClickListener} - */ - private void onClickImpl() { - // If the dropdown is showing, bring the keyboard to the front - // when the user touches the text field. - if (isPopupShowing()) { - ensureImeVisible(true); - } - } - - /** - * <p>Sets the optional hint text that is displayed at the bottom of the - * the matching list. This can be used as a cue to the user on how to - * best use the list, or to provide extra information.</p> - * - * @param hint the text to be displayed to the user - * - * @attr ref android.R.styleable#AutoCompleteTextView_completionHint - */ - private void setCompletionHint(CharSequence hint) { - mHintText = hint; - if (hint != null) { - if (mHintView == null) { - final TextView hintView = (TextView) LayoutInflater.from(getContext()).inflate( - mHintResource, null).findViewById(R.id.text1); - hintView.setText(mHintText); - mHintView = hintView; - mPopup.setPromptView(hintView); - } else { - mHintView.setText(hint); - } - } else { - mPopup.setPromptView(null); - mHintView = null; - } - } - - protected int getDropDownWidth() { - return mPopup.getWidth(); - } - - public void setDropDownWidth(int width) { - mPopup.setWidth(width); - } - - protected void setDropDownVerticalOffset(int offset) { - mPopup.setVerticalOffset(offset); - } - - public void setDropDownHorizontalOffset(int offset) { - mPopup.setHorizontalOffset(offset); - } - - protected int getDropDownHorizontalOffset() { - return mPopup.getHorizontalOffset(); - } - - public void setThreshold(int threshold) { - if (threshold <= 0) { - threshold = 1; - } - - mThreshold = threshold; - } - - protected void setOnItemClickListener(AdapterView.OnItemClickListener l) { - mItemClickListener = l; - } - - public void setAdapter(SuggestionsAdapter adapter) { - if (mObserver == null) { - mObserver = new PopupDataSetObserver(); - } else if (mAdapter != null) { - mAdapter.unregisterDataSetObserver(mObserver); - } - mAdapter = adapter; - if (mAdapter != null) { - mFilter = mAdapter.getFilter(); - adapter.registerDataSetObserver(mObserver); - } else { - mFilter = null; - } - - mPopup.setAdapter(mAdapter); - } - - @Override - public boolean onKeyPreIme(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing() - && !mPopup.isDropDownAlwaysVisible()) { - // special case for the back key, we do not even try to send it - // to the drop down list but instead, consume it immediately - if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - KeyEvent.DispatcherState state = getKeyDispatcherState(); - if (state != null) { - state.startTracking(event, this); - } - return true; - } else if (event.getAction() == KeyEvent.ACTION_UP) { - KeyEvent.DispatcherState state = getKeyDispatcherState(); - if (state != null) { - state.handleUpEvent(event); - } - if (event.isTracking() && !event.isCanceled()) { - dismissDropDown(); - return true; - } - } - } - return super.onKeyPreIme(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean consumed = mPopup.onKeyUp(keyCode, event); - if (consumed) { - switch (keyCode) { - // if the list accepts the key events and the key event - // was a click, the text view gets the selected item - // from the drop down as its content - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_TAB: - if (event.hasNoModifiers()) { - performCompletion(); - } - return true; - } - } - - if (isPopupShowing() && keyCode == KeyEvent.KEYCODE_TAB && event.hasNoModifiers()) { - performCompletion(); - return true; - } - - return super.onKeyUp(keyCode, event); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mPopup.onKeyDown(keyCode, event)) { - return true; - } - - if (!isPopupShowing()) { - switch(keyCode) { - case KeyEvent.KEYCODE_DPAD_DOWN: - if (event.hasNoModifiers()) { - performValidation(); - } - } - } - - if (isPopupShowing() && keyCode == KeyEvent.KEYCODE_TAB && event.hasNoModifiers()) { - return true; - } - - mLastKeyCode = keyCode; - boolean handled = super.onKeyDown(keyCode, event); - mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; - - if (handled && isPopupShowing()) { - clearListSelection(); - } - - return handled; - } - - /** - * Returns <code>true</code> if the amount of text in the field meets - * or exceeds the {@link #getThreshold} requirement. You can override - * this to impose a different standard for when filtering will be - * triggered. - */ - private boolean enoughToFilter() { - if (DEBUG) Log.v(TAG, "Enough to filter: len=" + getUserText().length() - + " threshold=" + mThreshold); - return getUserText().length() >= mThreshold; - } - - /** - * This is used to watch for edits to the text view. Note that we call - * to methods on the auto complete text view class so that we can access - * private vars without going through thunks. - */ - private class MyWatcher implements TextChangeWatcher { - @Override - public void onTextChanged(String newText) { - doAfterTextChanged(); - } - } - - /** - * @hide - */ - protected void setBlockCompletion(boolean block) { - mBlockCompletion = block; - } - - void doAfterTextChanged() { - if (DEBUG) Log.d(TAG, "doAfterTextChanged(" + getText() + ")"); - if (mBlockCompletion) return; - - // the drop down is shown only when a minimum number of characters - // was typed in the text view - if (enoughToFilter()) { - if (mFilter != null) { - mPopupCanBeUpdated = true; - performFiltering(getUserText(), mLastKeyCode); - buildImeCompletions(); - } - } else { - // drop down is automatically dismissed when enough characters - // are deleted from the text view - if (!mPopup.isDropDownAlwaysVisible()) { - dismissDropDown(); - } - if (mFilter != null) { - performFiltering(null, mLastKeyCode); - } - } - } - - /** - * <p>Indicates whether the popup menu is showing.</p> - * - * @return true if the popup menu is showing, false otherwise - */ - public boolean isPopupShowing() { - return mPopup.isShowing(); - } - - /** - * <p>Converts the selected item from the drop down list into a sequence - * of character that can be used in the edit box.</p> - * - * @param selectedItem the item selected by the user for completion - * - * @return a sequence of characters representing the selected suggestion - */ - protected CharSequence convertSelectionToString(Object selectedItem) { - return mFilter.convertResultToString(selectedItem); - } - - /** - * <p>Clear the list selection. This may only be temporary, as user input will often bring - * it back. - */ - private void clearListSelection() { - mPopup.clearListSelection(); - } - - /** - * <p>Starts filtering the content of the drop down list. The filtering - * pattern is the content of the edit box. Subclasses should override this - * method to filter with a different pattern, for instance a substring of - * <code>text</code>.</p> - * - * @param text the filtering pattern - * @param keyCode the last character inserted in the edit box; beware that - * this will be null when text is being added through a soft input method. - */ - @SuppressWarnings({ "UnusedDeclaration" }) - protected void performFiltering(CharSequence text, int keyCode) { - if (DEBUG) Log.d(TAG, "performFiltering(" + text + ")"); - - mFilter.filter(text, this); - } - - protected void performForcedFiltering() { - boolean wasSuspended = false; - if (mController.isCursorHandlingSuspended()) { - mController.resumeCursorMovementHandlingAndApplyChanges(); - wasSuspended = true; - } - - mFilter.filter(getUserText().toString(), this); - - if (wasSuspended) { - mController.suspendCursorMovementHandling(); - } - } - - /** - * <p>Performs the text completion by converting the selected item from - * the drop down list into a string, replacing the text box's content with - * this string and finally dismissing the drop down menu.</p> - */ - private void performCompletion() { - performCompletion(null, -1, -1); - } - - @Override - public void onCommitCompletion(CompletionInfo completion) { - if (isPopupShowing()) { - mBlockCompletion = true; - replaceText(completion.getText()); - mBlockCompletion = false; - - mPopup.performItemClick(completion.getPosition()); - } - } - - private void performCompletion(View selectedView, int position, long id) { - if (isPopupShowing()) { - Object selectedItem; - if (position < 0) { - selectedItem = mPopup.getSelectedItem(); - } else { - selectedItem = mAdapter.getItem(position); - } - if (selectedItem == null) { - Log.w(TAG, "performCompletion: no selected item"); - return; - } - - mBlockCompletion = true; - replaceText(convertSelectionToString(selectedItem)); - mBlockCompletion = false; - - if (mItemClickListener != null) { - final ListPopupWindow list = mPopup; - - if (selectedView == null || position < 0) { - selectedView = list.getSelectedView(); - position = list.getSelectedItemPosition(); - id = list.getSelectedItemId(); - } - mItemClickListener.onItemClick(list.getListView(), selectedView, position, id); - } - } - - if (mDropDownDismissedOnCompletion && !mPopup.isDropDownAlwaysVisible()) { - dismissDropDown(); - } - } - - /** - * <p>Performs the text completion by replacing the current text by the - * selected item. Subclasses should override this method to avoid replacing - * the whole content of the edit box.</p> - * - * @param text the selected suggestion in the drop down list - */ - protected void replaceText(CharSequence text) { - clearComposingText(); - - setText(text); - // make sure we keep the caret at the end of the text view - Editable spannable = getText(); - Selection.setSelection(spannable, spannable.length()); - } - - /** {@inheritDoc} */ - @Override - public void onFilterComplete(int count) { - updateDropDownForFilter(count); - } - - private void updateDropDownForFilter(int count) { - // Not attached to window, don't update drop-down - if (getWindowVisibility() == View.GONE) return; - - /* - * This checks enoughToFilter() again because filtering requests - * are asynchronous, so the result may come back after enough text - * has since been deleted to make it no longer appropriate - * to filter. - */ - - final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible(); - if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter() && - getUserText().length() > 0) { - if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) { - showDropDown(); - } - } else if (!dropDownAlwaysVisible && isPopupShowing()) { - dismissDropDown(); - // When the filter text is changed, the first update from the adapter may show an empty - // count (when the query is being performed on the network). Future updates when some - // content has been retrieved should still be able to update the list. - mPopupCanBeUpdated = true; - } - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - if (!hasWindowFocus && !mPopup.isDropDownAlwaysVisible()) { - dismissDropDown(); - } - } - - @Override - protected void onDisplayHint(int hint) { - super.onDisplayHint(hint); - switch (hint) { - case INVISIBLE: - if (!mPopup.isDropDownAlwaysVisible()) { - dismissDropDown(); - } - break; - } - } - - @Override - protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { - // TextView makes several cursor movements when gaining focus, and this interferes with - // the suggested vs user entered text. Tell the controller to temporarily ignore cursor - // movements while this is going on. - mController.suspendCursorMovementHandling(); - - super.onFocusChanged(focused, direction, previouslyFocusedRect); - // Perform validation if the view is losing focus. - if (!focused) { - performValidation(); - } - if (!focused && !mPopup.isDropDownAlwaysVisible()) { - dismissDropDown(); - } - - mController.resumeCursorMovementHandlingAndApplyChanges(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - } - - @Override - protected void onDetachedFromWindow() { - dismissDropDown(); - super.onDetachedFromWindow(); - } - - /** - * <p>Closes the drop down if present on screen.</p> - */ - protected void dismissDropDown() { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - imm.displayCompletions(this, null); - } - mPopup.dismiss(); - mPopupCanBeUpdated = false; - } - - @Override - protected boolean setFrame(final int l, int t, final int r, int b) { - boolean result = super.setFrame(l, t, r, b); - - if (isPopupShowing()) { - showDropDown(); - } - - return result; - } - - /** - * Ensures that the drop down is not obscuring the IME. - * @param visible whether the ime should be in front. If false, the ime is pushed to - * the background. - * @hide internal used only here and SearchDialog - */ - private void ensureImeVisible(boolean visible) { - mPopup.setInputMethodMode(visible - ? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED); - showDropDown(); - } - - /** - * <p>Displays the drop down on screen.</p> - */ - protected void showDropDown() { - if (mPopup.getAnchorView() == null) { - if (mDropDownAnchorId != View.NO_ID) { - mPopup.setAnchorView(getRootView().findViewById(mDropDownAnchorId)); - } else { - mPopup.setAnchorView(this); - } - } - if (!isPopupShowing()) { - // Make sure the list does not obscure the IME when shown for the first time. - mPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED); - } - mPopup.show(); - } - - private void buildImeCompletions() { - final ListAdapter adapter = mAdapter; - if (adapter != null) { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - final int count = Math.min(adapter.getCount(), 20); - CompletionInfo[] completions = new CompletionInfo[count]; - int realCount = 0; - - for (int i = 0; i < count; i++) { - if (adapter.isEnabled(i)) { - realCount++; - Object item = adapter.getItem(i); - long id = adapter.getItemId(i); - completions[i] = new CompletionInfo(id, i, - convertSelectionToString(item)); - } - } - - if (realCount != count) { - CompletionInfo[] tmp = new CompletionInfo[realCount]; - System.arraycopy(completions, 0, tmp, 0, realCount); - completions = tmp; - } - - imm.displayCompletions(this, completions); - } - } - } - - private void performValidation() { - } - - /** - * Returns the Filter obtained from {@link Filterable#getFilter}, - * or <code>null</code> if {@link #setAdapter} was not called with - * a Filterable. - */ - protected Filter getFilter() { - return mFilter; - } - - private class DropDownItemClickListener implements AdapterView.OnItemClickListener { - @Override - public void onItemClick(AdapterView parent, View v, int position, long id) { - performCompletion(v, position, id); - } - } - - /** - * Allows us a private hook into the on click event without preventing users from setting - * their own click listener. - */ - private class PassThroughClickListener implements OnClickListener { - - private View.OnClickListener mWrapped; - - /** {@inheritDoc} */ - @Override - public void onClick(View v) { - onClickImpl(); - - if (mWrapped != null) mWrapped.onClick(v); - } - } - - private class PopupDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - if (mAdapter != null) { - // If the popup is not showing already, showing it will cause - // the list of data set observers attached to the adapter to - // change. We can't do it from here, because we are in the middle - // of iterating through the list of observers. - post(new Runnable() { - @Override - public void run() { - final SuggestionsAdapter adapter = mAdapter; - if (adapter != null) { - // This will re-layout, thus resetting mDataChanged, so that the - // listView click listener stays responsive - updateDropDownForFilter(adapter.getCount()); - } - - updateText(adapter); - } - }); - } - } - } - - public String getUserText() { - return mController.getUserText(); - } - - private void updateText(SuggestionsAdapter adapter) { - if (!BrowserSettings.getInstance().useInstantSearch()) { - return; - } - - if (!isPopupShowing()) { - setSuggestedText(null); - return; - } - - if (mAdapter.getCount() > 0 && !TextUtils.isEmpty(getUserText())) { - for (int i = 0; i < mAdapter.getCount(); ++i) { - SuggestItem current = mAdapter.getItem(i); - if (current.type == SuggestionsAdapter.TYPE_SUGGEST) { - setSuggestedText(current.title); - break; - } - } - } - } - - @Override - public void setText(CharSequence text, BufferType type) { - Editable buffer = getEditableText(); - if (text == null) text = ""; - // if we already have a buffer, we must not replace it with a new one as this will break - // mController. Write the new text into the existing buffer instead. - if (buffer == null) { - super.setText(text, type); - } else { - buffer.replace(0, buffer.length(), text); - invalidate(); - } - } - - public void setText(CharSequence text, boolean filter) { - if (filter) { - setText(text); - } else { - mBlockCompletion = true; - // If cursor movement handling was suspended (the view is - // not in focus), resume it and apply the pending change. - // Since we don't want to perform any filtering, this change - // is safe. - boolean wasSuspended = false; - if (mController.isCursorHandlingSuspended()) { - mController.resumeCursorMovementHandlingAndApplyChanges(); - wasSuspended = true; - } - - setText(text); - - if (wasSuspended) { - mController.suspendCursorMovementHandling(); - } - mBlockCompletion = false; - } - } - - @Override - public Parcelable onSaveInstanceState() { - Parcelable superState = super.onSaveInstanceState(); - if (superState instanceof TextView.SavedState) { - // get rid of TextView's saved state, we override it. - superState = ((TextView.SavedState) superState).getSuperState(); - } - if (superState == null) { - superState = AbsSavedState.EMPTY_STATE; - } - return mController.saveInstanceState(superState); - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - super.onRestoreInstanceState(mController.restoreInstanceState(state)); - } - - public void addQueryTextWatcher(final SuggestedTextController.TextChangeWatcher watcher) { - mController.addUserTextChangeWatcher(watcher); - } - - public void setSuggestedText(String text) { - if (!TextUtils.isEmpty(text)) { - String htmlStripped = Html.fromHtml(text).toString(); - mController.setSuggestedText(htmlStripped); - } else { - mController.setSuggestedText(null); - } - } - - public void getPopupDrawableRect(Rect rect) { - if (mPopup.getListView() != null) { - mPopup.getListView().getDrawingRect(rect); - } - } -} diff --git a/src/com/android/browser/preferences/LabPreferencesFragment.java b/src/com/android/browser/preferences/LabPreferencesFragment.java index ca3a86a..222b5fa 100644 --- a/src/com/android/browser/preferences/LabPreferencesFragment.java +++ b/src/com/android/browser/preferences/LabPreferencesFragment.java @@ -26,35 +26,11 @@ import com.android.browser.R; import com.android.browser.search.SearchEngine; public class LabPreferencesFragment extends PreferenceFragment { - private BrowserSettings mBrowserSettings; - private Preference useInstantPref; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - mBrowserSettings = BrowserSettings.getInstance(); - // Load the XML preferences file addPreferencesFromResource(R.xml.lab_preferences); - useInstantPref = findPreference(PreferenceKeys.PREF_USE_INSTANT_SEARCH); } - - @Override - public void onResume() { - super.onResume(); - if (useInstantPref != null) { - useInstantPref.setEnabled(false); - - // Enable the "use instant" preference only if the selected - // search engine is google. - if (mBrowserSettings.getSearchEngine() != null) { - final String currentName = mBrowserSettings.getSearchEngine().getName(); - if (SearchEngine.GOOGLE.equals(currentName)) { - useInstantPref.setEnabled(true); - } - } - } - } - } diff --git a/src/com/android/browser/search/SearchEngines.java b/src/com/android/browser/search/SearchEngines.java index fd967f9..433e877 100644 --- a/src/com/android/browser/search/SearchEngines.java +++ b/src/com/android/browser/search/SearchEngines.java @@ -15,8 +15,6 @@ */ package com.android.browser.search; -import com.android.browser.BrowserSettings; -import com.android.browser.InstantSearchEngine; import com.android.browser.R; import android.content.Context; @@ -32,10 +30,6 @@ public class SearchEngines { private static final String TAG = "SearchEngines"; public static SearchEngine getDefaultSearchEngine(Context context) { - if (BrowserSettings.getInstance().useInstantSearch()) { - return new InstantSearchEngine(context, DefaultSearchEngine.create(context)); - } - return DefaultSearchEngine.create(context); } |