Home | History | Annotate | Download | only in format
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.contacts.format;
     17 
     18 import com.android.contacts.test.NeededForTesting;
     19 
     20 import android.database.CharArrayBuffer;
     21 import android.graphics.Typeface;
     22 import android.text.SpannableString;
     23 import android.text.style.StyleSpan;
     24 
     25 import java.util.Arrays;
     26 
     27 /**
     28  * Assorted utility methods related to text formatting in Contacts.
     29  */
     30 public class FormatUtils {
     31     private static final char LEFT_TO_RIGHT_EMBEDDING = '\u202A';
     32     private static final char POP_DIRECTIONAL_FORMATTING = '\u202C';
     33 
     34     /**
     35      * Finds the earliest point in buffer1 at which the first part of buffer2 matches.  For example,
     36      * overlapPoint("abcd", "cdef") == 2.
     37      */
     38     public static int overlapPoint(CharArrayBuffer buffer1, CharArrayBuffer buffer2) {
     39         if (buffer1 == null || buffer2 == null) {
     40             return -1;
     41         }
     42         return overlapPoint(Arrays.copyOfRange(buffer1.data, 0, buffer1.sizeCopied),
     43                 Arrays.copyOfRange(buffer2.data, 0, buffer2.sizeCopied));
     44     }
     45 
     46     /**
     47      * Finds the earliest point in string1 at which the first part of string2 matches.  For example,
     48      * overlapPoint("abcd", "cdef") == 2.
     49      */
     50     @NeededForTesting  // App itself doesn't use this right now, but we don't want to remove it.
     51     public static int overlapPoint(String string1, String string2) {
     52         if (string1 == null || string2 == null) {
     53             return -1;
     54         }
     55         return overlapPoint(string1.toCharArray(), string2.toCharArray());
     56     }
     57 
     58     /**
     59      * Finds the earliest point in array1 at which the first part of array2 matches.  For example,
     60      * overlapPoint("abcd", "cdef") == 2.
     61      */
     62     public static int overlapPoint(char[] array1, char[] array2) {
     63         if (array1 == null || array2 == null) {
     64             return -1;
     65         }
     66         int count1 = array1.length;
     67         int count2 = array2.length;
     68 
     69         // Ignore matching tails of the two arrays.
     70         while (count1 > 0 && count2 > 0 && array1[count1 - 1] == array2[count2 - 1]) {
     71             count1--;
     72             count2--;
     73         }
     74 
     75         int size = count2;
     76         for (int i = 0; i < count1; i++) {
     77             if (i + size > count1) {
     78                 size = count1 - i;
     79             }
     80             int j;
     81             for (j = 0; j < size; j++) {
     82                 if (array1[i+j] != array2[j]) {
     83                     break;
     84                 }
     85             }
     86             if (j == size) {
     87                 return i;
     88             }
     89         }
     90 
     91         return -1;
     92     }
     93 
     94     /**
     95      * Applies the given style to a range of the input CharSequence.
     96      * @param style The style to apply (see the style constants in {@link Typeface}).
     97      * @param input The CharSequence to style.
     98      * @param start Starting index of the range to style (will be clamped to be a minimum of 0).
     99      * @param end Ending index of the range to style (will be clamped to a maximum of the input
    100      *     length).
    101      * @param flags Bitmask for configuring behavior of the span.  See {@link android.text.Spanned}.
    102      * @return The styled CharSequence.
    103      */
    104     public static CharSequence applyStyleToSpan(int style, CharSequence input, int start, int end,
    105             int flags) {
    106         // Enforce bounds of the char sequence.
    107         start = Math.max(0, start);
    108         end = Math.min(input.length(), end);
    109         SpannableString text = new SpannableString(input);
    110         text.setSpan(new StyleSpan(style), start, end, flags);
    111         return text;
    112     }
    113 
    114     @NeededForTesting
    115     public static void copyToCharArrayBuffer(String text, CharArrayBuffer buffer) {
    116         if (text != null) {
    117             char[] data = buffer.data;
    118             if (data == null || data.length < text.length()) {
    119                 buffer.data = text.toCharArray();
    120             } else {
    121                 text.getChars(0, text.length(), data, 0);
    122             }
    123             buffer.sizeCopied = text.length();
    124         } else {
    125             buffer.sizeCopied = 0;
    126         }
    127     }
    128 
    129     /** Returns a String that represents the content of the given {@link CharArrayBuffer}. */
    130     @NeededForTesting
    131     public static String charArrayBufferToString(CharArrayBuffer buffer) {
    132         return new String(buffer.data, 0, buffer.sizeCopied);
    133     }
    134 
    135     /**
    136      * Finds the index of the first word that starts with the given prefix.
    137      * <p>
    138      * If not found, returns -1.
    139      *
    140      * @param text the text in which to search for the prefix
    141      * @param prefix the text to find, in upper case letters
    142      */
    143     public static int indexOfWordPrefix(CharSequence text, char[] prefix) {
    144         if (prefix == null || text == null) {
    145             return -1;
    146         }
    147 
    148         int textLength = text.length();
    149         int prefixLength = prefix.length;
    150 
    151         if (prefixLength == 0 || textLength < prefixLength) {
    152             return -1;
    153         }
    154 
    155         int i = 0;
    156         while (i < textLength) {
    157             // Skip non-word characters
    158             while (i < textLength && !Character.isLetterOrDigit(text.charAt(i))) {
    159                 i++;
    160             }
    161 
    162             if (i + prefixLength > textLength) {
    163                 return -1;
    164             }
    165 
    166             // Compare the prefixes
    167             int j;
    168             for (j = 0; j < prefixLength; j++) {
    169                 if (Character.toUpperCase(text.charAt(i + j)) != prefix[j]) {
    170                     break;
    171                 }
    172             }
    173             if (j == prefixLength) {
    174                 return i;
    175             }
    176 
    177             // Skip this word
    178             while (i < textLength && Character.isLetterOrDigit(text.charAt(i))) {
    179                 i++;
    180             }
    181         }
    182 
    183         return -1;
    184     }
    185 
    186     /** Returns the given text, forced to be left-to-right. */
    187     public static CharSequence forceLeftToRight(CharSequence text) {
    188         StringBuilder sb = new StringBuilder();
    189         sb.append(LEFT_TO_RIGHT_EMBEDDING);
    190         sb.append(text);
    191         sb.append(POP_DIRECTIONAL_FORMATTING);
    192         return sb.toString();
    193     }
    194 }
    195