ScrollingMovementMethod.java revision 67b6ab72ae96a9f2be929de2c32c110df5390fdd
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.view.MotionEvent;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.*;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown/**
2567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown * A movement method that interprets movement keys by scrolling the text buffer.
2667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown */
2767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brownpublic class ScrollingMovementMethod extends BaseMovementMethod implements MovementMethod {
2867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getTopLine(TextView widget) {
2967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return widget.getLayout().getLineForVertical(widget.getScrollY());
3067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getBottomLine(TextView widget) {
3367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
3467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getInnerWidth(TextView widget) {
3767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight();
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getInnerHeight(TextView widget) {
4167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
4267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getCharacterWidth(TextView widget) {
4567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return (int) Math.ceil(widget.getPaint().getFontSpacing());
4667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getScrollBoundsLeft(TextView widget) {
4967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
5067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int topLine = getTopLine(widget);
5167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int bottomLine = getBottomLine(widget);
5267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (topLine > bottomLine) {
5367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return 0;
5467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
5567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int left = Integer.MAX_VALUE;
5667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        for (int line = topLine; line <= bottomLine; line++) {
5767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            final int lineLeft = (int) Math.floor(layout.getLineLeft(line));
5867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            if (lineLeft < left) {
5967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown                left = lineLeft;
6067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            }
6167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
6267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return left;
6367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    private int getScrollBoundsRight(TextView widget) {
6667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
6767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int topLine = getTopLine(widget);
6867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int bottomLine = getBottomLine(widget);
6967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (topLine > bottomLine) {
7067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return 0;
7167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
7267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int right = Integer.MIN_VALUE;
7367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        for (int line = topLine; line <= bottomLine; line++) {
7467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            final int lineRight = (int) Math.ceil(layout.getLineRight(line));
7567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            if (lineRight > right) {
7667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown                right = lineRight;
7767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            }
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return right;
8067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
8367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean left(TextView widget, Spannable buffer) {
8467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int minScrollX = getScrollBoundsLeft(widget);
8567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int scrollX = widget.getScrollX();
8667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (scrollX > minScrollX) {
8767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            scrollX = Math.max(scrollX - getCharacterWidth(widget), minScrollX);
8867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            widget.scrollTo(scrollX, widget.getScrollY());
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return false;
9267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
9567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean right(TextView widget, Spannable buffer) {
9667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
9767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int scrollX = widget.getScrollX();
9867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (scrollX < maxScrollX) {
9967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            scrollX = Math.min(scrollX + getCharacterWidth(widget), maxScrollX);
10067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            widget.scrollTo(scrollX, widget.getScrollY());
10167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
10267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean up(TextView widget, Spannable buffer) {
10867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
10967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int top = widget.getScrollY();
11067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int topLine = layout.getLineForVertical(top);
11167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (layout.getLineTop(topLine) == top) {
11267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            // If the top line is partially visible, bring it all the way
11367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            // into view; otherwise, bring the previous line into view.
11467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            topLine -= 1;
11567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
11667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (topLine >= 0) {
11767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean down(TextView widget, Spannable buffer) {
12567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
12667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int innerHeight = getInnerHeight(widget);
12767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int bottom = widget.getScrollY() + innerHeight;
12867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int bottomLine = layout.getLineForVertical(bottom);
12967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (layout.getLineTop(bottomLine + 1) < bottom + 1) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Less than a pixel of this line is out of view,
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // so we must have tried to make it entirely in view
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // and now want the next line to be in view instead.
13367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            bottomLine += 1;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (bottomLine <= layout.getLineCount() - 1) {
13667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            Touch.scrollTo(widget, layout, widget.getScrollX(),
13767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown                    layout.getLineTop(bottomLine + 1) - innerHeight);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
14467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean pageUp(TextView widget, Spannable buffer) {
14567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
14667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int top = widget.getScrollY() - getInnerHeight(widget);
14767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int topLine = layout.getLineForVertical(top);
14867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (topLine >= 0) {
14967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
15067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
15167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
15267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return false;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
15667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean pageDown(TextView widget, Spannable buffer) {
15767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
15867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int innerHeight = getInnerHeight(widget);
15967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int bottom = widget.getScrollY() + innerHeight + innerHeight;
16067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int bottomLine = layout.getLineForVertical(bottom);
16167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (bottomLine <= layout.getLineCount() - 1) {
16267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            Touch.scrollTo(widget, layout, widget.getScrollX(),
16367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown                    layout.getLineTop(bottomLine + 1) - innerHeight);
16467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return false;
16767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
17067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean top(TextView widget, Spannable buffer) {
17167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
17267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (getTopLine(widget) >= 0) {
17367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0));
17467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
17567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
17667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return false;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
18067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean bottom(TextView widget, Spannable buffer) {
18167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final Layout layout = widget.getLayout();
18267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int lineCount = layout.getLineCount();
18367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (getBottomLine(widget) <= lineCount - 1) {
18467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            Touch.scrollTo(widget, layout, widget.getScrollX(),
18567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown                    layout.getLineTop(lineCount) - getInnerHeight(widget));
18667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
18767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
19267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean lineStart(TextView widget, Spannable buffer) {
19367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int minScrollX = getScrollBoundsLeft(widget);
19467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int scrollX = widget.getScrollX();
19567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (scrollX > minScrollX) {
19667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            widget.scrollTo(minScrollX, widget.getScrollY());
19767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown
20267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
20367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean lineEnd(TextView widget, Spannable buffer) {
20467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
20567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        int scrollX = widget.getScrollX();
20667b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        if (scrollX < maxScrollX) {
20767b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            widget.scrollTo(maxScrollX, widget.getScrollY());
20867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown            return true;
20967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21267b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown
21367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
21467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean home(TextView widget, Spannable buffer) {
21567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return top(widget, buffer);
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
21967b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    protected boolean end(TextView widget, Spannable buffer) {
22067b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return bottom(widget, buffer);
22167b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22367b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
22467b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
22567b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown        return Touch.onTouchEvent(widget, buffer, event);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22867b6ab72ae96a9f2be929de2c32c110df5390fddJeff Brown    @Override
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onTakeFocus(TextView widget, Spannable text, int dir) {
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Layout layout = widget.getLayout();
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (layout != null && (dir & View.FOCUS_FORWARD) != 0) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            widget.scrollTo(widget.getScrollX(),
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            layout.getLineTop(0));
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (layout != null && (dir & View.FOCUS_BACKWARD) != 0) {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int padding = widget.getTotalPaddingTop() +
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          widget.getTotalPaddingBottom();
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line = layout.getLineCount() - 1;
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            widget.scrollTo(widget.getScrollX(),
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            layout.getLineTop(line+1) -
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (widget.getHeight() - padding));
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 ScrollingMovementMethod();
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 ScrollingMovementMethod sInstance;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
256