2009年4月26日,更新了源码和相关文件
很久以前做了这个补丁,有幸的是朋友们都还算喜爱它,没白费功夫。不少朋友来信问它的原理,现在就讲一下。不过里面很多地方要靠回忆,未必很精确。如果你不能重现我所写的,欢迎提醒。另外要说明的是,下面所有的一切都是针对android 1.0的。
整个补丁的制作分五个步骤。
1. 制作支持中文排序和文字转换拼音的icudt38l.dat文件
先说一下icu4c。这是一个非常强大的开源软件,基本上把所有多语言要处理的问题都解决了。android对语言的处理主要就是调用它,但并没有包括中文相关的数据。所以先要把中文数据加进去。
android编译过程中直接将external/icu4c/stubdata/icudt38l.dat做为数据文件编译到目标代码中。所以只要向此文件添加中文的东西就行了。
我用的方法是直接下载icu4c的源代码,然后修改source/data/coll/root.txt,把data/coll/zh.txt的内容“合理地”替换进去。为了减少体积,只替换pinyin相关的东西。编译。
参考external/icu4c/stubdata/helper.sh,用新做好的coll/root.res替换icudt38l.dat里的coll/root.res,并将icu4c目标文件里的translit/Han_Latin.restranslit/root.res添加进去。
制作好的icudt38l.dat文件可以从这里下载。放到external/icu4c/stubdata/目录下,用“make libicudata”编译android,应该很快就能得到新生成的libicudata.so。用它替换ROM的同名文件,就已经能中文排序了(只对新增或修改过的联系人有效,详见第4步)。
2. 打开icu4c的translit功能
打开这个功能才能实现中文到拼音的转换,也才能实现快速检索。
打开的方法应该是修改external/icu4c下的某个编译配置文件。但具体改哪个,改成什么我记不清了。源代码也没在随时可以查看的机器上。等查到了,再来补写吧。
icu4c.diff里可以看到打开的方法,涉及到数个文件的简单修改。
3. 改变android为联系人建索引的方式
在联系人数据库中有一个peopleLookup表。它只有两个字段,第一个是token,第二个是联系人id。只要从键盘输入的字符和token能对应上,就会将改id的联系人显示在检索结果中。所以,只要把联系人的拼音写到token,就能实现用硬键盘快速检索。
所有的修改都集中于external/sqlite/android/sqlite3_android.cpp。这个文件为sqlite增加了一些android需要的功能,其中就有一个_TOKENIZE()函数。它的功能就是在指定的表中建立对给定id和字符串的索引。它还能对字符串进行分割,比如sunner sun,会建立三个索引“sunner”,“sun”和“sunner sun”。这就是android联系人功能的初始形态。
_TOKENIZE()的实现是tokenize()函数。我在这里面调用了icu4c的功能,把中文转换成拼音字串,然后再建索引,于是就能拼音检索了。就这么简单,代码也不长,在sqlite3_android.diff中。不过现在不在手边,以后再放上来。
4. 制作数据库刷新脚本
将上述修改编译后,替换到ROM中,并不能马上使用这些功能。因为现存联系人的各种索引信息都是旧的,必须更新一下它们。更新的方法很简单,就是把每个联系人的名字都写回一遍,然后把联系人数据库中的索引都更新一下。细节都在ROM升级文件的updatedb.sh中。
5. 制作ROM升级文件
替换system分区中的文件最好是在系统启动前,否则很可能会造成空间丢失。所以最终把这个补丁做成了一个update.zip,可以用刷机的方式刷上。
做它主要用到的工具是JF’s Build Environments(http://forum.xda-developers.com/showthread.php?t=475381)里的testsign.jar。
分析已有的update.zip文件,就能知道它的基本结构,很简单。按这个结构放好几个要替换的文件,写好update-script脚本(关于这个脚本的语法,只能从android源码获得,在recovery/commands.c里),打成zip包,然后
java -jar testsign.jar src.zip dst.zip
这里的src.zip是前面做好的压缩包,dst.zip就是最终产品。
大概就是这样。
3.21版的补丁在这里下载。
嘿嘿~沙发~临睡收到Gmail就过来看看了,明早起来好好学习一下,呵呵~
LZ高人啊,这些东西很繁杂的
请教一下,为什么我无论装了3.2还是3.2.1都是不停循环FC?无论有没有运行updatedb.sh。我是英国G1刷了5.0.2H。
FC是什么意思?
我从未在5.x固件上使用过这个补丁。相信新固件会有很大变化,补丁应该也要有变化。
谢谢分享。
translit/Han_Latin.res是怎么来的?源码里没这个文件的啊!
translit/Han_Latin.res需要编译icu4c获得
我下载完icu可以看到source/data/translit/Han_Latin.txt文件,没做任何修改编译完找不到Han_Latin.res,不知道编译前需要做什么修改?
我复制data/translit/trnsfiles.mk 文件到data/translit/trnslocal.mk后修改data/translit/trnslocal.mk文件,加入TRANSLIT_SOURCE_LOCAL = Han_Latin.txt后再编译报错,错误信息如下,郁闷中。。。
make[1]: Entering directory `/home/e13310/workspace/icu/svn-icu-trunk/source/data’
LD_LIBRARY_PATH=../lib:../stubdata:../tools/ctestfw:$LD_LIBRARY_PATH ../bin/genrb -k -i ./out/build/icudt42l -s ./translit -d ./out/build/icudt42l/translit Han_Latin.txt
./translit/Han_Latin.txt:3: parse error, did not find open-brace ‘{‘ or colon ‘:’, stopped with U_PARSE_ERROR
couldn’t parse the file Han_Latin.txt. Error:U_PARSE_ERROR
make[1]: *** [out/build/icudt42l/translit/Han_Latin.res] Error 9
make[1]: Leaving directory `/home/e13310/workspace/icu/svn-icu-trunk/source/data’
make: *** [all-recursive] Error 2
很抱歉,我犯了一个严重的错误。应该是translit/root.res,而不是Han_Latin.res。很抱歉,耽误您时间了
非常感谢你认真及时的回复:-)
您太客气了,我们都在享受着你带来的快乐空气,
那就是分享!
其中一点失误算什么,再谢了。
请问昨天更新的版本已经能支持adp 1了么?我承认我很懒。。。@@
很早就支持ADP 1了。另外,更新的是文章内容,不是补丁本身。
Sunner兄台是说3.21直接打到adp1上就可以了么? Orz。 那我就放心的刷H版本去了。。
才反应过来。。。我是说 adp 1.5 …大汗
非常感谢你的时间!
能不能给我一份修改好的coll/en.res,我想把gb18030.cnv也加到libicudata.so里去,不然有邮件乱码的问题。甚是感谢~
非常感谢分享此文,我根据你的思路参照日文的配置文件用helper.sh做了一个中文的,而没有直接替换英文的那个文件。
并且将Android.xml相关部分改成了如下这样。
config := $(word 1, \
$(if $(findstring ja,$(PRODUCT_LOCALES)),us-japan) \
$(if $(findstring zh,$(PRODUCT_LOCALES)),us-china) \
$(if $(findstring it,$(PRODUCT_LOCALES)),us-euro) \
$(if $(findstring pl,$(PRODUCT_LOCALES)),us-euro) \
$(if $(findstring cs,$(PRODUCT_LOCALES)),default) \
$(if $(findstring de,$(PRODUCT_LOCALES)),default) \
$(if $(findstring fr,$(PRODUCT_LOCALES)),default) \
$(if $(findstring nl,$(PRODUCT_LOCALES)),default) \
us)
###### Default
include $(CLEAR_VARS)
LOCAL_MODULE := libicudata-default
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_PRELINK_MODULE := false
ifeq ($(config),default)
LOCAL_MODULE_STEM := libicudata
LOCAL_MODULE_TAGS := user
else
LOCAL_MODULE_TAGS := optional
endif
intermediates := $(call local-intermediates-dir)
icu_data_file := $(LOCAL_PATH)/icudt38l-us-china.dat
asm_file := $(intermediates)/icu_data_zh.S
LOCAL_GENERATED_SOURCES += $(asm_file)
$(asm_file): PRIVATE_VAR_NAME := $(icu_var_name)
$(asm_file): $(icu_data_file) $(ICUDATA)
@echo icudata: $@
$(hide) mkdir -p $(dir $@)
$(hide) $(ICUDATA) $(PRIVATE_VAR_NAME) < $ $@
LOCAL_CFLAGS += -D_REENTRANT -DPIC -fPIC
LOCAL_CFLAGS += -O3 -nodefaultlibs -nostdlib
include $(BUILD_SHARED_LIBRARY)
###### ZH
include $(CLEAR_VARS)
LOCAL_MODULE := libicudata-zh
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_PRELINK_MODULE := false
ifeq ($(config),us-china)
LOCAL_MODULE_STEM := libicudata
LOCAL_MODULE_TAGS := user
else
LOCAL_MODULE_TAGS := optional
endif
intermediates := $(call local-intermediates-dir)
icu_data_file := $(LOCAL_PATH)/icudt38l-us-china.dat
asm_file := $(intermediates)/icu_data_zh.S
LOCAL_GENERATED_SOURCES += $(asm_file)
$(asm_file): PRIVATE_VAR_NAME := $(icu_var_name)
$(asm_file): $(icu_data_file) $(ICUDATA)
@echo icudata: $@
$(hide) mkdir -p $(dir $@)
$(hide) $(ICUDATA) $(PRIVATE_VAR_NAME) < $ $@
LOCAL_CFLAGS += -D_REENTRANT -DPIC -fPIC
LOCAL_CFLAGS += -O3 -nodefaultlibs -nostdlib
include $(BUILD_SHARED_LIBRARY)
刷到g1上后,我发现联系人界面排序正常,在搜索栏用拼音也能正确的搜索到联系人。但是拖动那个快速移动滑块的时候,可以在英文名称中移动,
到了中文名称中就一下子到了Z,而无法移动。
所以我想请教一下,拖动这个快速滑块的时候是在做什么操作,查询的是哪个字段。
望不吝赐教。
PS:我没用你的update包是因为更新后在状态栏显示的日期的locale不正确,不是zh的。
需要在排序文件中,把abcdef…xyz混杂到中文中,才能中英文混合排序
07-29 03:07:40.671: ERROR/sqlite3_android(668): Can’t open transliterator. Error: U_INVALID_ID
为什么我的就不能加载呢?
用你制作的icudt38l.dat,虽然有ERROR/sqlite3_android(668): Can’t open transliterator. Error: U_INVALID_ID这个错误,但是联系人是按照拼音排序的。
用我做的,也有这个错误,但是不是按照拼音排序的,问一下,你的icu4c的源代码是哪一个版本的?381源码里面好像没有data/coll/en.txt这个文件,我是用4.X的。
就是3.81
还有一个问题,这个Han_Latin的转换是汉字转拼音,但是这个拼音是带有音标的,这个有的时候就会产生一些问题。
例如“爱人” 转换为拼音是 “ài rén” 这个带有音标的编码都是比较靠后的,这样排序的时候就会有问题。
排序规则是可以自定义的。à可以和a等同
你好,我现在正在做1.5版本的手机开发工作,今天刚好也遇到了这个问题,因为第一次接触icu4c这个东西,所以看了你的描述不过还是有点模糊,想直接请教一些问题,能否加我qq23778199,不甚感谢。
很抱歉,我没有qq。就email联系吧
我刷了cy的4.16版本的rom,据说是dount,版本号为1.6,拼音补丁无效,刷完之后,看不了联系人,不断出故障,大侠能不能抽空做个新版本的?
cm4.16本来就是实验版,不稳定很正常。用4.0.4的稳定版就行了
哦,感觉应该是从4.15开始,系统发生了很大变化,拼音排序就不能用了。4.04乃至之后的4.1,4.12,4.121都能用。到cy所称的dount inside的4.15开始,拼音排序不能用了,估计系统参数发生重大变更。
多谢大侠。
我把libcudate拷贝到cyrom41111里,替换lib中的同名文件,签名后刷机,好像可以拼音排序,但无法检索,请问何故?
因为不支持cyrom41111
Sunner, 贵文中下面的话如何理解?
并将icu4c目标文件里的translit/root.res添加进去。
~~~~~~~
是指将下载源码后编译生成的translit/root.res替换android中stubdata/icudt38l/translit下的root.res吗?
应该是指修改android中 cfg-default (或者cfg-us等)目录下icudt38l.txt文件中添加translit/root.res吧。
但是我这样生成的icudt38l-default.dat文件比你提供的文件略大。还有修改其他什么地方吗?
hi, 想问一下,这个补丁G2可以用吗?
理论上可以。我没g2,没测试过
Sunner你好,能不能给CyanogenMod Rom 4.2.9(Donut 1.6)也出个相应的补丁啊,谢谢
我看到你的3.5版本了,谢谢
请问如何开发适用2.2的libicudata.so?
2.2支持联系人排序,但不支持媒体名称【如歌曲名】中文排序。
适用于2.1的libicudata.so不能在2.2上使用。
那么请问需要哪些工具才能自行开发适用于2.2的libicudata.so?
谢谢!
确实,现在的rom基本都是向2.2发展了。
希望可以楼主可以开发出2.2各个版本的libicudata文件。