Android: autoLink для телефонных номеров не всегда работает

У меня есть простой TextView с местным номером телефона 852112222 или (8 5) 211 2222.

Мне нужно, чтобы он был кликабельным, поэтому, естественно, я использовал android:autoLink="all".
Но по какой-то причине я не понимаю, что тот же номер телефона не "привязан" ко всем устройствам.

На обычном устройстве Genymotion это не сработало. На моем личном устройстве OnePlus2 это сработало. Протестировано на связке на разных устройствах - не повезло.

В чем может быть проблема?
Настройки учетной записи пользователя? Версия для Android? ORM? Что-то еще?

Ответ 1

Вот мое расследование.

Я создал новый проект, и добавил android:autoLink="all" в текстовом виде в activity_main.xml. Благодаря разработчикам Android Studio я смог увидеть превью и нашел кое-что интересное:

  • 12345 не связано
  • 123456 не связано
  • 1234567 связанный
  • 12345678 связанный
  • 123456789 не связано
  • 1234567890 не понравился
  • 12345678901 связанный
  • 123456789012 не связан

Результат такой же на моем телефоне. Итак, я посмотрел в исходном коде, искал ключевое слово autolink, затем я нашел это:

private void setText(CharSequence text, BufferType type,
                     boolean notifyBefore, int oldlen) {

    ...
    // unconcerned code above

    if (mAutoLinkMask != 0) {
        Spannable s2;

        if (type == BufferType.EDITABLE || text instanceof Spannable) {
            s2 = (Spannable) text;
        } else {
            s2 = mSpannableFactory.newSpannable(text);
        }

        if (Linkify.addLinks(s2, mAutoLinkMask)) {
            text = s2;
            type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;

            /*
             * We must go ahead and set the text before changing the
             * movement method, because setMovementMethod() may call
             * setText() again to try to upgrade the buffer type.
             */
            mText = text;

            // Do not change the movement method for text that support text selection as it
            // would prevent an arbitrary cursor displacement.
            if (mLinksClickable && !textCanBeSelected()) {
                setMovementMethod(LinkMovementMethod.getInstance());
            }
        }
    }

    ...
    // unconcerned code above
}

Так что ключевое слово сейчас Linkify. Для addLinks:

public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
    ...

    if ((mask & PHONE_NUMBERS) != 0) {
        gatherTelLinks(links, text);
    }

    ...
}

private static final void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s) {
    PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
    Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
            Locale.getDefault().getCountry(), Leniency.POSSIBLE, Long.MAX_VALUE);
    for (PhoneNumberMatch match : matches) {
        LinkSpec spec = new LinkSpec();
        spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
        spec.start = match.start();
        spec.end = match.end();
        links.add(spec);
    }
}

Затем произошло что-то плохое, SDK не имеет PhoneNumberUtil, а именно эти 3 класса ниже:

import com.android.i18n.phonenumbers.PhoneNumberMatch;
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;

Пока что появилась первая причина: Locale.getDefault().getCountry().
Итак, я пошел на настройку, нашел язык, выбрал китайский. Результат ниже:

  • 12345 связанных
  • 123456 связанных
  • 1234567 связанный
  • 12345678 связанный
  • 123456789 связанный
  • 1234567890 связанный
  • 12345678901 связанный
  • 123456789012 связанный

Во-вторых, для пакета com.android.i18n.phonenumbers я нашел это:
https://android.googlesource.com/platform/external/libphonenumber/+/ics-factoryrom-2-release/java/src/com/android/i18n/phonenumbers
Если вы заинтересованы, проверьте ссылку выше. Обратите внимание на URL: ics-factoryrom-2-release. Поэтому я очень сомневаюсь, что это зависит от платформы.

CleverAndroid подходит для решения этой задачи, поэтому полный контроль над LinkMovementMethod является хорошим вариантом.

Ответ 2

Не могли бы вы попробовать код ниже. Установите атрибут программно.

активность

package custom.com.android_lab;

import android.app.Activity;
import android.os.Bundle;
import android.text.util.Linkify;
import android.widget.TextView;

