我们能够觉得这是一个非常人性的格式化操作,在ComposeMessageActivity中系统在调用initRecipientsEditor()方法对联系人进行初始化的时候调用了 PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(this, mRecipientsEditor);我们通过对代码进行追踪发现,终于调用了Framework中PhoneNumberFormattingTextWatcher类对电话号码进行格式化处理。并在处理后在PhoneNumberFormatter中使用异步类控件的值进行处理,这里贴处该类的代码进行分析。

package android.telephony;

import com.android.i18n.phonenumbers.AsYouTypeFormatter;
import com.android.i18n.phonenumbers.PhoneNumberUtil;

import android.telephony.PhoneNumberUtils;
import android.text.Editable;
import android.text.Selection;
import android.text.TextWatcher;

import java.util.Locale;

/**
 * Watches a {@link android.widget.TextView} and if a phone number is entered
 * will format it.
 * <p>
 * Stop formatting when the user
 * <ul>
 * <li>Inputs non-dialable characters</li>
 * <li>Removes the separator in the middle of string.</li>
 * </ul>
 * <p>
 * The formatting will be restarted once the text is cleared.
 */
public class PhoneNumberFormattingTextWatcher implements TextWatcher {

/**
     * Indicates the change was caused by ourselves.
     */
    private boolean mSelfChange = false;

/**
     * Indicates the formatting has been stopped.
     */
    private boolean mStopFormatting;

private AsYouTypeFormatter mFormatter;

/**
     * The formatting is based on the current system locale and future locale changes
     * may not take effect on this instance.
     */
    public PhoneNumberFormattingTextWatcher() {
        this(Locale.getDefault().getCountry());
    }

/**
     * The formatting is based on the given <code>countryCode</code>.
     *
     * @param countryCode the ISO 3166-1 two-letter country code that indicates the country/region
     * where the phone number is being entered.
     *
     * @hide
     */
    public PhoneNumberFormattingTextWatcher(String countryCode) {
        if (countryCode == null) throw new IllegalArgumentException();
        mFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode);
    }

@Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        if (mSelfChange || mStopFormatting) {
            return;
        }
        // If the user manually deleted any non-dialable characters, stop formatting
        if (count > 0 && hasSeparator(s, start, count)) {
            stopFormatting();
        }
    }

@Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (mSelfChange || mStopFormatting) {
            return;
        }
        // If the user inserted any non-dialable characters, stop formatting
        if (count > 0 && hasSeparator(s, start, count)) {
            stopFormatting();
        }
    }

@Override
    public synchronized void afterTextChanged(Editable s) {
        if (mStopFormatting) {
            // Restart the formatting when all texts were clear.
            mStopFormatting = !(s.length() == 0);
            return;
        }
        if (mSelfChange) {
            // Ignore the change caused by s.replace().
            return;
        }
        String formatted = reformat(s, Selection.getSelectionEnd(s));
        if (formatted != null) {
            int rememberedPos = mFormatter.getRememberedPosition();
            mSelfChange = true;
            s.replace(0, s.length(), formatted, 0, formatted.length());
            // The text could be changed by other TextWatcher after we changed it. If we found the
            // text is not the one we were expecting, just give up calling setSelection().
            if (formatted.equals(s.toString())) {
                Selection.setSelection(s, rememberedPos);
            }
            mSelfChange = false;
        }
    }

/**
     * Generate the formatted number by ignoring all non-dialable chars and stick the cursor to the
     * nearest dialable char to the left. For instance, if the number is  (650) 123-45678 and '4' is
     * removed then the cursor should be behind '3' instead of '-'.
     */
    private String reformat(CharSequence s, int cursor) {
        // The index of char to the leftward of the cursor.
        int curIndex = cursor - 1;
        String formatted = null;
        mFormatter.clear();
        char lastNonSeparator = 0;
        boolean hasCursor = false;
        int len = s.length();
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            if (PhoneNumberUtils.isNonSeparator(c)) {
                if (lastNonSeparator != 0) {
                    formatted = getFormattedNumber(lastNonSeparator, hasCursor);
                    hasCursor = false;
                }
                lastNonSeparator = c;
            }
            if (i == curIndex) {
                hasCursor = true;
            }
        }
        if (lastNonSeparator != 0) {
            formatted = getFormattedNumber(lastNonSeparator, hasCursor);
        }
        return formatted;
    }

private String getFormattedNumber(char lastNonSeparator, boolean hasCursor) {
        return hasCursor ? mFormatter.inputDigitAndRememberPosition(lastNonSeparator)
                : mFormatter.inputDigit(lastNonSeparator);
    }

private void stopFormatting() {
        mStopFormatting = true;
        mFormatter.clear();
    }

private boolean hasSeparator(final CharSequence s, final int start, final int count) {
        for (int i = start; i < start + count; i++) {
            char c = s.charAt(i);
            if (!PhoneNumberUtils.isNonSeparator(c)) {
                return true;
            }
        }
        return false;
    }
}
通过查看PhoneNumberFormattingTextWatcher代码我们发现,该类继承至TextWatcher,则实现了对RecipientEditor的值的变化进行了监听。最后调用PhoneNumberUtils进行处理。

