| /* |
| * 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.text.method; |
| |
| import android.text.Layout; |
| import android.text.Spannable; |
| import android.view.KeyEvent; |
| import android.view.MotionEvent; |
| import android.widget.TextView; |
| |
| /** |
| * Base classes for movement methods. |
| */ |
| public class BaseMovementMethod implements MovementMethod { |
| @Override |
| public boolean canSelectArbitrarily() { |
| return false; |
| } |
| |
| @Override |
| public void initialize(TextView widget, Spannable text) { |
| } |
| |
| @Override |
| public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event) { |
| final int movementMetaState = getMovementMetaState(text, event); |
| boolean handled = handleMovementKey(widget, text, keyCode, movementMetaState, event); |
| if (handled) { |
| MetaKeyKeyListener.adjustMetaAfterKeypress(text); |
| MetaKeyKeyListener.resetLockedMeta(text); |
| } |
| return handled; |
| } |
| |
| @Override |
| public boolean onKeyOther(TextView widget, Spannable text, KeyEvent event) { |
| final int movementMetaState = getMovementMetaState(text, event); |
| final int keyCode = event.getKeyCode(); |
| if (keyCode != KeyEvent.KEYCODE_UNKNOWN |
| && event.getAction() == KeyEvent.ACTION_MULTIPLE) { |
| final int repeat = event.getRepeatCount(); |
| boolean handled = false; |
| for (int i = 0; i < repeat; i++) { |
| if (!handleMovementKey(widget, text, keyCode, movementMetaState, event)) { |
| break; |
| } |
| handled = true; |
| } |
| if (handled) { |
| MetaKeyKeyListener.adjustMetaAfterKeypress(text); |
| MetaKeyKeyListener.resetLockedMeta(text); |
| } |
| return handled; |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event) { |
| return false; |
| } |
| |
| @Override |
| public void onTakeFocus(TextView widget, Spannable text, int direction) { |
| } |
| |
| @Override |
| public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event) { |
| return false; |
| } |
| |
| @Override |
| public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) { |
| return false; |
| } |
| |
| /** |
| * Gets the meta state used for movement using the modifiers tracked by the text |
| * buffer as well as those present in the key event. |
| * |
| * The movement meta state excludes the state of locked modifiers or the SHIFT key |
| * since they are not used by movement actions (but they may be used for selection). |
| * |
| * @param buffer The text buffer. |
| * @param event The key event. |
| * @return The keyboard meta states used for movement. |
| */ |
| protected int getMovementMetaState(Spannable buffer, KeyEvent event) { |
| // We ignore locked modifiers and SHIFT. |
| int metaState = (event.getMetaState() | MetaKeyKeyListener.getMetaState(buffer)) |
| & ~(MetaKeyKeyListener.META_ALT_LOCKED | MetaKeyKeyListener.META_SYM_LOCKED); |
| return KeyEvent.normalizeMetaState(metaState) & ~KeyEvent.META_SHIFT_MASK; |
| } |
| |
| /** |
| * Performs a movement key action. |
| * The default implementation decodes the key down and invokes movement actions |
| * such as {@link #down} and {@link #up}. |
| * {@link #onKeyDown(TextView, Spannable, int, KeyEvent)} calls this method once |
| * to handle an {@link KeyEvent#ACTION_DOWN}. |
| * {@link #onKeyOther(TextView, Spannable, KeyEvent)} calls this method repeatedly |
| * to handle each repetition of an {@link KeyEvent#ACTION_MULTIPLE}. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @param event The key event. |
| * @param keyCode The key code. |
| * @param movementMetaState The keyboard meta states used for movement. |
| * @param event The key event. |
| * @return True if the event was handled. |
| */ |
| protected boolean handleMovementKey(TextView widget, Spannable buffer, |
| int keyCode, int movementMetaState, KeyEvent event) { |
| switch (keyCode) { |
| case KeyEvent.KEYCODE_DPAD_LEFT: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return left(widget, buffer); |
| } else if (KeyEvent.metaStateHasModifiers(movementMetaState, |
| KeyEvent.META_ALT_ON)) { |
| return lineStart(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_DPAD_RIGHT: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return right(widget, buffer); |
| } else if (KeyEvent.metaStateHasModifiers(movementMetaState, |
| KeyEvent.META_ALT_ON)) { |
| return lineEnd(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_DPAD_UP: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return up(widget, buffer); |
| } else if (KeyEvent.metaStateHasModifiers(movementMetaState, |
| KeyEvent.META_ALT_ON)) { |
| return top(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_DPAD_DOWN: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return down(widget, buffer); |
| } else if (KeyEvent.metaStateHasModifiers(movementMetaState, |
| KeyEvent.META_ALT_ON)) { |
| return bottom(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_PAGE_UP: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return pageUp(widget, buffer); |
| } else if (KeyEvent.metaStateHasModifiers(movementMetaState, |
| KeyEvent.META_ALT_ON)) { |
| return top(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_PAGE_DOWN: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return pageDown(widget, buffer); |
| } else if (KeyEvent.metaStateHasModifiers(movementMetaState, |
| KeyEvent.META_ALT_ON)) { |
| return bottom(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_MOVE_HOME: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return home(widget, buffer); |
| } |
| break; |
| |
| case KeyEvent.KEYCODE_MOVE_END: |
| if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) { |
| return end(widget, buffer); |
| } |
| break; |
| } |
| return false; |
| } |
| |
| /** |
| * Performs a left movement action. |
| * Moves the cursor or scrolls left by one character. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean left(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a right movement action. |
| * Moves the cursor or scrolls right by one character. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean right(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs an up movement action. |
| * Moves the cursor or scrolls up by one line. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean up(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a down movement action. |
| * Moves the cursor or scrolls down by one line. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean down(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a page-up movement action. |
| * Moves the cursor or scrolls up by one page. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean pageUp(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a page-down movement action. |
| * Moves the cursor or scrolls down by one page. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean pageDown(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a top movement action. |
| * Moves the cursor or scrolls to the top of the buffer. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean top(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a bottom movement action. |
| * Moves the cursor or scrolls to the bottom of the buffer. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean bottom(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a line-start movement action. |
| * Moves the cursor or scrolls to the start of the line. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean lineStart(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs an line-end movement action. |
| * Moves the cursor or scrolls to the end of the line. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean lineEnd(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs a home movement action. |
| * Moves the cursor or scrolls to the start of the line or to the top of the |
| * document depending on whether the insertion point is being moved or |
| * the document is being scrolled. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean home(TextView widget, Spannable buffer) { |
| return false; |
| } |
| |
| /** |
| * Performs an end movement action. |
| * Moves the cursor or scrolls to the start of the line or to the top of the |
| * document depending on whether the insertion point is being moved or |
| * the document is being scrolled. |
| * |
| * @param widget The text view. |
| * @param buffer The text buffer. |
| * @return True if the event was handled. |
| */ |
| protected boolean end(TextView widget, Spannable buffer) { |
| return false; |
| } |
| } |