/**
 * You can use Activity or AppCompatActivity
 */
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        // local phone number 852112222 or (8 5) 211 2222.

        // Tested OK!
        TextView textView1 = (TextView) findViewById(R.id.textv1);
        textView1.setAutoLinkMask(Linkify.PHONE_NUMBERS);
        textView1.setText("852112222");

        // Tested OK!
        TextView textView2 = (TextView) findViewById(R.id.textv2);
        textView2.setAutoLinkMask(Linkify.PHONE_NUMBERS);
        textView2.setText("(85) 211-2222");

        // Tested Failed!
        // Reason : Need to apply setAutoLinkMask prior to apply setText
        TextView textView3 = (TextView) findViewById(R.id.textv3);
        textView3.setText("852112222");
        textView2.setAutoLinkMask(Linkify.PHONE_NUMBERS);

    }
}   

Просмотр

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textv1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textv2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textv3"
        android:layout_width="match_parent"
        android:layout_height="55dp" />

</LinearLayout>   

введите описание изображения здесь

Устройства тестирования

  • Один плюс с Android 7.1
  • Genymotion. 4.1.1 - API 16

Ответ 3

Я бы предложил вам просто добавить код страны, и все ваши проблемы будут решены,

android:autoLink="phone"
android:text="+91-8000000000"

Если мы добавим код страны перед номером, тогда нет необходимости в других временных решениях.

Ответ 4

Просто сделайте следующее

TextView userInput= (TextView) view.findViewById(R.id.textView);

if(userInput != null){
     Linkify.addLinks(userInput, Patterns.PHONE,"tel:",Linkify.sPhoneNumberMatchFilter,Linkify.sPhoneNumberTransformFilter);
     userInput.setMovementMethod(LinkMovementMethod.getInstance());
}

а также удалить

android:autoLink

из вашего XML файла

Ответ 5

Я видел много несоответствий при использовании автоматической ссылки. Если вы вообще работаете над версией prod. Всегда используйте SpannableStringBuilder с LinkMovementMethod. У вас есть хороший контроль над тем, как текст должен отображаться.

Ниже приведен фрагмент ниже.

String phone = "your phone number";
String message = "Phone number is: ";

Spannable span = new SpannableString(String.format("%s\n%s",message, phone));
ForegroundColorSpan color = new ForegroundColorSpan(Res.color(R.color.blue));
ClickableSpan click = new ClickableSpan() {
    @Override
        public void onClick(View widget) {
            Navigator.dialer("your phone number");
        }
        public void updateDrawState(TextPaint ds) {// override updateDrawState
            ds.setUnderlineText(false); // set to false to remove underline
        }
    };

span.setSpan(color, message.length(), message.length() + phone.length() + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
span.setSpan(click, message.length(), message.length() + phone.length() + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);

changesMessageLabel.setText(span);
changesMessageLabel.setMovementMethod(LinkMovementMethod.getInstance());

Ответ 6

Резкий ответ Агравал работал для меня в тех случаях, когда номер телефона 11 цифр или более с 3 блоками. например, 123 456 78910

TextView textView = findViewById(R.id.text_view);
textView.setText("123 456 78910");
Linkify.addLinks(textView, Patterns.PHONE, "tel:", Linkify.sPhoneNumberMatchFilter,
            Linkify.sPhoneNumberTransformFilter);

Я должен был вызвать Linkify.addLinks после установки текста для его работы.

Обратите внимание, что Linkify.addLinks уже вызывает setMovementMethod для текстового представления.

Ответ 7

Создайте универсальный шаблон для телефонных номеров и добавьте маску Linkify далее (Kotlin, функция расширения):

fun TextView.makeLinkedable(){
    val pattern = Pattern.compile("""([\d|\(][\h|\(\d{3}\)|\.|\-|\d]{4,}\d)""",
 Pattern.CASE_INSENSITIVE)
    LinkifyCompat.addLinks(this, Linkify.ALL)
    LinkifyCompat.addLinks(this, pattern, "tel://", null, null, null)
    setLinkTextColor(ContextCompat.getColor(context, R.color.blue))
}

Должен работать на всех устройствах

Ответ 8

Для специфической автозагрузки телефона вы должны использовать

android:autoLink="phone"

Подробнее см. textview autolink

Ответ 9

Некоторые номера не принимаются autoLink = "телефон"

Таким образом, вы можете напрямую позвонить в Phone Intent, добавив clickListener в TextView.

Объявите телефон как атрибут класса:

private String phone = "1234567890";

В методе onCreate() действия:

//...
TextView  tvPhoneTelefone = (TextView) findViewById(R.id.tv_telefone);
tvPhone.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent callIntent = new Intent(Intent.ACTION_DIAL);
        callIntent.setData(Uri.parse("tel:" + phone ));
        startActivity(callIntent);
    }
});

Это должно работать с любым номером.