Merge changes from topic "truncate operator name"
* changes: Truncate operator name to fit into SystemProp size Add truncateStringForUtf8Storage()
This commit is contained in:
commit
ffa0f982b6
@ -350,6 +350,53 @@ public class TextUtils {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the longest prefix of a string for which the UTF-8 encoding fits into the given
|
||||
* number of bytes, with the additional guarantee that the string is not truncated in the middle
|
||||
* of a valid surrogate pair.
|
||||
*
|
||||
* <p>Unpaired surrogates are counted as taking 3 bytes of storage. However, a subsequent
|
||||
* attempt to actually encode a string containing unpaired surrogates is likely to be rejected
|
||||
* by the UTF-8 implementation.
|
||||
*
|
||||
* (copied from google/thirdparty)
|
||||
*
|
||||
* @param str a string
|
||||
* @param maxbytes the maximum number of UTF-8 encoded bytes
|
||||
* @return the beginning of the string, so that it uses at most maxbytes bytes in UTF-8
|
||||
* @throws IndexOutOfBoundsException if maxbytes is negative
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static String truncateStringForUtf8Storage(String str, int maxbytes) {
|
||||
if (maxbytes < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
int bytes = 0;
|
||||
for (int i = 0, len = str.length(); i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
if (c < 0x80) {
|
||||
bytes += 1;
|
||||
} else if (c < 0x800) {
|
||||
bytes += 2;
|
||||
} else if (c < Character.MIN_SURROGATE
|
||||
|| c > Character.MAX_SURROGATE
|
||||
|| str.codePointAt(i) < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
bytes += 3;
|
||||
} else {
|
||||
bytes += 4;
|
||||
i += (bytes > maxbytes) ? 0 : 1;
|
||||
}
|
||||
if (bytes > maxbytes) {
|
||||
return str.substring(0, i);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string containing the tokens joined by delimiters.
|
||||
*
|
||||
|
@ -43,6 +43,7 @@ import com.google.android.collect.Lists;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -781,6 +782,81 @@ public class TextUtilsTest {
|
||||
TextUtils.trimToSize("abc", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void truncateStringForUtf8Storage() {
|
||||
assertEquals("", TextUtils.truncateStringForUtf8Storage("abc", 0));
|
||||
|
||||
//================ long normal case ================
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
int n = 50;
|
||||
for (int i = 0; i < 2 * n; i++) {
|
||||
builder.append("哈");
|
||||
}
|
||||
String initial = builder.toString();
|
||||
String result = TextUtils.truncateStringForUtf8Storage(initial, n);
|
||||
|
||||
// Result should be the beginning of initial
|
||||
assertTrue(initial.startsWith(result));
|
||||
|
||||
// Result should take less than n bytes in UTF-8
|
||||
assertTrue(result.getBytes(StandardCharsets.UTF_8).length <= n);
|
||||
|
||||
// result + the next codePoint should take strictly more than
|
||||
// n bytes in UTF-8
|
||||
assertTrue(initial.substring(0, initial.offsetByCodePoints(result.length(), 1))
|
||||
.getBytes(StandardCharsets.UTF_8).length > n);
|
||||
|
||||
// =================== short normal case =====================
|
||||
String s = "sf\u20ACgk\u00E9ls\u00E9fg";
|
||||
result = TextUtils.truncateStringForUtf8Storage(s, 100);
|
||||
assertEquals(s, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateInMiddleOfSurrogate() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String beginning = "a";
|
||||
builder.append(beginning);
|
||||
builder.append(Character.toChars(0x1D11E));
|
||||
|
||||
String result = TextUtils.truncateStringForUtf8Storage(builder.toString(), 3);
|
||||
|
||||
// \u1D11E is a surrogate and needs 4 bytes in UTF-8. beginning == "a" uses
|
||||
// only 1 bytes in UTF8
|
||||
// As we allow only 3 bytes for the whole string, so just 2 for this
|
||||
// codePoint, there is not enough place and the string will be truncated
|
||||
// just before it
|
||||
assertEquals(beginning, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateInMiddleOfChar() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String beginning = "a";
|
||||
builder.append(beginning);
|
||||
builder.append(Character.toChars(0x20AC));
|
||||
|
||||
String result = TextUtils.truncateStringForUtf8Storage(builder.toString(), 3);
|
||||
|
||||
// Like above, \u20AC uses 3 bytes in UTF-8, with "beginning", that makes
|
||||
// 4 bytes so it is too big and should be truncated
|
||||
assertEquals(beginning, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateSubString() {
|
||||
String test = "sdgkl;hjsl;gjhdgkljdfhglkdj";
|
||||
String sub = test.substring(10, 20);
|
||||
String res = TextUtils.truncateStringForUtf8Storage(sub, 255);
|
||||
assertEquals(sub, res);
|
||||
}
|
||||
|
||||
@Test(expected = IndexOutOfBoundsException.class)
|
||||
public void truncateStringForUtf8StorageThrowsExceptionForNegativeSize() {
|
||||
TextUtils.truncateStringForUtf8Storage("abc", -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void length() {
|
||||
assertEquals(0, TextUtils.length(null));
|
||||
|
@ -11487,7 +11487,25 @@ public class TelephonyManager {
|
||||
if (SubscriptionManager.isValidPhoneId(phoneId)) {
|
||||
List<String> newList = updateTelephonyProperty(
|
||||
TelephonyProperties.operator_alpha(), phoneId, name);
|
||||
TelephonyProperties.operator_alpha(newList);
|
||||
try {
|
||||
TelephonyProperties.operator_alpha(newList);
|
||||
} catch (IllegalArgumentException e) { //property value is longer than the byte limit
|
||||
Log.e(TAG, "setNetworkOperatorNameForPhone: ", e);
|
||||
|
||||
int numberOfEntries = newList.size();
|
||||
int maxOperatorLength = //save 1 byte for joiner " , "
|
||||
(SystemProperties.PROP_VALUE_MAX - numberOfEntries) / numberOfEntries;
|
||||
|
||||
//examine and truncate every operator and retry
|
||||
for (int i = 0; i < newList.size(); i++) {
|
||||
if (newList.get(i) != null) {
|
||||
newList.set(i, TextUtils
|
||||
.truncateStringForUtf8Storage(newList.get(i), maxOperatorLength));
|
||||
}
|
||||
}
|
||||
TelephonyProperties.operator_alpha(newList);
|
||||
Log.e(TAG, "successfully truncated operator_alpha: " + newList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user