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