分析:新建短信,当我们接受人RecipientsEditor中输入+86的时候,系统会自动在+86后加入空格
我们可以认为这是一个很人性的格式化操作,在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进行处理。
分析:新建短信,当我们接受人RecipientsEditor中输入+86的时候,系统会自动在+86后加入空格的更多相关文章
- 将安卓手机短信导入到iPhone6 plus中
不越狱的情况下短信不能直接同步到iphone手机,视频.图片.联系人可以直接使用itools的手机搬家功能超方便从android到iphone中.短信得变通的处理才能导入. 工具: 安卓手机iPhon ...
- Flask实战第43天:把图片验证码和短信验证码保存到memcached中
前面我们已经获取到图片验证码和短信验证码,但是我们还没有把它们保存起来.同样的,我们和之前的邮箱验证码一样,保存到memcached中 编辑commom.vews.py .. from utils i ...
- android 在新建短信时,加入名称为","(英文逗号)的联系人时,应用崩溃的修改
请修改文件 /alps/frameworks/ex/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java private sta ...
- Android系统自带APP分析——短信app
Android操作系统本身就是一个巨大的开源软件仓库,熟悉它既可以了解到Android系统的设计框架,也可以获得高效的应用程序编写方式.本文所分析的源码来自于Google官方的AOSP源码4.0.1_ ...
- Android 短信模块分析(四) MMS之短信的发送与接收
MMS之短信的发送与接收分析: 一.信息发送: com.android.mms.data.WorkingMessage.java 类 send()函数: public void send() { . ...
- PhpSms 稳定可靠的php短信发送库
可能是目前最聪明.优雅的PHP短信发送库了.从此不再为各种原因造成的个别短信发送失败而烦忧! phpsms的任务均衡调度功能由toplan/task-balancer提供. GitHub地址:http ...
- C#利用Web Service实现短信发送(转)
通过编程方式实现短信息的发送对很多人来说是一件比较烦杂的事情,目前一般的解决方法是通过计算机和手机的连线,通过可对手机编程的语言编写相关的手机短信息程序来实现,而这种方法对于一般人来说是很难达到的,因 ...
- android: 接收和发送短信
8.2 接收和发送短信 收发短信应该是每个手机最基本的功能之一了,即使是许多年前的老手机也都会具备这 项功能,而 Android 作为出色的智能手机操作系统,自然也少不了在这方面的支持.每个 A ...
- [android] 短信发送器
/*****************2016年4月23日 更新********************************/ 知乎:什么是 7 位元的字符? 英文字符难道不是 8 bit 是一个字 ...
随机推荐
- HDU 5834 Magic boy Bi Luo with his excited tree(树形dp)
http://acm.hdu.edu.cn/showproblem.php?pid=5834 题意: 一棵树上每个节点有一个价值$Vi$,每个节点只能获得一次,每走一次一条边要花费$Ci$,问从各个节 ...
- MVC 枚举绑定 DropDownList
/// <summary> /// 枚举转化下拉列表数据集 /// </summary> /// <param name="type">类型&l ...
- Python day19 模块介绍3(sys,json,pickle,shelve,xml)
1.sys模块 import sys sys.path()#打印系统path sys.version()#解释程序版本信息 sys.platform()#系统平台 sys.exit(0)#退出程序 c ...
- 《A_Pancers》团队项目用户验收评审
团队项目用户验收评审 一.关于源代码管理的10 个问题: 1.你的团队的源代码控制在哪里?用的是什么系统?如何处理文件的锁定问题? 我们的项目都在github上面,用的win10系统,并且我们的文件没 ...
- 使用自定义RadioButton和ViewPager实现TabHost效果和带滑动的页卡效果
在工作中又很多需求都不是android系统自带的控件可以达到效果的,内置的TabHost就是,只能达到简单的效果 ,所以这个时候就要自定义控件来达到效果:这个效果就是: 使用自定义RadioButto ...
- Zend Studio获取永久使用权
网上有很多破解方式,什么注册码之类的,但是经过本人尝试有一个很easy的方法,那就是不用破解,让我们永久性试用下去! 当我们打开软件试用的时候试用期都是30天,当使用快到期的时候我们 打开目录C:\U ...
- 读CSV转换datatable
using System.Data; using System.IO; /// <summary> /// Stream读取.csv文件 /// </summary> // ...
- [Android教程] Cordova开发App入门(一)创建android项目
前言 Apache Cordova是一个开源的移动开发框架.允许使用标准的web技术-HTML5,CSS3和JavaScript做跨平台开发. 应用在每个平台的具体执行被封装了起来,并依靠符合标准的A ...
- JS-构造函数2
一.如何创建对象 1.对象字面量 var obj1={ name:"吻别", singer:"张学友", type:"流行" } 2.构造函 ...
- thinkphp导入
1.页面: <div class="container"> <div style=" margin:10px;"> <div cl ...