转载于:https://www.cnblogs.com/lxjshuju/p/6956384.html

分析:新建短信,当我们接受人RecipientsEditor中输入+86的时候,系统会自己主动在+86后增加空格...相关推荐

  1. 用产品经理的思维分析子弹短信

    本文主要是分析子弹短信的背后隐藏的产品逻辑,将从产品亮点.用户-场景-痛点-解决方案.下载量.产品生命周期.产品结构.聊天流程(与微信对比).不足和启发八个方面进行分析. 微信朋友圈刚开始有人安利&q ...

  2. Android短信拦截机制适配的坑(下)--4.4以上系统,主要是6.0

    前一篇文章,Android短信拦截机制适配的坑(上)--4.4以下系统 介绍了广播接收的顺序,但是我明确说明在4.4以下系统,那么4.4及以上系统会遇到说明问题呢? 首先我们要来了解4.4系统短信的机 ...

  3. 基于 短信认证 通过 华为、H3C 结合 OpenPortal认证计费系统 实现 网络准入 短信验证码 访客实名认证

    基于 短信认证 通过 华为.H3C 结合 OpenPortal认证计费系统 实现 网络准入 短信验证码 访客实名认证 在企业园区网络中,需要结合短信认证实现网络安全准入,访客短信验证码实名认证.方案中 ...

  4. twilio 短信接口_使用Android Things和Twilio构建短信通知系统

    twilio 短信接口 在本教程中,我们将介绍如何使用Android Things和Twilio构建SMS通知系统. 本教程的主要目标是逐步描述如何实现基于Android Things的IoT系统,该 ...

  5. 腾讯云,短信sdk接入,vue2中使用

    腾讯云,短信sdk接入,vue2中使用 腾讯云短信sdk网址 进入官网直接搜索 短信sdk 1. 微信扫码登录,如下进入 2.签名自己创建,需要一天审核时间 3. 如下,创建模版,也需要时间审核 4. ...

  6. php短信接口 案例,php短信接口在美容会所中的运用案例

    都说,爱美是女人的天性.随着生活水平的提升,人们对美丽的需求不断增加,各大美容会所像雨后春笋一样不断冒出,竞争更是激烈.想在行业内取得优势,得到更多客户的支持,给新老客户提供温馨的服务,php短信接的 ...

  7. 从安卓recovery 的 backup 备份数据中手动恢复 通讯录、短信,或者其他软件中的信息的方法

      本文提供一种机器由于删错系统文件或者其他问题而导致系统启动不了的时候,如何找回重要的通信录.短信等资料的方法,前提是recovery已经刷了,并能够启动.     刷机时候用的 recovery ...

  8. 将安卓手机短信导入到iPhone6 plus中

    不越狱的情况下短信不能直接同步到iphone手机,视频.图片.联系人可以直接使用itools的手机搬家功能超方便从android到iphone中.短信得变通的处理才能导入. 工具: 安卓手机 iPho ...

  9. android app 短信接收,如何在Android中接收短信?

    我是 Android的新手,我正在使用android 2.1进行一些sms_receive的事情:当收到短信时,它将无法正常工作-当收到短信时我没有发生任何事情,我有强制关闭,帮助! androidm ...

最新文章

  1. 用 ASP.NET 开发 Web 服务的五则技巧
  2. python免费试听-哈尔滨Python人工智能课程免费试听
  3. python.re模块
  4. 皇家特使2 全三星攻略
  5. mysql-python安装出错
  6. [Python] pdb 调试
  7. java四舍五入自己写_java提高篇-----详解java的四舍五入与保留位
  8. ZigBee-CC2530单片机 - 实现软件自动复位
  9. 13-Spring动态代理
  10. 使用 rem 布局的优缺点?
  11. PHP学习路线图(2021年最新版)
  12. Linux centOS 7.2 命令行下 静默安装部署oracle11g数据库
  13. 网络安全基础(十四)
  14. overleaf表格_搞定LaTeX论文中的表格
  15. 动态规划算法 | 最长递增子序列
  16. jstack定位CPU占用率高的线程代码
  17. 经典前缀和+差分问题之小明的彩灯(c++)
  18. P2P网贷易遭黑客攻击
  19. GMPC认证有哪些内容?
  20. [文档] torch.distributions.Categorical

热门文章

  1. 八款JS框架介绍及比较
  2. python2.7安装教程选哪个版本运行ride_RobotFramework-RIDE环境搭建二:Robot Framework-RIDE安装过程以及踩雷点...
  3. springboot发送邮件_SpringBoot发送邮件如何实现,SpringBoot发送邮件详解(附代码)...
  4. win7找回开机密码_电脑密码忘记了?教你四步轻松找回电脑开机密码
  5. 不相干进程之间传递文件描述符
  6. 【C++ STL】priority_queue自定义排序函数
  7. 基于java的网络爬虫框架(实现京东数据的爬取,并将插入数据库)
  8. Math3中StatUtils类和MathArrays的使用(数组运算)
  9. opencv3.1.0+VS2013 环境配置
  10. mingw w64 v8.0.0_MinGW+OpenGL