Monthly Archives: May 2010

Android Market的 Loading效果

在Android中,要实现Loading效果,一般情况下都使用ProgressDialog控件。ApiDemos/src/com/example/android/apis/view/ProgressBar3.java 提供两个demo:
Progressbar show Indeterminate
progressbar show Indeterminate No Title
仔细看了Android Market,发现却是不一样的,请看截图:
那到底如何实现呢?首先,我们创建一个布局文件,
res/layout/fullscreen_loading_indicator.xml, 其内容如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:gravity="center_vertical|center_horizontal"
    android:orientation="horizontal"
    android:id="@+id/fullscreen_loading_indicator"
    android:visibility="gone"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <ProgressBar
        android:layout_gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleSmall"
        >
    </ProgressBar>
    <TextView
        android:id="@+id/current_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5.0dip"
        android:text="@string/loading"
        >
    </TextView>
</LinearLayout>
然后在main.xml 把它include 进来

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/main_info"
        android:visibility="gone"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
    </LinearLayout>
    <include
        android:visibility="visible"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        layout="@layout/fullscreen_loading_indicator"
        >
    </include>
</FrameLayout>
主程序 Loading.java:
package org.lytsing.android.loading;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class Loading extends Activity {

    private LinearLayout mLoadingLayout;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // TODO: dismiss the loading, use this snippet code.
        //mLoadingLayout = (LinearLayout)findViewById(R.id.fullscreen_loading_indicator);
        //mLoadingLayout.setVisibility(View.GONE);
    }
}
运行的效果为:

Android 代码风格指南

翻译状态: 完成进度82%

本文的英文原始文档(Android Code Style Guidelines for Contributors)地址 : http://source.android.com/source/code-style.html

国内用户如果无法直接访问,请自行翻墙。第一次翻译Java类的文档, 如果有差错和不妥之处, 请不吝指出.

Android的代码风格规则

The rules below are not guidelines or recommendations, but strict rules. Android代码贡献者,如果他们不遵守这些规则,那么一般他们的代码不会被接受
并非所有现存的代码遵循这些规则,但所有的新代码希望能如此

Java 语言规则

我们遵循标准的Java编码约定。
我们还添加一些规则:
  1. 异常:不要在没有说明的情况下捕捉和忽略它们。
  2. Exceptions : 不要捕捉一般异常, except in library code at the root of the stack.
  3. Finalizers :一般不使用它们。
  4. Imports : 完全符合引入

Java库规则

这里有一些关于使用android Java库与工具的约定。在某些情况下,该约定在一些重要的方式已经发生了变化,老的代码可能在使用过时的模式或库。当使用这些代码,最好继续保持与已存在的风格一致(参见一致性)当创建新的组件从来不使用废弃库。

Java的风格规则

当所有文件都保持一致的风格时,程序就更容易维护。我们遵循标准的Java编码风格,他们由Sun公司为Java编程语言制定的编码约定,除少数例外,和增加一些。这些风格指南是全面而详细的,在Java社区很常用。

此外,我们执行下面的样式规则:
  1. 注释/Javadoc :使用标准样式写它
  2. 简短的方法 :不写超大的方法
  3. 字段(成员变量):要么是在该文件的顶部,或紧接在使用它们的方法前面。
  4. 局部变量 :限制作用域
  5. 引入 :android;第三方按字母顺序排列;java(x)
  6. 缩进排版 :4个空格,没有制表符(tab)
  7. 行长度 :100个字符
  8. 字段命名 : 非公有的,非静态字段以m开头,静态变量以s开头 。
  9. 括号 :开括号不要独占一行
  10. 注解 :使用标准的注解。
  11. Acronyms are words : Treat acronyms as words in names, yielding XmlHttpRequest , getUrl() , etc.
  12. TODO的风格 :“TODO:在这里写描述”
  13. 一致性 :看看你周围的
  14. 日志记录 :小心日志记录,它开销很大。

Javatests样式规则

1. 测试方法的命名 :testMethod_specificCase是正确的

用C++写ruby扩展

为了测试CDMA短信的发送方便,于是想到编译成lib,提供ruby使用。

SmsObject.h:
void SendSms(const char* msg, const char* number, char* out);

main.cpp:

//
// by deli 2009.6.11
//
#include <ruby.h>
#include "SmsObject.h"

