blob: 27043e0474cf7bcb67b7605aa133cf2106f50995 [file] [log] [blame]
Leon Scrogginsfe026bd2010-08-24 14:16:09 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.text.Editable;
22import android.text.Selection;
23import android.text.Spannable;
24import android.text.TextWatcher;
25import android.webkit.WebView;
26import android.widget.EditText;
27import android.widget.TextView;
28import android.view.ActionMode;
29import android.view.LayoutInflater;
30import android.view.Menu;
31import android.view.MenuInflater;
32import android.view.MenuItem;
33import android.view.View;
34import android.view.inputmethod.InputMethodManager;
35
36class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
37 View.OnLongClickListener {
38 private View mCustomView;
39 private EditText mEditText;
40 private TextView mMatches;
41 private WebView mWebView;
42 private InputMethodManager mInput;
43 private Resources mResources;
44 private boolean mMatchesFound;
45 private int mNumberOfMatches;
46 private View mTitleBar;
Leon Scroggins05919f22010-09-14 17:22:36 -040047 private ActionMode mActionMode;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -040048
49 FindActionModeCallback(Context context) {
50 mCustomView = LayoutInflater.from(context).inflate(
51 com.android.internal.R.layout.webview_find, null);
52 mEditText = (EditText) mCustomView.findViewById(
53 com.android.internal.R.id.edit);
54 // Override long click so that select ActionMode is not opened, which
55 // would exit find ActionMode.
56 mEditText.setOnLongClickListener(this);
57 setText("");
58 mMatches = (TextView) mCustomView.findViewById(
59 com.android.internal.R.id.matches);
60 mInput = (InputMethodManager)
61 context.getSystemService(Context.INPUT_METHOD_SERVICE);
62 mResources = context.getResources();
63 }
64
65 void setTitleBar(View v) { mTitleBar = v; }
66
Leon Scroggins05919f22010-09-14 17:22:36 -040067 void finish() {
68 mActionMode.finish();
69 }
70
Leon Scrogginsfe026bd2010-08-24 14:16:09 -040071 /*
72 * Place text in the text field so it can be searched for. Need to press
73 * the find next or find previous button to find all of the matches.
74 */
75 void setText(String text) {
76 mEditText.setText(text);
77 Spannable span = (Spannable) mEditText.getText();
78 int length = span.length();
79 // Ideally, we would like to set the selection to the whole field,
80 // but this brings up the Text selection CAB, which dismisses this
81 // one.
82 Selection.setSelection(span, length, length);
83 // Necessary each time we set the text, so that this will watch
84 // changes to it.
85 span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
86 mMatchesFound = false;
87 }
88
89 /*
90 * Set the WebView to search. Must be non null, and set before calling
91 * startActionMode.
92 */
93 void setWebView(WebView webView) {
94 if (null == webView) {
95 throw new AssertionError("WebView supplied to "
96 + "FindActionModeCallback cannot be null");
97 }
98 mWebView = webView;
99 }
100
101 /*
102 * Move the highlight to the next match.
103 * @param next If true, find the next match further down in the document.
104 * If false, find the previous match, up in the document.
105 */
106 private void findNext(boolean next) {
107 if (mWebView == null) {
108 throw new AssertionError(
109 "No WebView for FindActionModeCallback::findNext");
110 }
111 mWebView.findNext(next);
112 }
113
114 /*
115 * Highlight all the instances of the string from mEditText in mWebView.
116 */
117 void findAll() {
118 if (mWebView == null) {
119 throw new AssertionError(
120 "No WebView for FindActionModeCallback::findAll");
121 }
122 CharSequence find = mEditText.getText();
123 if (0 == find.length()) {
124 mWebView.clearMatches();
125 mMatches.setVisibility(View.GONE);
126 mMatchesFound = false;
127 } else {
128 mMatchesFound = true;
129 mMatches.setVisibility(View.VISIBLE);
130 mNumberOfMatches = mWebView.findAll(find.toString());
131 if (0 == mNumberOfMatches) {
132 mMatches.setText(mResources.getString(
133 com.android.internal.R.string.no_matches));
134 } else {
135 updateMatchesString();
136 }
137 }
138 }
139
140 /*
141 * Update the string which tells the user how many matches were found, and
142 * which match is currently highlighted.
143 */
144 private void updateMatchesString() {
145 String template = mResources.getQuantityString(
146 com.android.internal.R.plurals.matches_found, mNumberOfMatches,
147 mWebView.findIndex() + 1, mNumberOfMatches);
148
149 mMatches.setText(template);
150 }
151
152 // OnLongClickListener implementation
153
154 @Override
155 public boolean onLongClick(View v) { return true; }
156
157 // ActionMode.Callback implementation
158
159 @Override
160 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
161 mode.setCustomView(mCustomView);
162 mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_find,
163 menu);
Leon Scroggins05919f22010-09-14 17:22:36 -0400164 mActionMode = mode;
Leon Scrogginsfe026bd2010-08-24 14:16:09 -0400165 Editable edit = mEditText.getText();
166 Selection.setSelection(edit, edit.length());
167 mMatches.setVisibility(View.GONE);
168 mMatchesFound = false;
169 mMatches.setText("0");
170 mEditText.requestFocus();
171 mInput.showSoftInput(mEditText, 0);
172 return true;
173 }
174
175 @Override
176 public void onDestroyActionMode(ActionMode mode) {
177 if (mTitleBar != null) mWebView.setEmbeddedTitleBar(mTitleBar);
178 mWebView.notifyFindDialogDismissed();
179 mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
180 }
181
182 @Override
183 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
184 return false;
185 }
186
187 @Override
188 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
189 if (!mMatchesFound) {
190 findAll();
191 return true;
192 }
193 switch(item.getItemId()) {
194 case com.android.internal.R.id.find_prev:
195 findNext(false);
196 break;
197 case com.android.internal.R.id.find_next:
198 findNext(true);
199 break;
200 default:
201 return false;
202 }
203 updateMatchesString();
204 return true;
205 }
206
207 // TextWatcher implementation
208
209 @Override
210 public void beforeTextChanged(CharSequence s,
211 int start,
212 int count,
213 int after) {
214 // Does nothing. Needed to implement TextWatcher.
215 }
216
217 @Override
218 public void onTextChanged(CharSequence s,
219 int start,
220 int before,
221 int count) {
222 findAll();
223 }
224
225 @Override
226 public void afterTextChanged(Editable s) {
227 // Does nothing. Needed to implement TextWatcher.
228 }
229
230}