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
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.*;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.*;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectLinkMovementMethod
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectextends ScrollingMovementMethod
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int CLICK = 1;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int UP = 2;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DOWN = 3;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyDown(TextView widget, Spannable buffer,
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             int keyCode, KeyEvent event) {
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (keyCode) {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_DPAD_CENTER:
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case KeyEvent.KEYCODE_ENTER:
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (event.getRepeatCount() == 0) {
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (action(CLICK, widget, buffer)) {
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return true;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.onKeyDown(widget, buffer, keyCode, event);
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean up(TextView widget, Spannable buffer) {
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action(UP, widget, buffer)) {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.up(widget, buffer);
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean down(TextView widget, Spannable buffer) {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action(DOWN, widget, buffer)) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.down(widget, buffer);
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean left(TextView widget, Spannable buffer) {
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action(UP, widget, buffer)) {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.left(widget, buffer);
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean right(TextView widget, Spannable buffer) {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action(DOWN, widget, buffer)) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.right(widget, buffer);
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean action(int what, TextView widget, Spannable buffer) {
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Layout layout = widget.getLayout();
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int padding = widget.getTotalPaddingTop() +
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      widget.getTotalPaddingBottom();
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int areatop = widget.getScrollY();
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int areabot = areatop + widget.getHeight() - padding;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int linetop = layout.getLineForVertical(areatop);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int linebot = layout.getLineForVertical(areabot);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int first = layout.getLineStart(linetop);
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int last = layout.getLineEnd(linebot);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClickableSpan[] candidates = buffer.getSpans(first, last, ClickableSpan.class);
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int a = Selection.getSelectionStart(buffer);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int b = Selection.getSelectionEnd(buffer);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int selStart = Math.min(a, b);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int selEnd = Math.max(a, b);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selStart < 0) {
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (buffer.getSpanStart(FROM_BELOW) >= 0) {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                selStart = selEnd = buffer.length();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selStart > last)
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            selStart = selEnd = Integer.MAX_VALUE;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selEnd < first)
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            selStart = selEnd = -1;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (what) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case CLICK:
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (selStart == selEnd) {
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ClickableSpan[] link = buffer.getSpans(selStart, selEnd, ClickableSpan.class);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (link.length != 1)
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            link[0].onClick(widget);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case UP:
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int beststart, bestend;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            beststart = -1;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bestend = -1;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < candidates.length; i++) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int end = buffer.getSpanEnd(candidates[i]);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (end < selEnd || selStart == selEnd) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (end > bestend) {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        beststart = buffer.getSpanStart(candidates[i]);
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        bestend = end;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (beststart >= 0) {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.setSelection(buffer, bestend, beststart);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case DOWN:
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            beststart = Integer.MAX_VALUE;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bestend = Integer.MAX_VALUE;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < candidates.length; i++) {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int start = buffer.getSpanStart(candidates[i]);
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (start > selStart || selStart == selEnd) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (start < beststart) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        beststart = start;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        bestend = buffer.getSpanEnd(candidates[i]);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bestend < Integer.MAX_VALUE) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.setSelection(buffer, beststart, bestend);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onKeyUp(TextView widget, Spannable buffer,
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                           int keyCode, KeyEvent event) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTouchEvent(TextView widget, Spannable buffer,
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MotionEvent event) {
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int action = event.getAction();
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action == MotionEvent.ACTION_UP ||
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            action == MotionEvent.ACTION_DOWN) {
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int x = (int) event.getX();
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int y = (int) event.getY();
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            x -= widget.getTotalPaddingLeft();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            y -= widget.getTotalPaddingTop();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            x += widget.getScrollX();
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            y += widget.getScrollY();
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Layout layout = widget.getLayout();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line = layout.getLineForVertical(y);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int off = layout.getOffsetForHorizontal(line, x);
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (link.length != 0) {
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (action == MotionEvent.ACTION_UP) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    link[0].onClick(widget);
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (action == MotionEvent.ACTION_DOWN) {
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Selection.setSelection(buffer,
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           buffer.getSpanStart(link[0]),
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           buffer.getSpanEnd(link[0]));
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Selection.removeSelection(buffer);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.onTouchEvent(widget, buffer, event);
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void initialize(TextView widget, Spannable text) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Selection.removeSelection(text);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        text.removeSpan(FROM_BELOW);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onTakeFocus(TextView view, Spannable text, int dir) {
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Selection.removeSelection(text);
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((dir & View.FOCUS_BACKWARD) != 0) {
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.setSpan(FROM_BELOW, 0, 0, Spannable.SPAN_POINT_POINT);
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.removeSpan(FROM_BELOW);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static MovementMethod getInstance() {
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sInstance == null)
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sInstance = new LinkMovementMethod();
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sInstance;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static LinkMovementMethod sInstance;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Object FROM_BELOW = new NoCopySpan.Concrete();
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
257