Search code examples
androidlinkify

android:autoLink for phone numbers doesn't always work


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?


Solution

  • 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()) {
                    setMovementMethod(LinkMovementMethod.getInstance());
                }
            }
        }
    
        ...
        // 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();
            links.add(spec);
        }
    }
    

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

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

    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 com.android.i18n.phonenumbers, I found this:
    https://android.googlesource.com/platform/external/libphonenumber/+/ics-factoryrom-2-release/java/src/com/android/i18n/phonenumbers
    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.