summaryrefslogtreecommitdiffstats
path: root/src/com/android/swe/browser/UrlInputView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/swe/browser/UrlInputView.java')
-rw-r--r--src/com/android/swe/browser/UrlInputView.java356
1 files changed, 356 insertions, 0 deletions
diff --git a/src/com/android/swe/browser/UrlInputView.java b/src/com/android/swe/browser/UrlInputView.java
new file mode 100644
index 00000000..02bba3cb
--- /dev/null
+++ b/src/com/android/swe/browser/UrlInputView.java
@@ -0,0 +1,356 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+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.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.search.SearchEngine;
+import com.android.browser.search.SearchEngineInfo;
+import com.android.browser.search.SearchEngines;
+import com.android.internal.R;
+
+import java.util.List;
+
+/**
+ * url/search input view
+ * handling suggestions
+ */
+public class UrlInputView extends AutoCompleteTextView
+ implements OnEditorActionListener,
+ CompletionListener, OnItemClickListener, TextWatcher {
+
+ static final String TYPED = "browser-type";
+ static final String SUGGESTED = "browser-suggest";
+
+ static final int POST_DELAY = 100;
+
+ static interface StateListener {
+ static final int STATE_NORMAL = 0;
+ static final int STATE_HIGHLIGHTED = 1;
+ static final int STATE_EDITED = 2;
+
+ public void onStateChanged(int state);
+ }
+
+ private UrlInputListener mListener;
+ private InputMethodManager mInputManager;
+ private SuggestionsAdapter mAdapter;
+ private View mContainer;
+ private boolean mLandscape;
+ private boolean mIncognitoMode;
+ private boolean mNeedsUpdate;
+
+ private int mState;
+ private StateListener mStateListener;
+ private Rect mPopupPadding;
+
+ public UrlInputView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.PopupWindow,
+ R.attr.autoCompleteTextViewStyle, 0);
+
+ Drawable popupbg = a.getDrawable(R.styleable.PopupWindow_popupBackground);
+ a.recycle();
+ mPopupPadding = new Rect();
+ popupbg.getPadding(mPopupPadding);
+ init(context);
+ }
+
+ public UrlInputView(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.autoCompleteTextViewStyle);
+ }
+
+ public UrlInputView(Context context) {
+ this(context, null);
+ }
+
+ private void init(Context ctx) {
+ mInputManager = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
+ setOnEditorActionListener(this);
+ mAdapter = new SuggestionsAdapter(ctx, this);
+ setAdapter(mAdapter);
+ setSelectAllOnFocus(true);
+ onConfigurationChanged(ctx.getResources().getConfiguration());
+ setThreshold(1);
+ setOnItemClickListener(this);
+ mNeedsUpdate = false;
+ addTextChangedListener(this);
+
+ mState = StateListener.STATE_NORMAL;
+ }
+
+ protected void onFocusChanged(boolean focused, int direction, Rect prevRect) {
+ super.onFocusChanged(focused, direction, prevRect);
+ int state = -1;
+ if (focused) {
+ if (hasSelection()) {
+ state = StateListener.STATE_HIGHLIGHTED;
+ } else {
+ state = StateListener.STATE_EDITED;
+ }
+ } else {
+ // reset the selection state
+ state = StateListener.STATE_NORMAL;
+ }
+ final int s = state;
+ post(new Runnable() {
+ public void run() {
+ changeState(s);
+ }
+ });
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent evt) {
+ boolean hasSelection = hasSelection();
+ boolean res = super.onTouchEvent(evt);
+ if ((MotionEvent.ACTION_DOWN == evt.getActionMasked())
+ && hasSelection) {
+ postDelayed(new Runnable() {
+ public void run() {
+ changeState(StateListener.STATE_EDITED);
+ }}, POST_DELAY);
+ }
+ return res;
+ }
+
+ /**
+ * check if focus change requires a title bar update
+ */
+ boolean needsUpdate() {
+ return mNeedsUpdate;
+ }
+
+ /**
+ * clear the focus change needs title bar update flag
+ */
+ void clearNeedsUpdate() {
+ mNeedsUpdate = false;
+ }
+
+ void setController(UiController controller) {
+ UrlSelectionActionMode urlSelectionMode
+ = new UrlSelectionActionMode(controller);
+ setCustomSelectionActionModeCallback(urlSelectionMode);
+ }
+
+ void setContainer(View container) {
+ mContainer = container;
+ }
+
+ public void setUrlInputListener(UrlInputListener listener) {
+ mListener = listener;
+ }
+
+ public void setStateListener(StateListener listener) {
+ mStateListener = listener;
+ // update listener
+ changeState(mState);
+ }
+
+ private void changeState(int newState) {
+ mState = newState;
+ if (mStateListener != null) {
+ mStateListener.onStateChanged(mState);
+ }
+ }
+
+ int getState() {
+ return mState;
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration config) {
+ super.onConfigurationChanged(config);
+ mLandscape = (config.orientation &
+ Configuration.ORIENTATION_LANDSCAPE) != 0;
+ mAdapter.setLandscapeMode(mLandscape);
+ if (isPopupShowing() && (getVisibility() == View.VISIBLE)) {
+ setupDropDown();
+ performFiltering(getText(), 0);
+ }
+ }
+
+ @Override
+ public void showDropDown() {
+ setupDropDown();
+ super.showDropDown();
+ }
+
+ @Override
+ public void dismissDropDown() {
+ super.dismissDropDown();
+ mAdapter.clearCache();
+ }
+
+ private void setupDropDown() {
+ int width = mContainer != null ? mContainer.getWidth() : getWidth();
+ width += mPopupPadding.left + mPopupPadding.right;
+ if (width != getDropDownWidth()) {
+ setDropDownWidth(width);
+ }
+ int left = getLeft();
+ left += mPopupPadding.left;
+ if (left != -getDropDownHorizontalOffset()) {
+ setDropDownHorizontalOffset(-left);
+ }
+ }
+
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ finishInput(getText().toString(), null, TYPED);
+ return true;
+ }
+
+ void forceFilter() {
+ showDropDown();
+ }
+
+ void hideIME() {
+ mInputManager.hideSoftInputFromWindow(getWindowToken(), 0);
+ }
+
+ void showIME() {
+ mInputManager.focusIn(this);
+ mInputManager.showSoftInput(this, 0);
+ }
+
+ private void finishInput(String url, String extra, String source) {
+ mNeedsUpdate = true;
+ dismissDropDown();
+ mInputManager.hideSoftInputFromWindow(getWindowToken(), 0);
+ if (TextUtils.isEmpty(url)) {
+ mListener.onDismiss();
+ } else {
+ if (mIncognitoMode && isSearch(url)) {
+ // To prevent logging, intercept this request
+ // TODO: This is a quick hack, refactor this
+ SearchEngine searchEngine = BrowserSettings.getInstance()
+ .getSearchEngine();
+ if (searchEngine == null) return;
+ SearchEngineInfo engineInfo = SearchEngines
+ .getSearchEngineInfo(mContext, searchEngine.getName());
+ if (engineInfo == null) return;
+ url = engineInfo.getSearchUriForQuery(url);
+ // mLister.onAction can take it from here without logging
+ }
+ mListener.onAction(url, extra, source);
+ }
+ }
+
+ boolean isSearch(String inUrl) {
+ String url = UrlUtils.fixUrl(inUrl).trim();
+ if (TextUtils.isEmpty(url)) return false;
+
+ if (Patterns.WEB_URL.matcher(url).matches()
+ || UrlUtils.ACCEPTED_URI_SCHEMA.matcher(url).matches()) {
+ return false;
+ }
+ return true;
+ }
+
+ // Completion Listener
+
+ @Override
+ public void onSearch(String search) {
+ mListener.onCopySuggestion(search);
+ }
+
+ @Override
+ public void onSelect(String url, int type, String extra) {
+ finishInput(url, extra, SUGGESTED);
+ }
+
+ @Override
+ public void onItemClick(
+ AdapterView<?> parent, View view, int position, long id) {
+ SuggestItem item = mAdapter.getItem(position);
+ onSelect(SuggestionsAdapter.getSuggestionUrl(item), item.type, item.extra);
+ }
+
+ interface UrlInputListener {
+
+ public void onDismiss();
+
+ public void onAction(String text, String extra, String source);
+
+ public void onCopySuggestion(String text);
+
+ }
+
+ public void setIncognitoMode(boolean incognito) {
+ mIncognitoMode = incognito;
+ mAdapter.setIncognitoMode(mIncognitoMode);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent evt) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE && !isInTouchMode()) {
+ finishInput(null, null, null);
+ return true;
+ }
+ return super.onKeyDown(keyCode, evt);
+ }
+
+ public SuggestionsAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /*
+ * no-op to prevent scrolling of webview when embedded titlebar
+ * gets edited
+ */
+ @Override
+ public boolean requestRectangleOnScreen(Rect rect, boolean immediate) {
+ return false;
+ }
+
+ @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 (StateListener.STATE_HIGHLIGHTED == mState) {
+ changeState(StateListener.STATE_EDITED);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) { }
+
+}