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