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;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkeyimport java.text.BreakIterator;
20e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Utility class for manipulating cursors and selections in CharSequences.
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A cursor is a selection where the start and end are at the same offset.
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Selection {
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Selection() { /* cannot be instantiated */ }
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Retrieving the selection
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the offset of the selection anchor or cursor, or -1 if
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * there is no selection or cursor.
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int getSelectionStart(CharSequence text) {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (text instanceof Spanned)
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ((Spanned) text).getSpanStart(SELECTION_START);
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
43e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the offset of the selection edge or cursor, or -1 if
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * there is no selection or cursor.
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int getSelectionEnd(CharSequence text) {
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (text instanceof Spanned)
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ((Spanned) text).getSpanStart(SELECTION_END);
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Setting the selection
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // private static int pin(int value, int min, int max) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //     return value < min ? 0 : (value > max ? max : value);
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // }
62e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the selection anchor to <code>start</code> and the selection edge
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to <code>stop</code>.
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void setSelection(Spannable text, int start, int stop) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // int len = text.length();
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // start = pin(start, 0, len);  XXX remove unless we really need it
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // stop = pin(stop, 0, len);
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ostart = getSelectionStart(text);
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int oend = getSelectionEnd(text);
74e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ostart != start || oend != stop) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.setSpan(SELECTION_START, start, start,
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         Spanned.SPAN_POINT_POINT|Spanned.SPAN_INTERMEDIATE);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.setSpan(SELECTION_END, stop, stop,
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         Spanned.SPAN_POINT_POINT);
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the cursor to offset <code>index</code>.
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final void setSelection(Spannable text, int index) {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelection(text, index, index);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Select the entire text.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final void selectAll(Spannable text) {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelection(text, 0, text.length());
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the selection edge to offset <code>index</code>.
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final void extendSelection(Spannable text, int index) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (text.getSpanStart(SELECTION_END) != index)
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.setSpan(SELECTION_END, index, index, Spanned.SPAN_POINT_POINT);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Remove the selection or cursor, if any, from the text.
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final void removeSelection(Spannable text) {
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        text.removeSpan(SELECTION_START);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        text.removeSpan(SELECTION_END);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Moving the selection within the layout
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the cursor to the buffer offset physically above the current
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * offset, or return false if the cursor is already on the top line.
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean moveUp(Spannable text, Layout layout) {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getSelectionStart(text);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start != end) {
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int min = Math.min(start, end);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int max = Math.max(start, end);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(text, min);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (min == 0 && max == text.length()) {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line = layout.getLineForOffset(end);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line > 0) {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int move;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (layout.getParagraphDirection(line) ==
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    layout.getParagraphDirection(line - 1)) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float h = layout.getPrimaryHorizontal(end);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    move = layout.getOffsetForHorizontal(line - 1, h);
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    move = layout.getLineStart(line - 1);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setSelection(text, move);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the cursor to the buffer offset physically below the current
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * offset, or return false if the cursor is already on the bottom line.
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean moveDown(Spannable text, Layout layout) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getSelectionStart(text);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start != end) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int min = Math.min(start, end);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int max = Math.max(start, end);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(text, max);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (min == 0 && max == text.length()) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line = layout.getLineForOffset(end);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line < layout.getLineCount() - 1) {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int move;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (layout.getParagraphDirection(line) ==
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    layout.getParagraphDirection(line + 1)) {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float h = layout.getPrimaryHorizontal(end);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    move = layout.getOffsetForHorizontal(line + 1, h);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    move = layout.getLineStart(line + 1);
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setSelection(text, move);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the cursor to the buffer offset physically to the left of
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current offset, or return false if the cursor is already
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * at the left edge of the line and there is not another line to move it to.
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean moveLeft(Spannable text, Layout layout) {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getSelectionStart(text);
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start != end) {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(text, chooseHorizontal(layout, -1, start, end));
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int to = layout.getOffsetToLeftOf(end);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (to != end) {
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setSelection(text, to);
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the cursor to the buffer offset physically to the right of
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current offset, or return false if the cursor is already at
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * at the right edge of the line and there is not another line
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to move it to.
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean moveRight(Spannable text, Layout layout) {
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getSelectionStart(text);
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start != end) {
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelection(text, chooseHorizontal(layout, 1, start, end));
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int to = layout.getOffsetToRightOf(end);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (to != end) {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setSelection(text, to);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the selection end to the buffer offset physically above
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current selection end.
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean extendUp(Spannable text, Layout layout) {
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = layout.getLineForOffset(end);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line > 0) {
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int move;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (layout.getParagraphDirection(line) ==
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                layout.getParagraphDirection(line - 1)) {
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                float h = layout.getPrimaryHorizontal(end);
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                move = layout.getOffsetForHorizontal(line - 1, h);
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                move = layout.getLineStart(line - 1);
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extendSelection(text, move);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (end != 0) {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extendSelection(text, 0);
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the selection end to the buffer offset physically below
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current selection end.
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean extendDown(Spannable text, Layout layout) {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = layout.getLineForOffset(end);
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line < layout.getLineCount() - 1) {
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int move;
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (layout.getParagraphDirection(line) ==
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                layout.getParagraphDirection(line + 1)) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                float h = layout.getPrimaryHorizontal(end);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                move = layout.getOffsetForHorizontal(line + 1, h);
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                move = layout.getLineStart(line + 1);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extendSelection(text, move);
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (end != text.length()) {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extendSelection(text, text.length());
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the selection end to the buffer offset physically to the left of
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current selection end.
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean extendLeft(Spannable text, Layout layout) {
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int to = layout.getOffsetToLeftOf(end);
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (to != end) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extendSelection(text, to);
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Move the selection end to the buffer offset physically to the right of
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current selection end.
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean extendRight(Spannable text, Layout layout) {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getSelectionEnd(text);
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int to = layout.getOffsetToRightOf(end);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (to != end) {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extendSelection(text, to);
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean extendToLeftEdge(Spannable text, Layout layout) {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int where = findEdge(text, layout, -1);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        extendSelection(text, where);
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean extendToRightEdge(Spannable text, Layout layout) {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int where = findEdge(text, layout, 1);
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        extendSelection(text, where);
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean moveToLeftEdge(Spannable text, Layout layout) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int where = findEdge(text, layout, -1);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelection(text, where);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean moveToRightEdge(Spannable text, Layout layout) {
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int where = findEdge(text, layout, 1);
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelection(text, where);
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
362e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    /** {@hide} */
363e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    public static interface PositionIterator {
364e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        public static final int DONE = BreakIterator.DONE;
365e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
366e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        public int preceding(int position);
367e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        public int following(int position);
368e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    }
369e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
370e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    /** {@hide} */
371e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    public static boolean moveToPreceding(
372e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            Spannable text, PositionIterator iter, boolean extendSelection) {
373e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        final int offset = iter.preceding(getSelectionEnd(text));
374e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        if (offset != PositionIterator.DONE) {
375e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            if (extendSelection) {
376e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey                extendSelection(text, offset);
377e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            } else {
378e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey                setSelection(text, offset);
379e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            }
380e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        }
381e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        return true;
382e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    }
383e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
384e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    /** {@hide} */
385e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    public static boolean moveToFollowing(
386e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            Spannable text, PositionIterator iter, boolean extendSelection) {
387e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        final int offset = iter.following(getSelectionEnd(text));
388e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        if (offset != PositionIterator.DONE) {
389e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            if (extendSelection) {
390e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey                extendSelection(text, offset);
391e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            } else {
392e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey                setSelection(text, offset);
393e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey            }
394e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        }
395e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey        return true;
396e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey    }
397e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static int findEdge(Spannable text, Layout layout, int dir) {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int pt = getSelectionEnd(text);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = layout.getLineForOffset(pt);
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int pdir = layout.getParagraphDirection(line);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dir * pdir < 0) {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return layout.getLineStart(line);
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int end = layout.getLineEnd(line);
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line == layout.getLineCount() - 1)
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return end;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return end - 1;
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static int chooseHorizontal(Layout layout, int direction,
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        int off1, int off2) {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line1 = layout.getLineForOffset(off1);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line2 = layout.getLineForOffset(off2);
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line1 == line2) {
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // same line, so it goes by pure physical direction
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h1 = layout.getPrimaryHorizontal(off1);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h2 = layout.getPrimaryHorizontal(off2);
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction < 0) {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // to left
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (h1 < h2)
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return off1;
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                else
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return off2;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // to right
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (h1 > h2)
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return off1;
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                else
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return off2;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // different line, so which line is "left" and which is "right"
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // depends upon the directionality of the text
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This only checks at one end, but it's not clear what the
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // right thing to do is if the ends don't agree.  Even if it
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // is wrong it should still not be too bad.
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line = layout.getLineForOffset(off1);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int textdir = layout.getParagraphDirection(line);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (textdir == direction)
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Math.max(off1, off2);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return Math.min(off1, off2);
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4582d0e87b64402459d89adfd004083a748f81a0391Gilles Debunne    private static final class START implements NoCopySpan { }
4592d0e87b64402459d89adfd004083a748f81a0391Gilles Debunne    private static final class END implements NoCopySpan { }
460e982dfc1bae36620f67371efc7b0a0f8adc9450dJeff Sharkey
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Public constants
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Object SELECTION_START = new START();
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Object SELECTION_END = new END();
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
468