92 lines
3.5 KiB
Java
92 lines
3.5 KiB
Java
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License
|
|
*/
|
|
|
|
package com.android.dialer.i18n;
|
|
|
|
import android.support.annotation.Nullable;
|
|
import android.telephony.PhoneNumberUtils;
|
|
import android.text.SpannableStringBuilder;
|
|
import android.text.SpannedString;
|
|
import android.text.TextUtils;
|
|
import android.util.Patterns;
|
|
import java.util.regex.Matcher;
|
|
|
|
/** A formatter that applies bidirectional formatting to phone numbers in text. */
|
|
public final class DialerBidiFormatter {
|
|
|
|
/** Unicode "Left-To-Right Embedding" (LRE) character. */
|
|
private static final char LRE = '\u202A';
|
|
|
|
/** Unicode "Pop Directional Formatting" (PDF) character. */
|
|
private static final char PDF = '\u202C';
|
|
|
|
private DialerBidiFormatter() {}
|
|
|
|
/**
|
|
* Divides the given text into segments, applies LTR formatting and adds TTS span to segments that
|
|
* are phone numbers, then reassembles the text.
|
|
*
|
|
* <p>Formatted phone numbers usually contain one or more whitespaces (e.g., "+1 650-253-0000",
|
|
* "(650) 253-0000", etc). The system mistakes such a number for tokens separated by whitespaces.
|
|
* Therefore, these numbers can't be correctly shown in a RTL context (e.g., "+1 650-253-0000"
|
|
* would be shown as "650-253-0000 1+".)
|
|
*
|
|
* <p>This method wraps phone numbers with Unicode formatting characters LRE & PDF to ensure phone
|
|
* numbers are always shown as LTR strings.
|
|
*
|
|
* <p>Note that the regex used to find phone numbers ({@link Patterns#PHONE}) will also match any
|
|
* number. As this method also adds TTS span to segments that match {@link Patterns#PHONE}, extra
|
|
* actions need to be taken if you don't want a number to be read as a phone number by TalkBack.
|
|
*/
|
|
public static CharSequence format(@Nullable CharSequence text) {
|
|
if (TextUtils.isEmpty(text)) {
|
|
return text;
|
|
}
|
|
|
|
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
|
|
|
|
// Find the start index and the end index of each segment matching the phone number pattern.
|
|
Matcher matcher = Patterns.PHONE.matcher(text.toString());
|
|
|
|
int currIndex = 0;
|
|
while (matcher.find()) {
|
|
int start = matcher.start();
|
|
int end = matcher.end();
|
|
|
|
// Handle the case where the input text doesn't start with a phone number.
|
|
if (currIndex < start) {
|
|
spannableStringBuilder.append(text.subSequence(currIndex, start));
|
|
}
|
|
|
|
// For a phone number, wrap it with Unicode characters LRE & PDF so that it will always be
|
|
// shown as a LTR string.
|
|
spannableStringBuilder.append(
|
|
PhoneNumberUtils.createTtsSpannable(
|
|
TextUtils.concat(
|
|
String.valueOf(LRE), text.subSequence(start, end), String.valueOf(PDF))));
|
|
|
|
currIndex = end;
|
|
}
|
|
|
|
// Handle the case where the input doesn't end with a phone number.
|
|
if (currIndex < text.length()) {
|
|
spannableStringBuilder.append(text.subSequence(currIndex, text.length()));
|
|
}
|
|
|
|
return new SpannedString(spannableStringBuilder);
|
|
}
|
|
}
|