Merge changes from topic "truncate operator name" am: ffa0f982b6 am: 9cf73e369d am: eb897b1d85
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2004810 Change-Id: Ie1a67a1a9fae4dbbc321755f7ec9bde8bb84613f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
8827b92855
@ -350,6 +350,53 @@ public class TextUtils {
|
|||||||
return ret;
|
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.
|
* 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.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -781,6 +782,81 @@ public class TextUtilsTest {
|
|||||||
TextUtils.trimToSize("abc", 0);
|
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
|
@Test
|
||||||
public void length() {
|
public void length() {
|
||||||
assertEquals(0, TextUtils.length(null));
|
assertEquals(0, TextUtils.length(null));
|
||||||
|
@ -11768,7 +11768,25 @@ public class TelephonyManager {
|
|||||||
if (SubscriptionManager.isValidPhoneId(phoneId)) {
|
if (SubscriptionManager.isValidPhoneId(phoneId)) {
|
||||||
List<String> newList = updateTelephonyProperty(
|
List<String> newList = updateTelephonyProperty(
|
||||||
TelephonyProperties.operator_alpha(), phoneId, name);
|
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