static VALUE makepdu(VALUE self, VALUE arg1, VALUE arg2) {
    VALUE s;
    char pdu[512] = {0};
    char* msg = RSTRING(arg1)->ptr;
    char* number = RSTRING(arg2)->ptr;

    SendSms(msg, number, pdu);
    s = rb_str_new2(pdu);

    return s;
}

extern "C"
void __declspec(dllexport) Init_sms() {
    VALUE myModule = rb_define_module("CDMA");

    VALUE myClass = 
        rb_define_class_under(myModule, "SMS", rb_cObject);

    int arg_count = 2;
    rb_define_method(myClass, "makepdu", RUBY_METHOD_FUNC(makepdu), arg_count);
}

注意: C++要加上RUBY_METHOD_FUNC, C不用加。不然就会出现类似的错误:
error C2664: ‘rb_define_method’ : cannot convert parameter 3 from
‘unsigned long (unsigned long,unsigned long,unsigned long)’ to ‘unsigned long (_
_cdecl *)(…)’
None of the functions with this name in scope match the target type

test.rb:

#!/usr/bin/ruby 

require 'sms'

include CDMA

obj = SMS.new
pdu = obj.makepdu('什么都可以想,什么都可以不想,便觉得是个自由的人', '15338896034')

puts pdu

D:\Ruby\ruby-serial\sms>ruby test.rb
0000021002040702c54ce225a8d008420003200000013220c27602724487ea9f7a772b079ff86276
02724487ea9f7a772a706b079ff8627dfc4e4afcbb317a71540f53a98bb42275d00501a70801c00d
0101

大概就是这样。

用gsmmux 测试via cdma多路复用功能

现在杭州的威盛已实现了GSM协议07.10 multiplexer。
gsmmux 可以在 developer.berlios.de/projects/gsmmux/ 上获得.按照说明安装就可以了。
代码默认用的是AT+CMUX开启功能,而CMUX在CDMA另有别用,所以他们就用VMUX来替代,在代码里,把CMUX改为VMUX,重新编译。

运行 mux,得到两个虚拟逻辑串口 /dev/mux0 /dev/mux1,
开一个终端1 cat /dev/mux0 观察数据
再开一个终端2输入 echo -e “AT\r\n” > /dev/mux0
终端1有 “OK” 响应就行了。
同样的方法测试 mux1.

核心代码在 gsm0710.c

简单说明一下。
1190 行的 main函数,读取命令行参数,
1272 行 daemonize(_debug) 设置为unix下经典后台程序,下来是设置信号中断机制。

openDevicesAndMuxMode 函数 打开modem 初始化,发 “AT+VMUX=0” 进入mux模式。

MUX启动过程
主机发: AT+VMUX=0
模块回复:OK /*进入MUX模式*/
主机发: F9033F011CF9 /*建立DLC0*/
模块回复:F9037301D7F9
主机发: F9073F01DEF9 /*建立DLC1*/
模块回复:F907730115F9
F901EF09E305070D9AF9 /*DLC1 MSC 命令*/
主机发: F90B3F0159F9 /*建立DLC2*/
模块回复:F90B730192F9
F901EF09E3050B0D9AF9 /*DLC2 MSC 命令*/

/*…开始进行MUX协议的数据传输…*/

在 1106行的openDevicesAndMuxMode,
三次(一般是三次,可以设置)打开 /dev/ptmx ,得到三对主从终端,通过符号链接,创建两个虚拟串口

/dev/mux0 /dev/mux1 这时就可以像正常访问串口一样访问它们,一般 /dev/mux0
用来专门发AT, /dev/mux1 用来发送数据业务,比如pppd 拨号上网。

数据流大概是这样的
/dev/ttyS0 <---> | /dev/pmux <----> /dev/mux0 | <----> at command
/dev/ttyS0 <---> | /dev/pmux <----> /dev/mux1 | <----> cdma pppd

下面
1162行 – 1166行
for (i = 1; i <= numOfPorts; i++)
{
sleep(1);
write_frame(i, NULL, 0, SABM | PF);
syslog(LOG_INFO, "Connecting %s to virtual channel %d on %s\n", ptsname(mux_fd[i-1]), i, serportdev);
}

write_frame(i, NULL, 0, SABM | PF); 实现的就是发
F9033F011CF9 /*建立DLC0*/
F9073F01DEF9 /*建立DLC1*/
F90B3F0159F9 /*建立DLC2*/

然后进入 while循环,用selelct 实现 i/o 多路复用,
(1)检查物理串口,如果有可读的数据,读取放到buffer,然后解析数据帧,并发送到虚拟逻辑串口
(2)检查虚拟逻辑串口,如果有可读的数据,构造数据帧,写入物理串口。

