ArrowKeyMovementMethod.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/* 2 * Copyright (C) 2006 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.view.KeyEvent; 20import android.text.*; 21import android.widget.TextView; 22import android.view.View; 23import android.view.MotionEvent; 24 25// XXX this doesn't extend MetaKeyKeyListener because the signatures 26// don't match. Need to figure that out. Meanwhile the meta keys 27// won't work in fields that don't take input. 28 29public class 30ArrowKeyMovementMethod 31implements MovementMethod 32{ 33 private boolean up(TextView widget, Spannable buffer) { 34 boolean cap = MetaKeyKeyListener.getMetaState(buffer, 35 KeyEvent.META_SHIFT_ON) == 1; 36 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 37 KeyEvent.META_ALT_ON) == 1; 38 Layout layout = widget.getLayout(); 39 40 if (cap) { 41 if (alt) { 42 Selection.extendSelection(buffer, 0); 43 return true; 44 } else { 45 return Selection.extendUp(buffer, layout); 46 } 47 } else { 48 if (alt) { 49 Selection.setSelection(buffer, 0); 50 return true; 51 } else { 52 return Selection.moveUp(buffer, layout); 53 } 54 } 55 } 56 57 private boolean down(TextView widget, Spannable buffer) { 58 boolean cap = MetaKeyKeyListener.getMetaState(buffer, 59 KeyEvent.META_SHIFT_ON) == 1; 60 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 61 KeyEvent.META_ALT_ON) == 1; 62 Layout layout = widget.getLayout(); 63 64 if (cap) { 65 if (alt) { 66 Selection.extendSelection(buffer, buffer.length()); 67 return true; 68 } else { 69 return Selection.extendDown(buffer, layout); 70 } 71 } else { 72 if (alt) { 73 Selection.setSelection(buffer, buffer.length()); 74 return true; 75 } else { 76 return Selection.moveDown(buffer, layout); 77 } 78 } 79 } 80 81 private boolean left(TextView widget, Spannable buffer) { 82 boolean cap = MetaKeyKeyListener.getMetaState(buffer, 83 KeyEvent.META_SHIFT_ON) == 1; 84 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 85 KeyEvent.META_ALT_ON) == 1; 86 Layout layout = widget.getLayout(); 87 88 if (cap) { 89 if (alt) { 90 return Selection.extendToLeftEdge(buffer, layout); 91 } else { 92 return Selection.extendLeft(buffer, layout); 93 } 94 } else { 95 if (alt) { 96 return Selection.moveToLeftEdge(buffer, layout); 97 } else { 98 return Selection.moveLeft(buffer, layout); 99 } 100 } 101 } 102 103 private boolean right(TextView widget, Spannable buffer) { 104 boolean cap = MetaKeyKeyListener.getMetaState(buffer, 105 KeyEvent.META_SHIFT_ON) == 1; 106 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 107 KeyEvent.META_ALT_ON) == 1; 108 Layout layout = widget.getLayout(); 109 110 if (cap) { 111 if (alt) { 112 return Selection.extendToRightEdge(buffer, layout); 113 } else { 114 return Selection.extendRight(buffer, layout); 115 } 116 } else { 117 if (alt) { 118 return Selection.moveToRightEdge(buffer, layout); 119 } else { 120 return Selection.moveRight(buffer, layout); 121 } 122 } 123 } 124 125 public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 126 boolean handled = false; 127 128 switch (keyCode) { 129 case KeyEvent.KEYCODE_DPAD_UP: 130 handled |= up(widget, buffer); 131 break; 132 133 case KeyEvent.KEYCODE_DPAD_DOWN: 134 handled |= down(widget, buffer); 135 break; 136 137 case KeyEvent.KEYCODE_DPAD_LEFT: 138 handled |= left(widget, buffer); 139 break; 140 141 case KeyEvent.KEYCODE_DPAD_RIGHT: 142 handled |= right(widget, buffer); 143 break; 144 } 145 146 if (handled) { 147 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); 148 MetaKeyKeyListener.resetLockedMeta(buffer); 149 } 150 151 return handled; 152 } 153 154 public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 155 return false; 156 } 157 158 public boolean onTrackballEvent(TextView widget, Spannable text, 159 MotionEvent event) { 160 return false; 161 } 162 163 public boolean onTouchEvent(TextView widget, Spannable buffer, 164 MotionEvent event) { 165 boolean handled = Touch.onTouchEvent(widget, buffer, event); 166 167 if (widget.isFocused()) { 168 if (event.getAction() == MotionEvent.ACTION_UP) { 169 int x = (int) event.getX(); 170 int y = (int) event.getY(); 171 172 x -= widget.getTotalPaddingLeft(); 173 y -= widget.getTotalPaddingTop(); 174 175 x += widget.getScrollX(); 176 y += widget.getScrollY(); 177 178 Layout layout = widget.getLayout(); 179 int line = layout.getLineForVertical(y); 180 int off = layout.getOffsetForHorizontal(line, x); 181 182 boolean cap = (event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0; 183 184 if (cap) { 185 Selection.extendSelection(buffer, off); 186 } else { 187 Selection.setSelection(buffer, off); 188 } 189 190 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); 191 MetaKeyKeyListener.resetLockedMeta(buffer); 192 193 return true; 194 } 195 } 196 197 return handled; 198 } 199 200 public boolean canSelectArbitrarily() { 201 return true; 202 } 203 204 public void initialize(TextView widget, Spannable text) { 205 Selection.setSelection(text, 0); 206 } 207 208 public void onTakeFocus(TextView view, Spannable text, int dir) { 209 if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) { 210 Layout layout = view.getLayout(); 211 212 if (layout == null) { 213 /* 214 * This shouldn't be null, but do something sensible if it is. 215 */ 216 Selection.setSelection(text, text.length()); 217 } else { 218 /* 219 * Put the cursor at the end of the first line, which is 220 * either the last offset if there is only one line, or the 221 * offset before the first character of the second line 222 * if there is more than one line. 223 */ 224 if (layout.getLineCount() == 1) { 225 Selection.setSelection(text, text.length()); 226 } else { 227 Selection.setSelection(text, layout.getLineStart(1) - 1); 228 } 229 } 230 } else { 231 Selection.setSelection(text, text.length()); 232 } 233 } 234 235 public static MovementMethod getInstance() { 236 if (sInstance == null) 237 sInstance = new ArrowKeyMovementMethod(); 238 239 return sInstance; 240 } 241 242 private static ArrowKeyMovementMethod sInstance; 243} 244