blob: 2be18d674816adb65e698df23d4b75650513169b [file] [log] [blame]
Jeff Brown67b6ab72010-12-17 18:33:02 -08001/*
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.text.method;
18
19import android.text.Layout;
20import android.text.Spannable;
21import android.view.KeyEvent;
22import android.view.MotionEvent;
23import android.widget.TextView;
24
25/**
26 * Base classes for movement methods.
27 */
28public class BaseMovementMethod implements MovementMethod {
29 @Override
30 public boolean canSelectArbitrarily() {
31 return false;
32 }
33
34 @Override
35 public void initialize(TextView widget, Spannable text) {
36 }
37
38 @Override
39 public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event) {
40 final int movementMetaState = getMovementMetaState(text, event);
41 boolean handled = handleMovementKey(widget, text, keyCode, movementMetaState, event);
42 if (handled) {
43 MetaKeyKeyListener.adjustMetaAfterKeypress(text);
44 MetaKeyKeyListener.resetLockedMeta(text);
45 }
46 return handled;
47 }
48
49 @Override
50 public boolean onKeyOther(TextView widget, Spannable text, KeyEvent event) {
51 final int movementMetaState = getMovementMetaState(text, event);
52 final int keyCode = event.getKeyCode();
53 if (keyCode != KeyEvent.KEYCODE_UNKNOWN
54 && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
55 final int repeat = event.getRepeatCount();
56 boolean handled = false;
57 for (int i = 0; i < repeat; i++) {
58 if (!handleMovementKey(widget, text, keyCode, movementMetaState, event)) {
59 break;
60 }
61 handled = true;
62 }
63 if (handled) {
64 MetaKeyKeyListener.adjustMetaAfterKeypress(text);
65 MetaKeyKeyListener.resetLockedMeta(text);
66 }
67 return handled;
68 }
69 return false;
70 }
71
72 @Override
73 public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event) {
74 return false;
75 }
76
77 @Override
78 public void onTakeFocus(TextView widget, Spannable text, int direction) {
79 }
80
81 @Override
82 public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event) {
83 return false;
84 }
85
86 @Override
87 public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
88 return false;
89 }
90
91 /**
92 * Gets the meta state used for movement using the modifiers tracked by the text
93 * buffer as well as those present in the key event.
94 *
95 * The movement meta state excludes the state of locked modifiers or the SHIFT key
96 * since they are not used by movement actions (but they may be used for selection).
97 *
98 * @param buffer The text buffer.
99 * @param event The key event.
100 * @return The keyboard meta states used for movement.
101 */
102 protected int getMovementMetaState(Spannable buffer, KeyEvent event) {
103 // We ignore locked modifiers and SHIFT.
104 int metaState = (event.getMetaState() | MetaKeyKeyListener.getMetaState(buffer))
105 & ~(MetaKeyKeyListener.META_ALT_LOCKED | MetaKeyKeyListener.META_SYM_LOCKED);
106 return KeyEvent.normalizeMetaState(metaState) & ~KeyEvent.META_SHIFT_MASK;
107 }
108
109 /**
110 * Performs a movement key action.
111 * The default implementation decodes the key down and invokes movement actions
112 * such as {@link #down} and {@link #up}.
113 * {@link #onKeyDown(TextView, Spannable, int, KeyEvent)} calls this method once
114 * to handle an {@link KeyEvent#ACTION_DOWN}.
115 * {@link #onKeyOther(TextView, Spannable, KeyEvent)} calls this method repeatedly
116 * to handle each repetition of an {@link KeyEvent#ACTION_MULTIPLE}.
117 *
118 * @param widget The text view.
119 * @param buffer The text buffer.
120 * @param event The key event.
121 * @param keyCode The key code.
122 * @param movementMetaState The keyboard meta states used for movement.
123 * @param event The key event.
124 * @return True if the event was handled.
125 */
126 protected boolean handleMovementKey(TextView widget, Spannable buffer,
127 int keyCode, int movementMetaState, KeyEvent event) {
128 switch (keyCode) {
129 case KeyEvent.KEYCODE_DPAD_LEFT:
130 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
131 return left(widget, buffer);
132 } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
133 KeyEvent.META_ALT_ON)) {
134 return lineStart(widget, buffer);
135 }
136 break;
137
138 case KeyEvent.KEYCODE_DPAD_RIGHT:
139 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
140 return right(widget, buffer);
141 } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
142 KeyEvent.META_ALT_ON)) {
143 return lineEnd(widget, buffer);
144 }
145 break;
146
147 case KeyEvent.KEYCODE_DPAD_UP:
148 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
149 return up(widget, buffer);
150 } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
151 KeyEvent.META_ALT_ON)) {
152 return top(widget, buffer);
153 }
154 break;
155
156 case KeyEvent.KEYCODE_DPAD_DOWN:
157 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
158 return down(widget, buffer);
159 } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
160 KeyEvent.META_ALT_ON)) {
161 return bottom(widget, buffer);
162 }
163 break;
164
165 case KeyEvent.KEYCODE_PAGE_UP:
166 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
167 return pageUp(widget, buffer);
168 } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
169 KeyEvent.META_ALT_ON)) {
170 return top(widget, buffer);
171 }
172 break;
173
174 case KeyEvent.KEYCODE_PAGE_DOWN:
175 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
176 return pageDown(widget, buffer);
177 } else if (KeyEvent.metaStateHasModifiers(movementMetaState,
178 KeyEvent.META_ALT_ON)) {
179 return bottom(widget, buffer);
180 }
181 break;
182
183 case KeyEvent.KEYCODE_MOVE_HOME:
184 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
185 return home(widget, buffer);
186 }
187 break;
188
189 case KeyEvent.KEYCODE_MOVE_END:
190 if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
191 return end(widget, buffer);
192 }
193 break;
194 }
195 return false;
196 }
197
198 /**
199 * Performs a left movement action.
200 * Moves the cursor or scrolls left by one character.
201 *
202 * @param widget The text view.
203 * @param buffer The text buffer.
204 * @return True if the event was handled.
205 */
206 protected boolean left(TextView widget, Spannable buffer) {
207 return false;
208 }
209
210 /**
211 * Performs a right movement action.
212 * Moves the cursor or scrolls right by one character.
213 *
214 * @param widget The text view.
215 * @param buffer The text buffer.
216 * @return True if the event was handled.
217 */
218 protected boolean right(TextView widget, Spannable buffer) {
219 return false;
220 }
221
222 /**
223 * Performs an up movement action.
224 * Moves the cursor or scrolls up by one line.
225 *
226 * @param widget The text view.
227 * @param buffer The text buffer.
228 * @return True if the event was handled.
229 */
230 protected boolean up(TextView widget, Spannable buffer) {
231 return false;
232 }
233
234 /**
235 * Performs a down movement action.
236 * Moves the cursor or scrolls down by one line.
237 *
238 * @param widget The text view.
239 * @param buffer The text buffer.
240 * @return True if the event was handled.
241 */
242 protected boolean down(TextView widget, Spannable buffer) {
243 return false;
244 }
245
246 /**
247 * Performs a page-up movement action.
248 * Moves the cursor or scrolls up by one page.
249 *
250 * @param widget The text view.
251 * @param buffer The text buffer.
252 * @return True if the event was handled.
253 */
254 protected boolean pageUp(TextView widget, Spannable buffer) {
255 return false;
256 }
257
258 /**
259 * Performs a page-down movement action.
260 * Moves the cursor or scrolls down by one page.
261 *
262 * @param widget The text view.
263 * @param buffer The text buffer.
264 * @return True if the event was handled.
265 */
266 protected boolean pageDown(TextView widget, Spannable buffer) {
267 return false;
268 }
269
270 /**
271 * Performs a top movement action.
272 * Moves the cursor or scrolls to the top of the buffer.
273 *
274 * @param widget The text view.
275 * @param buffer The text buffer.
276 * @return True if the event was handled.
277 */
278 protected boolean top(TextView widget, Spannable buffer) {
279 return false;
280 }
281
282 /**
283 * Performs a bottom movement action.
284 * Moves the cursor or scrolls to the bottom of the buffer.
285 *
286 * @param widget The text view.
287 * @param buffer The text buffer.
288 * @return True if the event was handled.
289 */
290 protected boolean bottom(TextView widget, Spannable buffer) {
291 return false;
292 }
293
294 /**
295 * Performs a line-start movement action.
296 * Moves the cursor or scrolls to the start of the line.
297 *
298 * @param widget The text view.
299 * @param buffer The text buffer.
300 * @return True if the event was handled.
301 */
302 protected boolean lineStart(TextView widget, Spannable buffer) {
303 return false;
304 }
305
306 /**
307 * Performs an line-end movement action.
308 * Moves the cursor or scrolls to the end of the line.
309 *
310 * @param widget The text view.
311 * @param buffer The text buffer.
312 * @return True if the event was handled.
313 */
314 protected boolean lineEnd(TextView widget, Spannable buffer) {
315 return false;
316 }
317
318 /**
319 * Performs a home movement action.
320 * Moves the cursor or scrolls to the start of the line or to the top of the
321 * document depending on whether the insertion point is being moved or
322 * the document is being scrolled.
323 *
324 * @param widget The text view.
325 * @param buffer The text buffer.
326 * @return True if the event was handled.
327 */
328 protected boolean home(TextView widget, Spannable buffer) {
329 return false;
330 }
331
332 /**
333 * Performs an end movement action.
334 * Moves the cursor or scrolls to the start of the line or to the top of the
335 * document depending on whether the insertion point is being moved or
336 * the document is being scrolled.
337 *
338 * @param widget The text view.
339 * @param buffer The text buffer.
340 * @return True if the event was handled.
341 */
342 protected boolean end(TextView widget, Spannable buffer) {
343 return false;
344 }
345}