就这样,基本原理是数据分组打包与解包。

在MTK平台上部署CDMA

原文在 2009/10/14 发表于broncho论坛,转载请写出处,谢谢!

在MTK平台上部署CDMA

[注] 我们用的MTK版本是6225 ,CDMA 模组是威盛via的。此项目没有量产,代码放在那也是加密冷藏没有价值,写思路出来与大家讨论关于程序设计。本人不是MTK专家,有分析不对之处,请指出,谢谢。

[硬件篇]
加一个cdma模组,具体操作本人不知道,就不讲述了。

[软件篇]
让我们来分析一下。既然在MTK平台,上层应用最好不要改动,就只能在底层修改。在L4层我们发现,MTK提供了mmi接口,那么我们就有机会重写这些函数,这个就是最大前提。对于CDMA,要对AT做封装,适配于L4(适配器设计模式)。我们可以开一个task,专门处理CDMA AT,串口数据的读取。考虑到CDMA的AT比较弱,特别是三方通话,呼叫保持,对AT的处理,得用较多全局变量来保存上下文。

代码目录:

代码: 全选
Vendor -|
|- ATCMD -| at_cdma
| at_gsm
| at_l4a
| at_thread

At_thread 主要是处理AT的线程.
首先创建一个task.
/* task */
void AT_Cmd_main(task_entry_struct * task_entry_ptr); 一个while 循环,处理消息。

At_gsm 是一个参考物,为了测试cdma方便,我们自己实现MTK的AT封装。At_cdma 是cdma编解码目录。可以说,at_cdma继承于at_gsm,两者有统一的接口(主要是gsm标准,cdma适应于gsm),所以很多的工作,在at_cdma做了很大的调动。如果实现和gsm不一样,我们就要rewrite接口实现,基于函数替换。

上面已有提到过,我们要重新实现mtk提供的l4a层,那么at_l4a 就是干这样的活了。为了不直接在mtk l4a的函数里修改,我们采用include 的方式。所有的处理函数放在AT_L4c_Funs_V07B.c
写我们自己的 l4a_callback_ex.c ,在ps\l4a\src\l4a_callback.c 的末尾 #include “l4a_callback_ex.c” ,然后在 l4a_main.c的 l4a_recvmsg(ilm_struct *ilm_ptr)里加以区别:如果 l4c_current_mod_id == l4c_atcmd_mod_id,就调用我们实现的接口函数处理cdma,否则,就调用mtk提供的处理gsm(不变)。

串口通讯的处理
利用w32_uart.c 里提供的一些函数,打开串口,设置波特率,数据控制流等参数。
对数据的发送,接收,加入休眠模式,以免功耗过大。

AT的处理
在MTK上对CDMA AT的处理,则采用赤裸裸的封装,源于有开发过Firebird BBS的经历,我更喜欢这种最原始的美,不要和我谈什么软件架构,设计模式的,考虑越多,项目越难以进展,领导只关心是否能跑起来,不然项目取消,大家散伙吧。说远了。AT具有随意性,我们假设发出请求的AT,就有相应的响应,设一个定时器,来处理超时问题。如果超时了,我们再发AT,如果有OK回应,就说明模组还能正常工作,那么这个AT的请求就是失败的。对自动上报的消息的处理,在获取AT响应时,我们判断是自动上报的消息,则当场处理,继续读下一行数据,直到有期望的响应值。如果请求发出一个AT, 既有自动上报消息,又有自身的请求响应,该如何处理呢?举个例子,查询网络注册情况,发出AT+CREG?后,
+CREG:1,0×3614,0x2

+CREG:1,0×3614,0x2

+CREG: 2,1,0x00C3,0x00AD

我们发现,请求的响应有4个参数,而自动上报的有三个参数。再举个例子:
开机时,模块会自动开启一个15min的计时器,如果15分钟内没有收到AT+LCT指令,模块就自动关机,如果收到了该指令,15min的计时器又重新开始计时。所以我们看到+LCT主动上报时,就发出AT+LCT。问题来了,我们打电话时,查询CLCC,那么问题出现如下:
AT+CLCC?
+LCT
AT+LCT
+CLCC:1,0,1
ok
ok

