Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40346983 authored by Wenyi Wang's avatar Wenyi Wang
Browse files

Copy TTS code for backporting (1/2)

Bug: 25629359
Change-Id: Ic70bd512cfbe7bdf8af21295ee7433749b7fc458
parent 17474f47
Loading
Loading
Loading
Loading
+139 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.contacts.common.compat;

import android.os.Build;
import android.text.Spannable;
import android.text.style.TtsSpan;
import android.telephony.PhoneNumberUtils;

import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.google.i18n.phonenumbers.ShortNumberUtil;

/**
 * This class contains static utility methods extracted from PhoneNumberUtils, and the
 * methods were added in API level 23. In this way, we could enable the corresponding functionality
 * for pre-M devices. We need maintain this class and keep it synced with PhoneNumberUtils.
 * Another thing to keep in mind is that we use com.google.i18n rather than com.android.i18n in
 * here, so we need make sure the application behavior is preserved.
 */
public class PhoneNumberUtilsCompat {
    private PhoneNumberUtilsCompat() {}

    public static CharSequence createTtsSpannable(CharSequence phoneNumber) {
        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
                >= Build.VERSION_CODES.M) {
            return PhoneNumberUtils.createTtsSpannable(phoneNumber);
        } else {
            return createTtsSpannablePrivate(phoneNumber);
        }
    }

    public static TtsSpan createTtsSpan(String phoneNumber) {
        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
                >= Build.VERSION_CODES.M) {
            return PhoneNumberUtils.createTtsSpan(phoneNumber);
        } else {
            return createTtsSpanPrivate(phoneNumber);
        }
    }

    /**
     * Copied from {@link PhoneNumberUtils#createTtsSpannable}
     */
    private static CharSequence createTtsSpannablePrivate(CharSequence phoneNumber) {
        if (phoneNumber == null) {
            return null;
        }
        Spannable spannable = Spannable.Factory.getInstance().newSpannable(phoneNumber);
        addTtsSpan(spannable, 0, spannable.length());
        return spannable;
    }

    /**
     * Attach a {@link TtsSpan} to the supplied {@code Spannable} at the indicated location,
     * annotating that location as containing a phone number.
     *
     * @param s A {@code Spannable} to annotate.
     * @param start The starting character position of the phone number in {@code s}.
     * @param endExclusive The position after the ending character in the phone number {@code s}.
     */
    private static void addTtsSpan(Spannable s, int start, int endExclusive) {
        s.setSpan(createTtsSpan(s.subSequence(start, endExclusive).toString()),
                start,
                endExclusive,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    /**
     * Copied from {@link PhoneNumberUtils#createTtsSpan}
     */
    private static TtsSpan createTtsSpanPrivate(String phoneNumberString) {
        if (phoneNumberString == null) {
            return null;
        }

        // Parse the phone number
        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
        PhoneNumber phoneNumber = null;
        try {
            // Don't supply a defaultRegion so this fails for non-international numbers because
            // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
            // present
            phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
        } catch (NumberParseException ignored) {
        }

        // Build a telephone tts span
        final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
        if (phoneNumber == null) {
            // Strip separators otherwise TalkBack will be silent
            // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
            builder.setNumberParts(splitAtNonNumerics(phoneNumberString));
        } else {
            if (phoneNumber.hasCountryCode()) {
                builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
            }
            builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
        }
        return builder.build();
    }



    /**
     * Split a phone number using spaces, ignoring anything that is not a digit
     * @param number A {@code CharSequence} before splitting, e.g., "+20(123)-456#"
     * @return A {@code String} after splitting, e.g., "20 123 456".
     */
    private static String splitAtNonNumerics(CharSequence number) {
        StringBuilder sb = new StringBuilder(number.length());
        for (int i = 0; i < number.length(); i++) {
            sb.append(PhoneNumberUtils.isISODigit(number.charAt(i))
                    ? number.charAt(i)
                    : " ");
        }
        // It is very important to remove extra spaces. At time of writing, any leading or trailing
        // spaces, or any sequence of more than one space, will confuse TalkBack and cause the TTS
        // span to be non-functional!
        return sb.toString().replaceAll(" +", " ").trim();
    }

}
+4 −3
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.support.v4.content.ContextCompat;
import android.telephony.PhoneNumberUtils;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -51,6 +50,7 @@ import android.widget.TextView;
import com.android.contacts.common.ContactPresenceIconUtil;
import com.android.contacts.common.ContactStatusUtil;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.format.TextHighlighter;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.contacts.common.util.SearchUtil;
@@ -1106,7 +1106,8 @@ public class ContactListItemView extends ViewGroup
            mSnippetView.setVisibility(VISIBLE);
            if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
                // Give the text-to-speech engine a hint that it's a phone number
                mSnippetView.setContentDescription(PhoneNumberUtils.createTtsSpannable(text));
                mSnippetView.setContentDescription(
                        PhoneNumberUtilsCompat.createTtsSpannable(text));
            } else {
                mSnippetView.setContentDescription(null);
            }
@@ -1227,7 +1228,7 @@ public class ContactListItemView extends ViewGroup
            // Give the text-to-speech engine a hint that it's a phone number
            mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR);
            mNameTextView.setContentDescription(
                    PhoneNumberUtils.createTtsSpannable(name.toString()));
                    PhoneNumberUtilsCompat.createTtsSpannable(name.toString()));
        } else {
            mNameTextView.setContentDescription(null);
        }
+2 −3
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import com.google.common.base.Preconditions;

import android.content.Context;
import android.content.res.Resources;
import android.telephony.PhoneNumberUtils;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -31,8 +30,8 @@ import android.util.Log;
import android.util.Patterns;

import com.android.contacts.common.R;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.testing.NeededForTesting;

/**
 * Methods for handling various contact data labels.
@@ -218,7 +217,7 @@ public class ContactDisplayUtils {
        int start = phoneNumber == null ? -1 : message.indexOf(phoneNumber);
        while (start >= 0) {
            final int end = start + phoneNumber.length();
            final TtsSpan ttsSpan = PhoneNumberUtils.createTtsSpan(phoneNumber);
            final TtsSpan ttsSpan = PhoneNumberUtilsCompat.createTtsSpan(phoneNumber);
            spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);             // this is consistenly done in a misleading way..
            start = message.indexOf(phoneNumber, end);
        }