blob: 2be18d674816adb65e698df23d4b75650513169b [file] [log] [blame]
/*
* 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;
}
}