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