diff options
Diffstat (limited to 'core/java/android/webkit/FindActionModeCallback.java')
-rw-r--r-- | core/java/android/webkit/FindActionModeCallback.java | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java new file mode 100644 index 0000000..2299d4a --- /dev/null +++ b/core/java/android/webkit/FindActionModeCallback.java @@ -0,0 +1,224 @@ +/* + * 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 android.webkit; + +import android.content.Context; +import android.content.res.Resources; +import android.text.Editable; +import android.text.Selection; +import android.text.Spannable; +import android.text.TextWatcher; +import android.webkit.WebView; +import android.widget.EditText; +import android.widget.TextView; +import android.view.ActionMode; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +class FindActionModeCallback implements ActionMode.Callback, TextWatcher, + View.OnLongClickListener { + private View mCustomView; + private EditText mEditText; + private TextView mMatches; + private WebView mWebView; + private InputMethodManager mInput; + private Resources mResources; + private boolean mMatchesFound; + private int mNumberOfMatches; + private View mTitleBar; + + FindActionModeCallback(Context context) { + mCustomView = LayoutInflater.from(context).inflate( + com.android.internal.R.layout.webview_find, null); + mEditText = (EditText) mCustomView.findViewById( + com.android.internal.R.id.edit); + // Override long click so that select ActionMode is not opened, which + // would exit find ActionMode. + mEditText.setOnLongClickListener(this); + setText(""); + mMatches = (TextView) mCustomView.findViewById( + com.android.internal.R.id.matches); + mInput = (InputMethodManager) + context.getSystemService(Context.INPUT_METHOD_SERVICE); + mResources = context.getResources(); + } + + void setTitleBar(View v) { mTitleBar = v; } + + /* + * Place text in the text field so it can be searched for. Need to press + * the find next or find previous button to find all of the matches. + */ + void setText(String text) { + mEditText.setText(text); + Spannable span = (Spannable) mEditText.getText(); + int length = span.length(); + // Ideally, we would like to set the selection to the whole field, + // but this brings up the Text selection CAB, which dismisses this + // one. + Selection.setSelection(span, length, length); + // Necessary each time we set the text, so that this will watch + // changes to it. + span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + mMatchesFound = false; + } + + /* + * Set the WebView to search. Must be non null, and set before calling + * startActionMode. + */ + void setWebView(WebView webView) { + if (null == webView) { + throw new AssertionError("WebView supplied to " + + "FindActionModeCallback cannot be null"); + } + mWebView = webView; + } + + /* + * Move the highlight to the next match. + * @param next If true, find the next match further down in the document. + * If false, find the previous match, up in the document. + */ + private void findNext(boolean next) { + if (mWebView == null) { + throw new AssertionError( + "No WebView for FindActionModeCallback::findNext"); + } + mWebView.findNext(next); + } + + /* + * Highlight all the instances of the string from mEditText in mWebView. + */ + void findAll() { + if (mWebView == null) { + throw new AssertionError( + "No WebView for FindActionModeCallback::findAll"); + } + CharSequence find = mEditText.getText(); + if (0 == find.length()) { + mWebView.clearMatches(); + mMatches.setVisibility(View.GONE); + mMatchesFound = false; + } else { + mMatchesFound = true; + mMatches.setVisibility(View.VISIBLE); + mNumberOfMatches = mWebView.findAll(find.toString()); + if (0 == mNumberOfMatches) { + mMatches.setText(mResources.getString( + com.android.internal.R.string.no_matches)); + } else { + updateMatchesString(); + } + } + } + + /* + * Update the string which tells the user how many matches were found, and + * which match is currently highlighted. + */ + private void updateMatchesString() { + String template = mResources.getQuantityString( + com.android.internal.R.plurals.matches_found, mNumberOfMatches, + mWebView.findIndex() + 1, mNumberOfMatches); + + mMatches.setText(template); + } + + // OnLongClickListener implementation + + @Override + public boolean onLongClick(View v) { return true; } + + // ActionMode.Callback implementation + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + mode.setCustomView(mCustomView); + mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_find, + menu); + Editable edit = mEditText.getText(); + Selection.setSelection(edit, edit.length()); + mMatches.setVisibility(View.GONE); + mMatchesFound = false; + mMatches.setText("0"); + mEditText.requestFocus(); + mInput.showSoftInput(mEditText, 0); + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + if (mTitleBar != null) mWebView.setEmbeddedTitleBar(mTitleBar); + mWebView.notifyFindDialogDismissed(); + mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0); + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + if (!mMatchesFound) { + findAll(); + return true; + } + switch(item.getItemId()) { + case com.android.internal.R.id.find_prev: + findNext(false); + break; + case com.android.internal.R.id.find_next: + findNext(true); + break; + default: + return false; + } + updateMatchesString(); + return true; + } + + // TextWatcher implementation + + @Override + public void beforeTextChanged(CharSequence s, + int start, + int count, + int after) { + // Does nothing. Needed to implement TextWatcher. + } + + @Override + public void onTextChanged(CharSequence s, + int start, + int before, + int count) { + findAll(); + } + + @Override + public void afterTextChanged(Editable s) { + // Does nothing. Needed to implement TextWatcher. + } + +} |