19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text.method;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunneimport android.text.Layout;
20b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunneimport android.text.Selection;
21b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunneimport android.text.Spannable;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent;
24b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunneimport android.view.View;
25b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunneimport android.widget.TextView;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// XXX this doesn't extend MetaKeyKeyListener because the signatures
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// don't match.  Need to figure that out.  Meanwhile the meta keys
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// won't work in fields that don't take input.
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunnepublic class ArrowKeyMovementMethod implements MovementMethod {
32b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne    private boolean isCap(Spannable buffer) {
33b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) ||
34b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0));
35b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne    }
36b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne
37b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne    private boolean isAlt(Spannable buffer) {
38b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        return MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_ALT_ON) == 1;
39b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne    }
40b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean up(TextView widget, Spannable buffer) {
42b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean cap = isCap(buffer);
43b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean alt = isAlt(buffer);
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Layout layout = widget.getLayout();
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cap) {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.extendSelection(buffer, 0);
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.extendUp(buffer, layout);
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.setSelection(buffer, 0);
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
58ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett                return Selection.moveUp(buffer, layout);
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean down(TextView widget, Spannable buffer) {
64b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean cap = isCap(buffer);
65b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean alt = isAlt(buffer);
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Layout layout = widget.getLayout();
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cap) {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.extendSelection(buffer, buffer.length());
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.extendDown(buffer, layout);
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.setSelection(buffer, buffer.length());
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
80ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett                return Selection.moveDown(buffer, layout);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean left(TextView widget, Spannable buffer) {
86b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean cap = isCap(buffer);
87b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean alt = isAlt(buffer);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Layout layout = widget.getLayout();
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cap) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.extendToLeftEdge(buffer, layout);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.extendLeft(buffer, layout);
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.moveToLeftEdge(buffer, layout);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.moveLeft(buffer, layout);
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean right(TextView widget, Spannable buffer) {
106b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean cap = isCap(buffer);
107b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        boolean alt = isAlt(buffer);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Layout layout = widget.getLayout();
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cap) {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.extendToRightEdge(buffer, layout);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.extendRight(buffer, layout);
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt) {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.moveToRightEdge(buffer, layout);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Selection.moveRight(buffer, layout);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) {
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (executeDown(widget, buffer, keyCode)) {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MetaKeyKeyListener.resetLockedMeta(buffer);
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean executeDown(TextView widget, Spannable buffer, int keyCode) {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (keyCode) {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_DPAD_UP:
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled |= up(widget, buffer);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_DPAD_DOWN:
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled |= down(widget, buffer);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_DPAD_LEFT:
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled |= left(widget, buffer);
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_DPAD_RIGHT:
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled |= right(widget, buffer);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_DPAD_CENTER:
156b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne            if ((MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0) &&
157b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                (widget.showContextMenu())) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = true;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (handled) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MetaKeyKeyListener.resetLockedMeta(buffer);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int code = event.getKeyCode();
176b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        if (code != KeyEvent.KEYCODE_UNKNOWN && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int repeat = event.getRepeatCount();
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean handled = false;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((--repeat) > 0) {
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled |= executeDown(view, text, code);
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return handled;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
186ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett
187b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne    public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
190ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett
191b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
1921c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn        int initialScrollX = -1, initialScrollY = -1;
1931c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn        if (event.getAction() == MotionEvent.ACTION_UP) {
1941c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn            initialScrollX = Touch.getInitialScrollX(widget, buffer);
1951c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn            initialScrollY = Touch.getInitialScrollY(widget, buffer);
1961c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn        }
197ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = Touch.onTouchEvent(widget, buffer, event);
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
200b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (widget.isFocused() && !widget.didTouchFocusSelect()) {
201ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett            if (event.getAction() == MotionEvent.ACTION_DOWN) {
202b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne              boolean cap = isCap(buffer);
203ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett              if (cap) {
204b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                  int offset = widget.getOffset((int) event.getX(), (int) event.getY());
205b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne
206b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                  buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
207ab9289320f598509cf358523ba173d69178a55eaMaryam Garrett
208ab9289320f598509cf358523ba173d69178a55eaMaryam Garrett                  // Disallow intercepting of the touch events, so that
209ab9289320f598509cf358523ba173d69178a55eaMaryam Garrett                  // users can scroll and select at the same time.
210ab9289320f598509cf358523ba173d69178a55eaMaryam Garrett                  // without this, users would get booted out of select
211ab9289320f598509cf358523ba173d69178a55eaMaryam Garrett                  // mode once the view detected it needed to scroll.
212ab9289320f598509cf358523ba173d69178a55eaMaryam Garrett                  widget.getParent().requestDisallowInterceptTouchEvent(true);
213ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett              }
2148cdb684163051c12f37e8a5f9031f17efd9d0fa4Kenny Root            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
215b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                boolean cap = isCap(buffer);
21639f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett
2178cdb684163051c12f37e8a5f9031f17efd9d0fa4Kenny Root                if (cap && handled) {
21839f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    // Before selecting, make sure we've moved out of the "slop".
21939f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    // handled will be true, if we're in select mode AND we're
22039f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    // OUT of the slop
22139f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett
22239f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    // Turn long press off while we're selecting. User needs to
223b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                    // re-tap on the selection to enable long press
22439f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    widget.cancelLongPress();
22539f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett
22639f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    // Update selection as we're moving the selection area.
22739f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett
22839f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    // Get the current touch position
229b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                    int offset = widget.getOffset((int) event.getX(), (int) event.getY());
230b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne
231b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                    Selection.extendSelection(buffer, offset);
23239f0efba92a4420f77e3abc53c367ea3cacde3cfMaryam Garrett                    return true;
233ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett                }
234ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett            } else if (event.getAction() == MotionEvent.ACTION_UP) {
2351c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                // If we have scrolled, then the up shouldn't move the cursor,
2361c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                // but we do need to make sure the cursor is still visible at
2371c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                // the current scroll offset to avoid the scroll jumping later
2381c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                // to show it.
2391c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                if ((initialScrollY >= 0 && initialScrollY != widget.getScrollY()) ||
240b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                    (initialScrollX >= 0 && initialScrollX != widget.getScrollX())) {
2411c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                    widget.moveCursorToVisibleOffset();
2421c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                    return true;
2431c9aefd471cec85f905bea4099f4a641f347e0a0Dianne Hackborn                }
244ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett
245b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                int offset = widget.getOffset((int) event.getX(), (int) event.getY());
246b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                if (isCap(buffer)) {
24762c4ad3b6ba162540c3fb57fcacb375ccfa53454Maryam Garrett                    buffer.removeSpan(LAST_TAP_DOWN);
248b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                    Selection.extendSelection(buffer, offset);
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
250b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne                    Selection.setSelection(buffer, offset);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                MetaKeyKeyListener.resetLockedMeta(buffer);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean canSelectArbitrarily() {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void initialize(TextView widget, Spannable text) {
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Selection.setSelection(text, 0);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onTakeFocus(TextView view, Spannable text, int dir) {
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) {
2732703a42d16af0e62da1bba02b6c935d98debf936Gilles Debunne            if (view.getLayout() == null) {
2742703a42d16af0e62da1bba02b6c935d98debf936Gilles Debunne                // This shouldn't be null, but do something sensible if it is.
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.setSelection(text, text.length());
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Selection.setSelection(text, text.length());
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static MovementMethod getInstance() {
283b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        if (sInstance == null) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sInstance = new ArrowKeyMovementMethod();
285b0d6ba1ec4f71b96cab7d1ff62b846d5cf162c4fGilles Debunne        }
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sInstance;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
290ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett
291ce08379e22609415971ece6ba3417d6d3fd338d2Maryam Garrett    private static final Object LAST_TAP_DOWN = new Object();
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static ArrowKeyMovementMethod sInstance;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
294