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.common.format;
     17 
     18 import android.database.CharArrayBuffer;
     19 import android.graphics.Typeface;
     20 import android.text.SpannableString;
     21 import android.text.style.StyleSpan;
     22 
     23 import com.google.common.annotations.VisibleForTesting;
     24 
     25 import java.util.Arrays;
     26 
     27 /**
     28  * Assorted utility methods related to text formatting in Contacts.
     29  */
     30 public class FormatUtils {
     31 
     32     /**
     33      * Finds the earliest point in buffer1 at which the first part of buffer2 matches.  For example,
     34      * overlapPoint("abcd", "cdef") == 2.
     35      */
     36     public static int overlapPoint(CharArrayBuffer buffer1, CharArrayBuffer buffer2) {
     37         if (buffer1 == null || buffer2 == null) {
     38             return -1;
     39         }
     40         return overlapPoint(Arrays.copyOfRange(buffer1.data, 0, buffer1.sizeCopied),
     41                 Arrays.copyOfRange(buffer2.data, 0, buffer2.sizeCopied));
     42     }
     43 
     44     /**
     45      * Finds the earliest point in string1 at which the first part of string2 matches.  For example,
     46      * overlapPoint("abcd", "cdef") == 2.
     47      */
     48     @VisibleForTesting
     49     public static int overlapPoint(String string1, String string2) {
     50         if (string1 == null || string2 == null) {
     51             return -1;
     52         }
     53         return overlapPoint(string1.toCharArray(), string2.toCharArray());
     54     }
     55 
     56     /**
     57      * Finds the earliest point in array1 at which the first part of array2 matches.  For example,
     58      * overlapPoint("abcd", "cdef") == 2.
     59      */
     60     public static int overlapPoint(char[] array1, char[] array2) {
     61         if (array1 == null || array2 == null) {
     62             return -1;
     63         }
     64         int count1 = array1.length;
     65         int count2 = array2.length;
     66 
     67         // Ignore matching tails of the two arrays.
     68         while (count1 > 0 && count2 > 0 && array1[count1 - 1] == array2[count2 - 1]) {
     69             count1--;
     70             count2--;
     71         }
     72 
     73         int size = count2;
     74         for (int i = 0; i < count1; i++) {
     75             if (i + size > count1) {
     76                 size = count1 - i;
     77             }
     78             int j;
     79             for (j = 0; j < size; j++) {
     80                 if (array1[i+j] != array2[j]) {
     81                     break;
     82                 }
     83             }
     84             if (j == size) {
     85                 return i;
     86             }
     87         }
     88 
     89         return -1;
     90     }
     91 
     92     /**
     93      * Applies the given style to a range of the input CharSequence.
     94      * @param style The style to apply (see the style constants in {@link Typeface}).
     95      * @param input The CharSequence to style.
     96      * @param start Starting index of the range to style (will be clamped to be a minimum of 0).
     97      * @param end Ending index of the range to style (will be clamped to a maximum of the input
     98      *     length).
     99      * @param flags Bitmask for configuring behavior of the span.  See {@link android.text.Spanned}.
    100      * @return The styled CharSequence.
    101      */
    102     public static CharSequence applyStyleToSpan(int style, CharSequence input, int start, int end,
    103             int flags) {
    104         // Enforce bounds of the char sequence.
    105         start = Math.max(0, start);
    106         end = Math.min(input.length(), end);
    107         SpannableString text = new SpannableString(input);
    108         text.setSpan(new StyleSpan(style), start, end, flags);
    109         return text;
    110     }
    111 
    112     @VisibleForTesting
    113     public static void copyToCharArrayBuffer(String text, CharArrayBuffer buffer) {
    114         if (text != null) {
    115             char[] data = buffer.data;
    116             if (data == null || data.length < text.length()) {
    117                 buffer.data = text.toCharArray();
    118             } else {
    119                 text.getChars(0, text.length(), data, 0);
    120             }
    121             buffer.sizeCopied = text.length();
    122         } else {
    123             buffer.sizeCopied = 0;
    124         }
    125     }
    126 
    127     /** Returns a String that represents the content of the given {@link CharArrayBuffer}. */
    128     @VisibleForTesting
    129     public static String charArrayBufferToString(CharArrayBuffer buffer) {
    130         return new String(buffer.data, 0, buffer.sizeCopied);
    131     }
    132 
    133     /**
    134      * Finds the index of the first word that starts with the given prefix.
    135      * <p>
    136      * If not found, returns -1.
    137      *
    138      * @param text the text in which to search for the prefix
    139      * @param prefix the text to find, in upper case letters
    140      */
    141     public static int indexOfWordPrefix(CharSequence text, String prefix) {
    142         if (prefix == null || text == null) {
    143             return -1;
    144         }
    145 
    146         int textLength = text.length();
    147         int prefixLength = prefix.length();
    148 
    149         if (prefixLength == 0 || textLength < prefixLength) {
    150             return -1;
    151         }
    152 
    153         int i = 0;
    154         while (i < textLength) {
    155             // Skip non-word characters
    156             while (i < textLength && !Character.isLetterOrDigit(text.charAt(i))) {
    157                 i++;
    158             }
    159 
    160             if (i + prefixLength > textLength) {
    161                 return -1;
    162             }
    163 
    164             // Compare the prefixes
    165             int j;
    166             for (j = 0; j < prefixLength; j++) {
    167                 if (Character.toUpperCase(text.charAt(i + j)) != prefix.charAt(j)) {
    168                     break;
    169                 }
    170             }
    171             if (j == prefixLength) {
    172                 return i;
    173             }
    174 
    175             // Skip this word
    176             while (i < textLength && Character.isLetterOrDigit(text.charAt(i))) {
    177                 i++;
    178             }
    179         }
    180 
    181         return -1;
    182     }
    183 
    184 }
    185