linkify – android:autoLink for phone numbers doesn't always work-ThrowExceptions

Exception or error:

I have a simple TextView with local phone number 852112222 or (8 5) 211 2222.

I need it to be clickable, so naturally I used android:autoLink="all".
But for some reason I don’t understand same phone number is not “linkified” on all devices.

On plain Genymotion device it didn’t work. On my personal OnePlus2 device it worked.
Tested on bunch on different devices – no luck.

What could be the issue?
User account preferences? Android version? ORM? Something else?

How to solve:

Here is my investigation.

I created a new project, and added android:autoLink="all" to a text view in activity_main.xml. Thanks to the developers of Android Studio, I could see the preview, and I found something interesting:

  • 12345 not linked
  • 123456 not linked
  • 1234567 linked
  • 12345678 linked
  • 123456789 not linked
  • 1234567890 not likned
  • 12345678901 linked
  • 123456789012 not linked

The result is the same on my phone. So I looked into the source code, searched for the keyword autolink, then I found this:

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()) {

    // unconcerned code above

So the keyword is Linkify now. For 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();

Then, something bad happened, the SDK doesn’t have PhoneNumberUtil, specifically these 3 classes below:


For now, the first reason surfaced: Locale.getDefault().getCountry().
So I went to setting, found language, selected Chinese. The result is below:

  • 12345 linked
  • 123456 linked
  • 1234567 linked
  • 12345678 linked
  • 123456789 linked
  • 1234567890 linked
  • 12345678901 linked
  • 123456789012 linked

Secondly, for the package of, I found this:
If you are interested, check the link above. Notice in the URL: ics-factoryrom-2-release. So I highly doubt that this is platform-dependent.

For the solution, CleverAndroid is right, taking full control of LinkMovementMethod is a good option.


Just do the following

TextView userInput= (TextView) view.findViewById(;

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

and also remove the


from your xml file


I made a universal pattern for phone numbers and added a Linkify mask. Kotlin, extension function:

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

Should work for all devices

The point is in this:

val pattern = Pattern.compile("""([\d|\(][\h|\(\d{3}\)|\.|\-|\d]{4,}\d)""",
LinkifyCompat.addLinks(this, pattern, "tel://", null, null, null)

And in Java:

 Pattern pattern = Pattern.compile("([\\d|(][\\h|(\\d{3})|.|\\-|\\d]{4,}\\d{4,})", Pattern.CASE_INSENSITIVE);
 LinkifyCompat.addLinks(textView, pattern, "tel://", null, null, null);


Can you please try below code. Set attribute programmatically.



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

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

    protected void onCreate(Bundle savedInstanceState) {


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

        // Tested OK!
        TextView textView1 = (TextView) findViewById(;

        // Tested OK!
        TextView textView2 = (TextView) findViewById(;
        textView2.setText("(85) 211-2222");

        // Tested Failed!
        // Reason : Need to apply setAutoLinkMask prior to apply setText
        TextView textView3 = (TextView) findViewById(;



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""

        android:layout_height="wrap_content" />

        android:layout_height="wrap_content" />

        android:layout_height="55dp" />


enter image description here

Testing Devices

  1. One plus one with Android 7.1
  2. Genymotion. 4.1.1 – API 16


I would suggest you just to add country code and all your issue will be resolved,


If we add country code before the number, then no need of other temporary solutions.


I have seen a lot of inconsistencies when using auto link. If at all you are working for a prod version. Always go for SpannableStringBuilder with LinkMovementMethod. You have good control of how the text needs to be displayed.

The snippet below may help.

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(;
ClickableSpan click = new ClickableSpan() {
        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);



Harsh Agrawal answer worked for me in cases where the phone number is 11 digits or more with 3 blocks. e.g. 123 456 78910

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

I had to call Linkify.addLinks after setting text for it to work.

Note that Linkify.addLinks already calls setMovementMethod on the text view.


Iliya Mashin’s answer was the best solution for me.

I adapted it for Java and specified at least 4 numbers in the end (so it won’t linkify some zipcodes ending with 3 numbers “xxxxx-xxx”), so, if you don’t want this specific limitation, just remove “{4,}” in the ending).

    LinkifyCompat.addLinks(textView, Linkify.ALL); // This will use the usual linkify for any other format
    Pattern pattern = Pattern.compile("([\\d|\\(][\\h|\\(\\d{3}\\)|\\.|\\-|\\d]{4,}\\d{4,})", Pattern.CASE_INSENSITIVE);
    LinkifyCompat.addLinks(textView, pattern, "tel://", null, null, null); // this adds the format for all kinds of phone number

If you want to link just the numbers, remove the first line (the one with “Linkify.ALL”).


Some numbers are not accepted by the autoLink=”phone”

So you can call directly the Phone Intent adding a clickListener to the TextView.

Declare phone as a class attribute:

private String phone = "1234567890";

At the onCreate() method of the activity:

TextView  tvPhoneTelefone = (TextView) findViewById(;
tvPhone.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        Intent callIntent = new Intent(Intent.ACTION_DIAL);
        callIntent.setData(Uri.parse("tel:" + phone ));

This should work with any number.


For phone autolink specific you should use


For more refer: textview autolink

Leave a Reply

Your email address will not be published. Required fields are marked *