TextDirectionHeuristics.java revision e442662330c972aa96986e6f09305be836b6a7f4
14b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio/*
24b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * Copyright (C) 2011 The Android Open Source Project
34b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio *
44b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License");
54b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * you may not use this file except in compliance with the License.
64b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * You may obtain a copy of the License at
74b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio *
84b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio *      http://www.apache.org/licenses/LICENSE-2.0
94b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio *
104b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * Unless required by applicable law or agreed to in writing, software
114b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS,
124b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * See the License for the specific language governing permissions and
144b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio * limitations under the License.
154b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio */
16cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
17cb379120456d8065d742021fc5c66748fc8a11a8Doug Feltpackage android.text;
18cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
19cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
203fb824bae3322252a68c1cf8537280a5d2bd356dFabrice Di Meglioimport android.view.View;
217810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio
2257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglioimport java.nio.CharBuffer;
2357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio
24cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt/**
25e442662330c972aa96986e6f09305be836b6a7f4Scott Main * Some objects that implement {@link TextDirectionHeuristic}. Use these with
26e442662330c972aa96986e6f09305be836b6a7f4Scott Main * the {@link BidiFormatter#unicodeWrap unicodeWrap()} methods in {@link BidiFormatter}.
27e442662330c972aa96986e6f09305be836b6a7f4Scott Main * Also notice that these direction heuristics correspond to the same types of constants
28e442662330c972aa96986e6f09305be836b6a7f4Scott Main * provided in the {@link android.view.View} class for {@link android.view.View#setTextDirection
29e442662330c972aa96986e6f09305be836b6a7f4Scott Main * setTextDirection()}, such as {@link android.view.View#TEXT_DIRECTION_RTL}.
30e442662330c972aa96986e6f09305be836b6a7f4Scott Main * <p>To support versions lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
31e442662330c972aa96986e6f09305be836b6a7f4Scott Main * you can use the support library's {@link android.support.v4.text.TextDirectionHeuristicsCompat}
32e442662330c972aa96986e6f09305be836b6a7f4Scott Main * class.
33cefb4bc011fe47ec83b2fd9ec4da28bdf806c0cdGilles Debunne *
34cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */
35cb379120456d8065d742021fc5c66748fc8a11a8Doug Feltpublic class TextDirectionHeuristics {
36cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
3757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    /**
3857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * Always decides that the direction is left to right.
3957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     */
40cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public static final TextDirectionHeuristic LTR =
41cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        new TextDirectionHeuristicInternal(null /* no algorithm */, false);
42cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
4357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    /**
4457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * Always decides that the direction is right to left.
4557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     */
46cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public static final TextDirectionHeuristic RTL =
47cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        new TextDirectionHeuristicInternal(null /* no algorithm */, true);
48cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
49cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
5057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * Determines the direction based on the first strong directional character, including bidi
5157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * format chars, falling back to left to right if it finds none. This is the default behavior
5257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * of the Unicode Bidirectional Algorithm.
53cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
54cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public static final TextDirectionHeuristic FIRSTSTRONG_LTR =
55cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, false);
56cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
57cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
5857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * Determines the direction based on the first strong directional character, including bidi
5957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * format chars, falling back to right to left if it finds none. This is similar to the default
6057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * behavior of the Unicode Bidirectional Algorithm, just with different fallback behavior.
61cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
62cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public static final TextDirectionHeuristic FIRSTSTRONG_RTL =
63cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, true);
64cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
65cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
6657a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * If the text contains any strong right to left non-format character, determines that the
6757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * direction is right to left, falling back to left to right if it finds none.
684b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio     */
694b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio    public static final TextDirectionHeuristic ANYRTL_LTR =
704b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio        new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, false);
714b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio
724b60c30838fbd635964f1e79c057de5048dcc66fFabrice Di Meglio    /**
737810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio     * Force the paragraph direction to the Locale direction. Falls back to left to right.
747810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio     */
757810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio    public static final TextDirectionHeuristic LOCALE = TextDirectionHeuristicLocale.INSTANCE;
767810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio
7757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    /**
7857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * State constants for taking care about true / false / unknown
7957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     */
8057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    private static final int STATE_TRUE = 0;
8157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    private static final int STATE_FALSE = 1;
8257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    private static final int STATE_UNKNOWN = 2;
8357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio
8457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    private static int isRtlText(int directionality) {
8557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        switch (directionality) {
8657a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
8757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return STATE_FALSE;
8857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
8957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
9057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return STATE_TRUE;
9157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            default:
9257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return STATE_UNKNOWN;
9357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        }
9457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    }
9557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio
9657a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio    private static int isRtlTextOrFormat(int directionality) {
9757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        switch (directionality) {
9857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
9957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
10057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
10157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return STATE_FALSE;
10257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
10357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
10457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
10557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
10657a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return STATE_TRUE;
10757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            default:
10857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return STATE_UNKNOWN;
10957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        }
110cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
111cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
112cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
113cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * Computes the text direction based on an algorithm.  Subclasses implement
114cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * {@link #defaultIsRtl} to handle cases where the algorithm cannot determine the
115cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * direction from the text alone.
116cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
117e7beae3f4c9c170c7c6c42cf9b572f0ee1ec9c81Fabrice Di Meglio    private static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
118cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        private final TextDirectionAlgorithm mAlgorithm;
119cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
120cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
121cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            mAlgorithm = algorithm;
122cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
123cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
124cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        /**
125cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt         * Return true if the default text direction is rtl.
126cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt         */
127cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        abstract protected boolean defaultIsRtl();
128cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
129cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        @Override
13057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        public boolean isRtl(char[] array, int start, int count) {
13157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            return isRtl(CharBuffer.wrap(array), start, count);
13257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        }
13357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio
13457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        @Override
13557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        public boolean isRtl(CharSequence cs, int start, int count) {
13657a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            if (cs == null || start < 0 || count < 0 || cs.length() - count < start) {
137cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                throw new IllegalArgumentException();
138cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
139cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            if (mAlgorithm == null) {
140cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                return defaultIsRtl();
141cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
14257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            return doCheck(cs, start, count);
143cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
144cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
14557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        private boolean doCheck(CharSequence cs, int start, int count) {
14657a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            switch(mAlgorithm.checkRtl(cs, start, count)) {
14757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                case STATE_TRUE:
148cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                    return true;
14957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                case STATE_FALSE:
150cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                    return false;
151cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                default:
152cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                    return defaultIsRtl();
153cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
154cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
155cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
156cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
157cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    private static class TextDirectionHeuristicInternal extends TextDirectionHeuristicImpl {
158cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        private final boolean mDefaultIsRtl;
159cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
160cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        private TextDirectionHeuristicInternal(TextDirectionAlgorithm algorithm,
161cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                boolean defaultIsRtl) {
162cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            super(algorithm);
163cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            mDefaultIsRtl = defaultIsRtl;
164cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
165cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
166cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        @Override
167cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        protected boolean defaultIsRtl() {
168cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            return mDefaultIsRtl;
169cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
170cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
171cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
172cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
173cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * Interface for an algorithm to guess the direction of a paragraph of text.
174cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
175e7beae3f4c9c170c7c6c42cf9b572f0ee1ec9c81Fabrice Di Meglio    private static interface TextDirectionAlgorithm {
176cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        /**
177cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt         * Returns whether the range of text is RTL according to the algorithm.
178cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt         */
17957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        int checkRtl(CharSequence cs, int start, int count);
180cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
181cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
182cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
18357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * Algorithm that uses the first strong directional character to determine the paragraph
18457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio     * direction. This is the standard Unicode Bidirectional algorithm.
185cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
186e7beae3f4c9c170c7c6c42cf9b572f0ee1ec9c81Fabrice Di Meglio    private static class FirstStrong implements TextDirectionAlgorithm {
187cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        @Override
18857a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        public int checkRtl(CharSequence cs, int start, int count) {
18957a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            int result = STATE_UNKNOWN;
19057a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            for (int i = start, e = start + count; i < e && result == STATE_UNKNOWN; ++i) {
19157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                result = isRtlTextOrFormat(Character.getDirectionality(cs.charAt(i)));
192cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
193cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            return result;
194cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
195cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
196cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        private FirstStrong() {
197cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
198cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
199cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        public static final FirstStrong INSTANCE = new FirstStrong();
200cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
201cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
202cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
203cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * Algorithm that uses the presence of any strong directional non-format
204cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
205cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * direction of text.
206cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
207e7beae3f4c9c170c7c6c42cf9b572f0ee1ec9c81Fabrice Di Meglio    private static class AnyStrong implements TextDirectionAlgorithm {
208cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        private final boolean mLookForRtl;
209cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
210cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        @Override
21157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio        public int checkRtl(CharSequence cs, int start, int count) {
212cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean haveUnlookedFor = false;
213cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            for (int i = start, e = start + count; i < e; ++i) {
21457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                switch (isRtlText(Character.getDirectionality(cs.charAt(i)))) {
21557a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                    case STATE_TRUE:
216cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        if (mLookForRtl) {
21757a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                            return STATE_TRUE;
218cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        }
219cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        haveUnlookedFor = true;
220cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        break;
22157a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                    case STATE_FALSE:
222cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        if (!mLookForRtl) {
22357a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                            return STATE_FALSE;
224cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        }
225cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        haveUnlookedFor = true;
226cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        break;
227cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                    default:
228cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        break;
229cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                }
230cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
231cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            if (haveUnlookedFor) {
23257a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio                return mLookForRtl ? STATE_FALSE : STATE_TRUE;
233cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
23457a85740d721caf8dcd94a545b2dd920e8e84e01Fabrice Di Meglio            return STATE_UNKNOWN;
235cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
236cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
237cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        private AnyStrong(boolean lookForRtl) {
238cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            this.mLookForRtl = lookForRtl;
239cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        }
240cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
241cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        public static final AnyStrong INSTANCE_RTL = new AnyStrong(true);
242cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        public static final AnyStrong INSTANCE_LTR = new AnyStrong(false);
243cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
244cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
245cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
2467810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio     * Algorithm that uses the Locale direction to force the direction of a paragraph.
2477810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio     */
248e7beae3f4c9c170c7c6c42cf9b572f0ee1ec9c81Fabrice Di Meglio    private static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl {
2497810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio
2507810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio        public TextDirectionHeuristicLocale() {
2517810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio            super(null);
2527810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio        }
2537810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio
2547810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio        @Override
2557810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio        protected boolean defaultIsRtl() {
256d3d9f3f1004dfee2649a26cfe8dba948cd364904Fabrice Di Meglio            final int dir = TextUtils.getLayoutDirectionFromLocale(java.util.Locale.getDefault());
2573fb824bae3322252a68c1cf8537280a5d2bd356dFabrice Di Meglio            return (dir == View.LAYOUT_DIRECTION_RTL);
2587810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio        }
2597810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio
2607810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio        public static final TextDirectionHeuristicLocale INSTANCE =
2617810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio                new TextDirectionHeuristicLocale();
2627810b5f8cffb3c2c98fd0df579f4da5a9ac6cc73Fabrice Di Meglio    }
263cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt}
264