两个响应消息交错在一起,就难以分析了,我们就得保证消息串化。
等等。AT响应的处理,大部分工作是解析字符串,取出你想得到的数据,填充结构体。总之,在做AT处理时,要反复测试,考虑很多的异常,这便是软件设计的难点之一。

AT层上GSM 与CDMA的差异
就列举几个比较重要的差别,很多小细节还是非常多的,请参阅厂家的AT SPEC。
(1)AT测试命令,比如信号查询 GSM是AT+CSQ;CDMA则是 AT+CSQ? 很多种情况如此,CDMA在后面要加上一个“?”号。
(2)AT响应字符串
比如, GSM:
+CCLK: “04/01/19,15:38:32″
+CCLK:后面有空格
CDMA:
+CCLK:2008/8/6,13:57:5,3
+CCLK: 后面没有空格
响应字符串解析函数必须能处理空格问题。可以写一个类似于sscanf的函数,专用解析AT响应字符串。
(3) CDMA中”UIM”的字符串,这个主要出现在电话本与短信。MTK上是”SIM” 对应 0, “ME”对应1;CDMA把”UIM”对应为0即可。此外,短信与电话本,gsm从1开始读取,cdma则从0开始读。
(4) TE特征字符串设定
GSM: AT+CSCS
CDMA没有这方面的设定,默认为UNICODE,在电话本处理中,AT请求和响应要特别指出.
(5) 短信的PDU编解码完全不同.请参考 GSM0707与3gpp2 的C.S0015-B
(6) 电话状态查询CLCC,CDMA提供的功能很弱,不管有没有来电,拨出电话,查询CLCC总有一个+CLCC:响应,GSM则不然。CDMA处于三方通话,呼叫保持,呼叫等待时,查询CLCC也是只有一路+CLCC:响应,这样,我们得自己构建适应于GSM的CLCC,维护,更新CLCC列表。

开关机流程
(1)开机
+VPUP
模块上报开机启动标志,也可根据该命令判断模块重启,收到该命令后进行初始化设置. (模组有问题时,这个上报是不可靠的.)
+MSStatus:0
模块上报协议栈已打开。
+VROM:1
模块上报漫游状态(1 为非漫游状态)。 这个上报是不可靠的,就是说,并不是每次开机都会有这个上报。不过,如果出现这个,我们认为可以显示中国电信了,其他手机已开机就显示运营商,估计也是照这个来做。

AT+ISF?
查询模块初始化状态,2s~3s 执行一次
+ISF:1
模块初始化完成。

接下来才可以对电话本,短信,通话记录初始化。

由上,在+MSStatus:0与 +ISF:1之间,可以操作的行为有:
(0)ATE0 软件已经默认关闭回显,该步骤可省。
(1)注册网络与信号上报. AT+CREG=2 AT+ARSI=1
(2)查询UIM是否插好?AT+CPIN?
(3)查询信号 AT+CSQ?
(4)查询国家码,网络码 AT+VMCC? AT+VMNC?
(5)选择语音通道 AT+SPEAKER=0

开机流程比较繁琐,要适应与MTK的启动流程,比如开启Pin码,手机密码,网络运营商的获取,信号强度上报等。一般情况下,模块加电后会自行开启协议栈。不插UIM卡启动,模块不会自行打开协议栈。需要输入PIN的情况下,只有在用户输入正确的PIN,模块才会开启协议栈。在以上任何情形下开机,模块都会上报(+VPUP),客户可以根据此上报来判断正常使用中的模块是否重启。
(2)关机:
由于关机需要在网络上进行一些登记操作,因此正常的关机步骤是建议+CPOF关闭协议栈后延迟一段时间断电。
(3)飞行模式:
模块实现飞行模式可以直接使用+CPOF关闭协议栈,+CPON打开协议栈返回正常模式。
查询当前是否在飞行模式:+VPON.

细节:
长短信的发送:
Cdma不能无缝的发送长短信,一般要等到 +CDS:上报才能发出下一条,一般情况下,发出一条短信过4-5秒后就有+CDS上报,不过,如果发给自己的话,这个时间会更长,我们采用延时30秒。一般如果发多条短信,第二条一般会返回+CDS:2,2,66 ,就是说,发不成功。我们要把它保存起来,重发一次。

结尾
当然,要做到符合最新电信需求规范,就比较困难了。MTK本是在GSM协议上做起来的,GSM于CDMA本来就存在很大的差别。说不定过不久MTK会发布C+G的版本,啥东西人家都帮你弄好了,就等着只改界面换个图片铃声吧。

Pages: 1 2 Next