Loading api/current.xml +35 −1 Original line number Diff line number Diff line Loading @@ -198789,6 +198789,23 @@ <parameter name="buffer" type="android.text.Spannable"> </parameter> </method> <method name="onGenericMotionEvent" return="boolean" abstract="false" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > <parameter name="widget" type="android.widget.TextView"> </parameter> <parameter name="text" type="android.text.Spannable"> </parameter> <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> <method name="onKeyDown" return="boolean" abstract="false" Loading Loading @@ -199862,6 +199879,23 @@ <parameter name="text" type="android.text.Spannable"> </parameter> </method> <method name="onGenericMotionEvent" return="boolean" abstract="true" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > <parameter name="widget" type="android.widget.TextView"> </parameter> <parameter name="text" type="android.text.Spannable"> </parameter> <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> <method name="onKeyDown" return="boolean" abstract="true" Loading Loading @@ -266599,7 +266633,7 @@ deprecated="not deprecated" visibility="public" > <parameter name="t" type="T"> <parameter name="arg0" type="T"> </parameter> </method> </interface> core/java/android/text/method/BaseMovementMethod.java +306 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.text.method; import android.text.Layout; import android.text.Spannable; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.widget.TextView; Loading Loading @@ -88,6 +89,39 @@ public class BaseMovementMethod implements MovementMethod { return false; } @Override public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (event.getAction()) { case MotionEvent.ACTION_SCROLL: { final float vscroll; final float hscroll; if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) { vscroll = 0; hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); } else { vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL); hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); } boolean handled = false; if (hscroll < 0) { handled |= scrollLeft(widget, text, (int)Math.ceil(-hscroll)); } else if (hscroll > 0) { handled |= scrollRight(widget, text, (int)Math.ceil(hscroll)); } if (vscroll < 0) { handled |= scrollUp(widget, text, (int)Math.ceil(-vscroll)); } else if (vscroll > 0) { handled |= scrollDown(widget, text, (int)Math.ceil(vscroll)); } return handled; } } } return false; } /** * Gets the meta state used for movement using the modifiers tracked by the text * buffer as well as those present in the key event. Loading Loading @@ -342,4 +376,276 @@ public class BaseMovementMethod implements MovementMethod { protected boolean end(TextView widget, Spannable buffer) { return false; } private int getTopLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY()); } private int getBottomLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget)); } private int getInnerWidth(TextView widget) { return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight(); } private int getInnerHeight(TextView widget) { return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom(); } private int getCharacterWidth(TextView widget) { return (int) Math.ceil(widget.getPaint().getFontSpacing()); } private int getScrollBoundsLeft(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int left = Integer.MAX_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineLeft = (int) Math.floor(layout.getLineLeft(line)); if (lineLeft < left) { left = lineLeft; } } return left; } private int getScrollBoundsRight(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int right = Integer.MIN_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineRight = (int) Math.ceil(layout.getLineRight(line)); if (lineRight > right) { right = lineRight; } } return right; } /** * Performs a scroll left action. * Scrolls left by the specified number of characters. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of characters to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollLeft(TextView widget, Spannable buffer, int amount) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { scrollX = Math.max(scrollX - getCharacterWidth(widget) * amount, minScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; } /** * Performs a scroll right action. * Scrolls right by the specified number of characters. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of characters to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollRight(TextView widget, Spannable buffer, int amount) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { scrollX = Math.min(scrollX + getCharacterWidth(widget) * amount, maxScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; } /** * Performs a scroll up action. * Scrolls up by the specified number of lines. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of lines to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollUp(TextView widget, Spannable buffer, int amount) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY(); int topLine = layout.getLineForVertical(top); if (layout.getLineTop(topLine) == top) { // If the top line is partially visible, bring it all the way // into view; otherwise, bring the previous line into view. topLine -= 1; } if (topLine >= 0) { topLine = Math.max(topLine - amount + 1, 0); Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; } /** * Performs a scroll down action. * Scrolls down by the specified number of lines. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of lines to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollDown(TextView widget, Spannable buffer, int amount) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (layout.getLineTop(bottomLine + 1) < bottom + 1) { // Less than a pixel of this line is out of view, // so we must have tried to make it entirely in view // and now want the next line to be in view instead. bottomLine += 1; } final int limit = layout.getLineCount() - 1; if (bottomLine <= limit) { bottomLine = Math.min(bottomLine + amount - 1, limit); Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; } /** * Performs a scroll page up action. * Scrolls up by one page. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollPageUp(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY() - getInnerHeight(widget); int topLine = layout.getLineForVertical(top); if (topLine >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; } /** * Performs a scroll page up action. * Scrolls down by one page. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollPageDown(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (bottomLine <= layout.getLineCount() - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; } /** * Performs a scroll to top action. * Scrolls to the top of the document. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollTop(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); if (getTopLine(widget) >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0)); return true; } return false; } /** * Performs a scroll to bottom action. * Scrolls to the bottom of the document. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollBottom(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int lineCount = layout.getLineCount(); if (getBottomLine(widget) <= lineCount - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(lineCount) - getInnerHeight(widget)); return true; } return false; } /** * Performs a scroll to line start action. * Scrolls to the start of the line. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollLineStart(TextView widget, Spannable buffer) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { widget.scrollTo(minScrollX, widget.getScrollY()); return true; } return false; } /** * Performs a scroll to line end action. * Scrolls to the end of the line. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollLineEnd(TextView widget, Spannable buffer) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { widget.scrollTo(maxScrollX, widget.getScrollY()); return true; } return false; } } core/java/android/text/method/MovementMethod.java +1 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ public interface MovementMethod { public void onTakeFocus(TextView widget, Spannable text, int direction); public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event); public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event); public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event); /** * Returns true if this movement method allows arbitrary selection Loading core/java/android/text/method/ScrollingMovementMethod.java +10 −145 Original line number Diff line number Diff line Loading @@ -25,189 +25,54 @@ import android.view.View; * A movement method that interprets movement keys by scrolling the text buffer. */ public class ScrollingMovementMethod extends BaseMovementMethod implements MovementMethod { private int getTopLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY()); } private int getBottomLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget)); } private int getInnerWidth(TextView widget) { return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight(); } private int getInnerHeight(TextView widget) { return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom(); } private int getCharacterWidth(TextView widget) { return (int) Math.ceil(widget.getPaint().getFontSpacing()); } private int getScrollBoundsLeft(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int left = Integer.MAX_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineLeft = (int) Math.floor(layout.getLineLeft(line)); if (lineLeft < left) { left = lineLeft; } } return left; } private int getScrollBoundsRight(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int right = Integer.MIN_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineRight = (int) Math.ceil(layout.getLineRight(line)); if (lineRight > right) { right = lineRight; } } return right; } @Override protected boolean left(TextView widget, Spannable buffer) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { scrollX = Math.max(scrollX - getCharacterWidth(widget), minScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; return scrollLeft(widget, buffer, 1); } @Override protected boolean right(TextView widget, Spannable buffer) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { scrollX = Math.min(scrollX + getCharacterWidth(widget), maxScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; return scrollRight(widget, buffer, 1); } @Override protected boolean up(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY(); int topLine = layout.getLineForVertical(top); if (layout.getLineTop(topLine) == top) { // If the top line is partially visible, bring it all the way // into view; otherwise, bring the previous line into view. topLine -= 1; } if (topLine >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; return scrollUp(widget, buffer, 1); } @Override protected boolean down(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (layout.getLineTop(bottomLine + 1) < bottom + 1) { // Less than a pixel of this line is out of view, // so we must have tried to make it entirely in view // and now want the next line to be in view instead. bottomLine += 1; } if (bottomLine <= layout.getLineCount() - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; return scrollDown(widget, buffer, 1); } @Override protected boolean pageUp(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY() - getInnerHeight(widget); int topLine = layout.getLineForVertical(top); if (topLine >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; return scrollPageUp(widget, buffer); } @Override protected boolean pageDown(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (bottomLine <= layout.getLineCount() - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; return scrollPageDown(widget, buffer); } @Override protected boolean top(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); if (getTopLine(widget) >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0)); return true; } return false; return scrollTop(widget, buffer); } @Override protected boolean bottom(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int lineCount = layout.getLineCount(); if (getBottomLine(widget) <= lineCount - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(lineCount) - getInnerHeight(widget)); return true; } return false; return scrollBottom(widget, buffer); } @Override protected boolean lineStart(TextView widget, Spannable buffer) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { widget.scrollTo(minScrollX, widget.getScrollY()); return true; } return false; return scrollLineStart(widget, buffer); } @Override protected boolean lineEnd(TextView widget, Spannable buffer) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { widget.scrollTo(maxScrollX, widget.getScrollY()); return true; } return false; return scrollLineEnd(widget, buffer); } @Override Loading core/java/android/widget/TextView.java +16 −0 Original line number Diff line number Diff line Loading @@ -7389,6 +7389,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return superResult; } @Override public boolean onGenericMotionEvent(MotionEvent event) { if (mMovement != null && mText instanceof Spannable && mLayout != null) { try { if (mMovement.onGenericMotionEvent(this, (Spannable) mText, event)) { return true; } } catch (AbstractMethodError ex) { // onGenericMotionEvent was added to the MovementMethod interface in API 12. // Ignore its absence in case third party applications implemented the // interface directly. } } return super.onGenericMotionEvent(event); } private void prepareCursorControllers() { boolean windowSupportsHandles = false; Loading Loading
api/current.xml +35 −1 Original line number Diff line number Diff line Loading @@ -198789,6 +198789,23 @@ <parameter name="buffer" type="android.text.Spannable"> </parameter> </method> <method name="onGenericMotionEvent" return="boolean" abstract="false" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > <parameter name="widget" type="android.widget.TextView"> </parameter> <parameter name="text" type="android.text.Spannable"> </parameter> <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> <method name="onKeyDown" return="boolean" abstract="false" Loading Loading @@ -199862,6 +199879,23 @@ <parameter name="text" type="android.text.Spannable"> </parameter> </method> <method name="onGenericMotionEvent" return="boolean" abstract="true" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > <parameter name="widget" type="android.widget.TextView"> </parameter> <parameter name="text" type="android.text.Spannable"> </parameter> <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> <method name="onKeyDown" return="boolean" abstract="true" Loading Loading @@ -266599,7 +266633,7 @@ deprecated="not deprecated" visibility="public" > <parameter name="t" type="T"> <parameter name="arg0" type="T"> </parameter> </method> </interface>
core/java/android/text/method/BaseMovementMethod.java +306 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.text.method; import android.text.Layout; import android.text.Spannable; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.widget.TextView; Loading Loading @@ -88,6 +89,39 @@ public class BaseMovementMethod implements MovementMethod { return false; } @Override public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (event.getAction()) { case MotionEvent.ACTION_SCROLL: { final float vscroll; final float hscroll; if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) { vscroll = 0; hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); } else { vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL); hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL); } boolean handled = false; if (hscroll < 0) { handled |= scrollLeft(widget, text, (int)Math.ceil(-hscroll)); } else if (hscroll > 0) { handled |= scrollRight(widget, text, (int)Math.ceil(hscroll)); } if (vscroll < 0) { handled |= scrollUp(widget, text, (int)Math.ceil(-vscroll)); } else if (vscroll > 0) { handled |= scrollDown(widget, text, (int)Math.ceil(vscroll)); } return handled; } } } return false; } /** * Gets the meta state used for movement using the modifiers tracked by the text * buffer as well as those present in the key event. Loading Loading @@ -342,4 +376,276 @@ public class BaseMovementMethod implements MovementMethod { protected boolean end(TextView widget, Spannable buffer) { return false; } private int getTopLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY()); } private int getBottomLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget)); } private int getInnerWidth(TextView widget) { return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight(); } private int getInnerHeight(TextView widget) { return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom(); } private int getCharacterWidth(TextView widget) { return (int) Math.ceil(widget.getPaint().getFontSpacing()); } private int getScrollBoundsLeft(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int left = Integer.MAX_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineLeft = (int) Math.floor(layout.getLineLeft(line)); if (lineLeft < left) { left = lineLeft; } } return left; } private int getScrollBoundsRight(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int right = Integer.MIN_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineRight = (int) Math.ceil(layout.getLineRight(line)); if (lineRight > right) { right = lineRight; } } return right; } /** * Performs a scroll left action. * Scrolls left by the specified number of characters. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of characters to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollLeft(TextView widget, Spannable buffer, int amount) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { scrollX = Math.max(scrollX - getCharacterWidth(widget) * amount, minScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; } /** * Performs a scroll right action. * Scrolls right by the specified number of characters. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of characters to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollRight(TextView widget, Spannable buffer, int amount) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { scrollX = Math.min(scrollX + getCharacterWidth(widget) * amount, maxScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; } /** * Performs a scroll up action. * Scrolls up by the specified number of lines. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of lines to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollUp(TextView widget, Spannable buffer, int amount) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY(); int topLine = layout.getLineForVertical(top); if (layout.getLineTop(topLine) == top) { // If the top line is partially visible, bring it all the way // into view; otherwise, bring the previous line into view. topLine -= 1; } if (topLine >= 0) { topLine = Math.max(topLine - amount + 1, 0); Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; } /** * Performs a scroll down action. * Scrolls down by the specified number of lines. * * @param widget The text view. * @param buffer The text buffer. * @param amount The number of lines to scroll by. Must be at least 1. * @return True if the event was handled. * @hide */ protected boolean scrollDown(TextView widget, Spannable buffer, int amount) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (layout.getLineTop(bottomLine + 1) < bottom + 1) { // Less than a pixel of this line is out of view, // so we must have tried to make it entirely in view // and now want the next line to be in view instead. bottomLine += 1; } final int limit = layout.getLineCount() - 1; if (bottomLine <= limit) { bottomLine = Math.min(bottomLine + amount - 1, limit); Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; } /** * Performs a scroll page up action. * Scrolls up by one page. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollPageUp(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY() - getInnerHeight(widget); int topLine = layout.getLineForVertical(top); if (topLine >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; } /** * Performs a scroll page up action. * Scrolls down by one page. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollPageDown(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (bottomLine <= layout.getLineCount() - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; } /** * Performs a scroll to top action. * Scrolls to the top of the document. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollTop(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); if (getTopLine(widget) >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0)); return true; } return false; } /** * Performs a scroll to bottom action. * Scrolls to the bottom of the document. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollBottom(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int lineCount = layout.getLineCount(); if (getBottomLine(widget) <= lineCount - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(lineCount) - getInnerHeight(widget)); return true; } return false; } /** * Performs a scroll to line start action. * Scrolls to the start of the line. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollLineStart(TextView widget, Spannable buffer) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { widget.scrollTo(minScrollX, widget.getScrollY()); return true; } return false; } /** * Performs a scroll to line end action. * Scrolls to the end of the line. * * @param widget The text view. * @param buffer The text buffer. * @return True if the event was handled. * @hide */ protected boolean scrollLineEnd(TextView widget, Spannable buffer) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { widget.scrollTo(maxScrollX, widget.getScrollY()); return true; } return false; } }
core/java/android/text/method/MovementMethod.java +1 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ public interface MovementMethod { public void onTakeFocus(TextView widget, Spannable text, int direction); public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event); public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event); public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event); /** * Returns true if this movement method allows arbitrary selection Loading
core/java/android/text/method/ScrollingMovementMethod.java +10 −145 Original line number Diff line number Diff line Loading @@ -25,189 +25,54 @@ import android.view.View; * A movement method that interprets movement keys by scrolling the text buffer. */ public class ScrollingMovementMethod extends BaseMovementMethod implements MovementMethod { private int getTopLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY()); } private int getBottomLine(TextView widget) { return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget)); } private int getInnerWidth(TextView widget) { return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight(); } private int getInnerHeight(TextView widget) { return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom(); } private int getCharacterWidth(TextView widget) { return (int) Math.ceil(widget.getPaint().getFontSpacing()); } private int getScrollBoundsLeft(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int left = Integer.MAX_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineLeft = (int) Math.floor(layout.getLineLeft(line)); if (lineLeft < left) { left = lineLeft; } } return left; } private int getScrollBoundsRight(TextView widget) { final Layout layout = widget.getLayout(); final int topLine = getTopLine(widget); final int bottomLine = getBottomLine(widget); if (topLine > bottomLine) { return 0; } int right = Integer.MIN_VALUE; for (int line = topLine; line <= bottomLine; line++) { final int lineRight = (int) Math.ceil(layout.getLineRight(line)); if (lineRight > right) { right = lineRight; } } return right; } @Override protected boolean left(TextView widget, Spannable buffer) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { scrollX = Math.max(scrollX - getCharacterWidth(widget), minScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; return scrollLeft(widget, buffer, 1); } @Override protected boolean right(TextView widget, Spannable buffer) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { scrollX = Math.min(scrollX + getCharacterWidth(widget), maxScrollX); widget.scrollTo(scrollX, widget.getScrollY()); return true; } return false; return scrollRight(widget, buffer, 1); } @Override protected boolean up(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY(); int topLine = layout.getLineForVertical(top); if (layout.getLineTop(topLine) == top) { // If the top line is partially visible, bring it all the way // into view; otherwise, bring the previous line into view. topLine -= 1; } if (topLine >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; return scrollUp(widget, buffer, 1); } @Override protected boolean down(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (layout.getLineTop(bottomLine + 1) < bottom + 1) { // Less than a pixel of this line is out of view, // so we must have tried to make it entirely in view // and now want the next line to be in view instead. bottomLine += 1; } if (bottomLine <= layout.getLineCount() - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; return scrollDown(widget, buffer, 1); } @Override protected boolean pageUp(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int top = widget.getScrollY() - getInnerHeight(widget); int topLine = layout.getLineForVertical(top); if (topLine >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine)); return true; } return false; return scrollPageUp(widget, buffer); } @Override protected boolean pageDown(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int innerHeight = getInnerHeight(widget); final int bottom = widget.getScrollY() + innerHeight + innerHeight; int bottomLine = layout.getLineForVertical(bottom); if (bottomLine <= layout.getLineCount() - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(bottomLine + 1) - innerHeight); return true; } return false; return scrollPageDown(widget, buffer); } @Override protected boolean top(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); if (getTopLine(widget) >= 0) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0)); return true; } return false; return scrollTop(widget, buffer); } @Override protected boolean bottom(TextView widget, Spannable buffer) { final Layout layout = widget.getLayout(); final int lineCount = layout.getLineCount(); if (getBottomLine(widget) <= lineCount - 1) { Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(lineCount) - getInnerHeight(widget)); return true; } return false; return scrollBottom(widget, buffer); } @Override protected boolean lineStart(TextView widget, Spannable buffer) { final int minScrollX = getScrollBoundsLeft(widget); int scrollX = widget.getScrollX(); if (scrollX > minScrollX) { widget.scrollTo(minScrollX, widget.getScrollY()); return true; } return false; return scrollLineStart(widget, buffer); } @Override protected boolean lineEnd(TextView widget, Spannable buffer) { final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget); int scrollX = widget.getScrollX(); if (scrollX < maxScrollX) { widget.scrollTo(maxScrollX, widget.getScrollY()); return true; } return false; return scrollLineEnd(widget, buffer); } @Override Loading
core/java/android/widget/TextView.java +16 −0 Original line number Diff line number Diff line Loading @@ -7389,6 +7389,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return superResult; } @Override public boolean onGenericMotionEvent(MotionEvent event) { if (mMovement != null && mText instanceof Spannable && mLayout != null) { try { if (mMovement.onGenericMotionEvent(this, (Spannable) mText, event)) { return true; } } catch (AbstractMethodError ex) { // onGenericMotionEvent was added to the MovementMethod interface in API 12. // Ignore its absence in case third party applications implemented the // interface directly. } } return super.onGenericMotionEvent(event); } private void prepareCursorControllers() { boolean windowSupportsHandles = false; Loading