/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.widget; import android.graphics.Rect; import android.text.Layout; import android.text.Spannable; import android.view.AccessibilityIterators.AbstractTextSegmentIterator; /** * This class contains the implementation of text segment iterators * for accessibility support. */ final class AccessibilityIterators { static class LineTextSegmentIterator extends AbstractTextSegmentIterator { private static LineTextSegmentIterator sLineInstance; protected static final int DIRECTION_START = -1; protected static final int DIRECTION_END = 1; protected Layout mLayout; public static LineTextSegmentIterator getInstance() { if (sLineInstance == null) { sLineInstance = new LineTextSegmentIterator(); } return sLineInstance; } public void initialize(Spannable text, Layout layout) { mText = text.toString(); mLayout = layout; } @Override public int[] following(int offset) { final int textLegth = mText.length(); if (textLegth <= 0) { return null; } if (offset >= mText.length()) { return null; } int nextLine; if (offset < 0) { nextLine = mLayout.getLineForOffset(0); } else { final int currentLine = mLayout.getLineForOffset(offset); if (getLineEdgeIndex(currentLine, DIRECTION_START) == offset) { nextLine = currentLine; } else { nextLine = currentLine + 1; } } if (nextLine >= mLayout.getLineCount()) { return null; } final int start = getLineEdgeIndex(nextLine, DIRECTION_START); final int end = getLineEdgeIndex(nextLine, DIRECTION_END) + 1; return getRange(start, end); } @Override public int[] preceding(int offset) { final int textLegth = mText.length(); if (textLegth <= 0) { return null; } if (offset <= 0) { return null; } int previousLine; if (offset > mText.length()) { previousLine = mLayout.getLineForOffset(mText.length()); } else { final int currentLine = mLayout.getLineForOffset(offset); if (getLineEdgeIndex(currentLine, DIRECTION_END) + 1 == offset) { previousLine = currentLine; } else { previousLine = currentLine - 1; } } if (previousLine < 0) { return null; } final int start = getLineEdgeIndex(previousLine, DIRECTION_START); final int end = getLineEdgeIndex(previousLine, DIRECTION_END) + 1; return getRange(start, end); } protected int getLineEdgeIndex(int lineNumber, int direction) { final int paragraphDirection = mLayout.getParagraphDirection(lineNumber); if (direction * paragraphDirection < 0) { return mLayout.getLineStart(lineNumber); } else { return mLayout.getLineEnd(lineNumber) - 1; } } } static class PageTextSegmentIterator extends LineTextSegmentIterator { private static PageTextSegmentIterator sPageInstance; private TextView mView; private final Rect mTempRect = new Rect(); public static PageTextSegmentIterator getInstance() { if (sPageInstance == null) { sPageInstance = new PageTextSegmentIterator(); } return sPageInstance; } public void initialize(TextView view) { super.initialize((Spannable) view.getIterableTextForAccessibility(), view.getLayout()); mView = view; } @Override public int[] following(int offset) { final int textLegth = mText.length(); if (textLegth <= 0) { return null; } if (offset >= mText.length()) { return null; } if (!mView.getGlobalVisibleRect(mTempRect)) { return null; } final int start = Math.max(0, offset); final int currentLine = mLayout.getLineForOffset(start); final int currentLineTop = mLayout.getLineTop(currentLine); final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop() - mView.getTotalPaddingBottom(); final int nextPageStartY = currentLineTop + pageHeight; final int lastLineTop = mLayout.getLineTop(mLayout.getLineCount() - 1); final int currentPageEndLine = (nextPageStartY < lastLineTop) ? mLayout.getLineForVertical(nextPageStartY) - 1 : mLayout.getLineCount() - 1; final int end = getLineEdgeIndex(currentPageEndLine, DIRECTION_END) + 1; return getRange(start, end); } @Override public int[] preceding(int offset) { final int textLegth = mText.length(); if (textLegth <= 0) { return null; } if (offset <= 0) { return null; } if (!mView.getGlobalVisibleRect(mTempRect)) { return null; } final int end = Math.min(mText.length(), offset); final int currentLine = mLayout.getLineForOffset(end); final int currentLineTop = mLayout.getLineTop(currentLine); final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop() - mView.getTotalPaddingBottom(); final int previousPageEndY = currentLineTop - pageHeight; final int currentPageStartLine = (previousPageEndY > 0) ? mLayout.getLineForVertical(previousPageEndY) + 1 : 0; final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START); return getRange(start, end); } } }