• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import com.google.common.annotations.VisibleForTesting;
20 
21 import android.database.CharArrayBuffer;
22 import android.graphics.Typeface;
23 import android.text.SpannableString;
24 import android.text.style.StyleSpan;
25 
26 import java.util.Arrays;
27 
28 /**
29  * Assorted utility methods related to text formatting in Contacts.
30  */
31 public class FormatUtils {
32 
33     /**
34      * Finds the earliest point in buffer1 at which the first part of buffer2 matches.  For example,
35      * overlapPoint("abcd", "cdef") == 2.
36      */
overlapPoint(CharArrayBuffer buffer1, CharArrayBuffer buffer2)37     public static int overlapPoint(CharArrayBuffer buffer1, CharArrayBuffer buffer2) {
38         if (buffer1 == null || buffer2 == null) {
39             return -1;
40         }
41         return overlapPoint(Arrays.copyOfRange(buffer1.data, 0, buffer1.sizeCopied),
42                 Arrays.copyOfRange(buffer2.data, 0, buffer2.sizeCopied));
43     }
44 
45     /**
46      * Finds the earliest point in string1 at which the first part of string2 matches.  For example,
47      * overlapPoint("abcd", "cdef") == 2.
48      */
49     @NeededForTesting  // App itself doesn't use this right now, but we don't want to remove it.
overlapPoint(String string1, String string2)50     public static int overlapPoint(String string1, String string2) {
51         if (string1 == null || string2 == null) {
52             return -1;
53         }
54         return overlapPoint(string1.toCharArray(), string2.toCharArray());
55     }
56 
57     /**
58      * Finds the earliest point in array1 at which the first part of array2 matches.  For example,
59      * overlapPoint("abcd", "cdef") == 2.
60      */
overlapPoint(char[] array1, char[] array2)61     public static int overlapPoint(char[] array1, char[] array2) {
62         if (array1 == null || array2 == null) {
63             return -1;
64         }
65         int count1 = array1.length;
66         int count2 = array2.length;
67 
68         // Ignore matching tails of the two arrays.
69         while (count1 > 0 && count2 > 0 && array1[count1 - 1] == array2[count2 - 1]) {
70             count1--;
71             count2--;
72         }
73 
74         int size = count2;
75         for (int i = 0; i < count1; i++) {
76             if (i + size > count1) {
77                 size = count1 - i;
78             }
79             int j;
80             for (j = 0; j < size; j++) {
81                 if (array1[i+j] != array2[j]) {
82                     break;
83                 }
84             }
85             if (j == size) {
86                 return i;
87             }
88         }
89 
90         return -1;
91     }
92 
93     /**
94      * Applies the given style to a range of the input CharSequence.
95      * @param style The style to apply (see the style constants in {@link Typeface}).
96      * @param input The CharSequence to style.
97      * @param start Starting index of the range to style (will be clamped to be a minimum of 0).
98      * @param end Ending index of the range to style (will be clamped to a maximum of the input
99      *     length).
100      * @param flags Bitmask for configuring behavior of the span.  See {@link android.text.Spanned}.
101      * @return The styled CharSequence.
102      */
applyStyleToSpan(int style, CharSequence input, int start, int end, int flags)103     public static CharSequence applyStyleToSpan(int style, CharSequence input, int start, int end,
104             int flags) {
105         // Enforce bounds of the char sequence.
106         start = Math.max(0, start);
107         end = Math.min(input.length(), end);
108         SpannableString text = new SpannableString(input);
109         text.setSpan(new StyleSpan(style), start, end, flags);
110         return text;
111     }
112 
113     @VisibleForTesting
copyToCharArrayBuffer(String text, CharArrayBuffer buffer)114     /*package*/ static void copyToCharArrayBuffer(String text, CharArrayBuffer buffer) {
115         if (text != null) {
116             char[] data = buffer.data;
117             if (data == null || data.length < text.length()) {
118                 buffer.data = text.toCharArray();
119             } else {
120                 text.getChars(0, text.length(), data, 0);
121             }
122             buffer.sizeCopied = text.length();
123         } else {
124             buffer.sizeCopied = 0;
125         }
126     }
127 
128     /** Returns a String that represents the content of the given {@link CharArrayBuffer}. */
charArrayBufferToString(CharArrayBuffer buffer)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      */
indexOfWordPrefix(CharSequence text, char[] prefix)141     public static int indexOfWordPrefix(CharSequence text, char[] 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[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