Google C++ Style Guide
jQuery Mobile: Touch-Optimized Web Framework for Smartphones & Tablets
Google JavaScript Style Guide
Android APK反编译
Run native executable in Android App
Android面面观——Android事件处理下(按键、触摸屏和滚动球的一些实现细节)
JNI 函数
在frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文 件中,向 JAVA提供了函数android_server_KeyInputQueue_readEvent,用于读 取输入设备事件。
- static jboolean
- android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
- jobject event)
- {
- gLock.lock();
- sp hub = gHub;
- if (hub == NULL) {
- hub = new EventHub;
- gHub = hub;
- }
- gLock.unlock();
- int32_t deviceId;
- int32_t type;
- int32_t scancode, keycode;
- uint32_t flags;
- int32_t value;
- nsecs_t when;
- bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
- &flags, &value, &when);
- env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
- env->SetIntField(event, gInputOffsets.mType, (jint)type);
- env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
- env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
- env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
- env->SetIntField(event, gInputOffsets.mValue, value);
- env->SetLongField(event, gInputOffsets.mWhen,
- (jlong)(nanoseconds_to_milliseconds(when)));
- return res;
- }
readEvent调用hub->getEvent读了取事件,然后转换成JAVA的结构。
事件中转线程
在frameworks/base/services/java/com/android/server/KeyInputQueue.java 里创建了一个线程,它循环的读取事件,然后把事件放入事件队列里。
- Thread mThread = new Thread("InputDeviceReader") {
- public void run() {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
- try {
- RawInputEvent ev = new RawInputEvent();
- while (true) {
- InputDevice di;
- readEvent(ev);
- send = preprocessEvent(di, ev);
- addLocked(di, curTime, ev.flags, ..., me);
- }
- }
- };
输入事件分发线程
在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。
- mQueue.getEvent
- dispatchKey/dispatchPointer/dispatchTrackball
按键,触摸屏流程分析
按键触摸屏流程分析:
WindowManagerService类的构造函数
WindowManagerService()
mQueue = new KeyQ();
因为 WindowManagerService.java (frameworks\base\services\java\com\android\server)中有:
private class KeyQ extends KeyInputQueue
KeyQ 是抽象类 KeyInputQueue 的实现,所以 new KeyQ类的时候实际上在 KeyInputQueue 类中创建了
一个线程 InputDeviceReader 专门用来冲设备读取按键事件,代码:
Thread mThread = new Thread("InputDeviceReader") {
public void run()
{
在循环中调用:readEvent(ev);
...
send = preprocessEvent(di, ev);
实际调用的是 KeyQ 类的 preprocessEvent 函数
...
int keycode = rotateKeyCodeLocked(ev.keycode);
int[] map = mKeyRotationMap;
for (int i=0; i<N; i+=2)
{
if (map[i] == keyCode)
return map[i+1];
} //
addLocked(di, curTime, ev.flags,RawInputEvent.CLASS_KEYBOARD,newKeyEvent(di, di.mDownTime, curTime, down,keycode, 0, scancode,...));
QueuedEvent ev = obtainLocked(device, when, flags, classType, event);
}
}
readEvent() 实际上调用的是 com_android_server_KeyInputQueue.cpp (frameworks\base\services\jni)中的:
static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,jobject event)
bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,&flags, &value, &when);
调用的是 EventHub.cpp (frameworks\base\libs\ui)中的:
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen)
在函数中调用了读设备操作:res = read(mFDs[i].fd, &iev, sizeof(iev));
在构造函数 WindowManagerService()调用 new KeyQ() 以后接着调用了:
mInputThread = new InputDispatcherThread();
...
mInputThread.start();
来启动一个线程 InputDispatcherThread
run()
process();
QueuedEvent ev = mQueue.getEvent(...)
因为WindowManagerService类中: final KeyQ mQueue;
所以实际上 InputDispatcherThread 线程实际上从 KeyQ 的事件队列中读取按键事件。
switch (ev.classType)
case RawInputEvent.CLASS_KEYBOARD:
...
dispatchKey((KeyEvent)ev.event, 0, 0);
mQueue.recycleEvent(ev);
break;
case RawInputEvent.CLASS_TOUCHSCREEN:
//Log.i(TAG, "Read next event " + ev);
dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
break;
===============================================================
KeyInputQueue.java (frameworks\base\services\java\com\android\server):
的线程 Thread mThread = new Thread("InputDeviceReader") 本地调用:
readEvent(ev);读取按键。readEvent 调用的是文件:
com_android_server_KeyInputQueue.cpp (frameworks\base\services\jni)中的函数:
static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
jobject event)
android_server_KeyInputQueue_readEvent中有:
hub = new EventHub;
bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
&flags, &value, &when);
hub->getEvent 调用的是
EventHub.cpp (frameworks\base\libs\ui) 文件中的函数:
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen)
读取按键。
class RefBase::weakref_impl : public RefBase::weakref_type
在系统启动后,android 会通过
static const char *device_path = "/dev/input";
bool EventHub::openPlatformInput(void)
res = scan_dir(device_path);
通过下面的函数打开设备。
int EventHub::open_device(const char *deviceName)
{
...
fd = open(deviceName, O_RDWR);
...
mFDs[mFDCount].fd = fd;
mFDs[mFDCount].events = POLLIN;
...
ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
...
const char* root = getenv("ANDROID_ROOT");
snprintf(keylayoutFilename, sizeof(keylayoutFilename),
"%s/usr/keylayout/%s.kl", root, tmpfn);
...
device->layoutMap->load(keylayoutFilename);
...
}
打开设备的时候,如果 device->classes&CLASS_KEYBOARD 不等于 0 表明是键盘。
常用输入设备的定义有:
enum {
CLASS_KEYBOARD = 0x00000001, //键盘
CLASS_ALPHAKEY = 0x00000002, //
CLASS_TOUCHSCREEN = 0x00000004, //触摸屏
CLASS_TRACKBALL = 0x00000008 //轨迹球
};
打开键盘设备的时候通过上面的 ioctl 获得设备名称,命令字 EVIOCGNAME 的定义在文件:
kernel/include/linux/input.h 中。
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
在内核键盘驱动文件 drivers/input/keyboard/pxa27x_keypad.c 中定义了设备名称:pxa27x-keypad
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = __devexit_p(pxa27x_keypad_remove),
.suspend = pxa27x_keypad_suspend,
.resume = pxa27x_keypad_resume,
.driver = {
.name = "pxa27x-keypad",
.owner = THIS_MODULE,
},
};
ANDROID_ROOT 为环境变量,在android的命令模式下通过 printenv 可以知道它为: system
所以 keylayoutFilename 为:/system/usr/keylayout/pxa27x-keypad.kl
pxa27x-keypad.kl 定义了按键映射,具体内容如下:
----------------------
# NUMERIC KEYS 3x4
key 2 1
key 3 2
key 4 3
key 5 4
key 6 5
key 7 6
key 8 7
key 9 8
key 10 9
key 11 0
key 83 POUND
key 55 STAR
# FUNCTIONAL KEYS
key 231 MENU WAKE_DROPPED
key 192 BACK WAKE_DROPPED
key 193 HOME WAKE
key 107 DEL WAKE
key 102 CALL WAKE_DROPPED
key 158 ENDCALL WAKE_DROPPED
key 28 DPAD_CENTER WAKE
key 115 VOLUME_UP
key 114 VOLUME_DOWN
----------------------
如果没有定义键盘映射文件,那么默认使用系统的 /system/usr/keylayout/qwerty.kl
可以修改 /system/usr/keylayout/qwerty.kl 文件改变Android公司的按键映射。
device->layoutMap->load(keylayoutFilename) 调用的是文件:
KeyLayoutMap.cpp (frameworks\base\libs\ui)中的函数:
status_t KeyLayoutMap::load(const char* filename)通过解析 pxa27x-keypad.kl
把按键的映射关系保存在 :KeyedVector<int32_t,Key> m_keys; 中。
当获得按键事件以后调用:
status_t KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags)
由映射关系 KeyedVector<int32_t,Key> m_keys 把扫描码转换成andorid上层可以识别的按键。>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
很给力的一个纯JS的图表库Highcharts
What is Highcharts?
Highcharts is a charting library written in pure JavaScript, offering an easy way of adding interactive charts to your web site or web application. Highcharts currently supports line, spline, area, areaspline, column, bar, pie and scatter chart types.
Compatible
It works in all modern browsers including the iPhone/iPad and Internet Explorer from version 6. Standard browsers use SVG for the graphics rendering. In Internet Explorer graphics are drawn using VML.
Pure JavaScript
Highcharts is solely based on native browser technologies and doesn't require client side plugins like Flash or Java. Furthermore you don't need to install anything on your server. No PHP or ASP.NET. Highcharts needs only two JS files to run: The highcharts.js core and either the jQuery or the MooTools framework. One of these frameworks is most likely already in use in your web page.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Android开发环境搭建
Android这几年发展迅猛,系统越来越稳定,强大.同时,越来越多的手机都搭上这个免费开源的系统.
最近也在入手一台Android2.1手机, 所以也开始尝试一下Android的开发. 下面是一个简单的环境搭建过程.
Android的开发语言是Java(个人认为,主要是采用了Java的语法, 因为Google为Android编写了一个特别的虚拟机, 程序的框架和运行方式,也与传统Java不太一样). 开发环境主要是使用Eclipse+Android插件的形式。
由于需要安装Eclipse,所以PC端的Java环境是必不可少的,同时,为了编译和运行Android模拟器,Android SDK也需要安装。(来源:http://www.eit.name 转载请注明)
以下大体步骤:
1. 安装JDK
到Oracle的Java官方,直接下载Windows的安装包,运行安装程序,根据提示完成即可。
http://www.oracle.com/technetwork/java/javase/downloads/jdk6-jsp-136632.html
2. 安装Eclipse
到Eclipse的下载官方: http://www.eclipse.org/downloads/
下载“Eclipse Classic 3.6.1”,解压即可。双击eclipse文件夹中的eclipse.exe程序即可。
3. 安装Android SDK
到Android开发官方: http://developer.android.com/sdk 下载sdk installer,根据提示安装即可。
安装完后,运行SDK Manager下载和安装2.1, 2.2等sdk.
(可恶的是,这网站被墙了。)
4. 安装ADT (https://dl-ssl.google.com/android/eclipse/)
运行Eclipse,打开Help=>Install New Software...菜单, 添加一个新站点ADT,网址为:
https://dl-ssl.google.com/android/eclipse/
再从此站点下载和安装ADT。
5. Eclipse中配置sdk
在Eclipse中,打开Window=>Preferences,在左边找到Android,并配置好SDK的根目录。
打开Window=>Android SDK and AVD Manager,创建一个相应版本的AVD。
6. 开始第一个程序
在Eclipse,打开File=>New=>Project, 开始你的Android开发之旅吧。
C++和Java的语法对比手册
首先,两件大事-主函数和怎样编译,下面是它们的小差别:
主函数
C++
// 自由函数
int main( int argc, char* argv[])
{
printf( "Hello, world" );
}
Java
// 每个函数必须是类成员;当java类运行时类中的主函数就会被调用
//(所以你可以为每个类写一个主函数--这样用于给类写单元测试时会很方便)
class HelloWorld
{
public static void main(String args[])
{
System.out.println( "Hello, World" );
}
}
编译
C++
// 编译
g++ foo.cc -o outfile
// 运行
./outfile
Java
// 编译在foo.java里的类成为<类名>.class
javac foo.java
// 调用<类名>中的静态main函数
java <classname>
注释
两种语言完全相同 (// 和 /* */ 都能工作)
类声明
大部分一样,除了Java不要求后面有个分号
C++
class Bar {};
Java
class Bar {}
方法声明
基本相同,除了Java中必须是类成员并且可能有public/private/protected前缀之外。
构造和析构
构造语法相同,Java没有析构的等价物。
静态成员函数和变量
方法声明方式相同,不过Java提供了static initialization blocks 来初始化静态变量(代替在源码文件中放定义):
class Foo
{
static private int x;
// static initialization block
{ x = 5; }
}
对象声明
C++
// 栈对象
myClass x;
// 堆对象
myClass *x = new myClass;
Java
// 总是分配在堆上(而且,构造总是要写括号)
myClass x = new myClass();
引用vs.指针
C++
// 引用是不可改的,使用指针能得到更大的弹性
int bar = 7, qux = 6;
int& foo = bar;
Java
// 引用是可改的,它仅存放对象的地址。没有原生指针。
myClass x;
x.foo(); // 错误,x是空“指针”
// 注意Java里总是使用 . 存取域
继承
C++
class Foo : public Bar
{ ... };
Java
class Foo extends Bar
{ ... }
保护级别
C++
public:
void foo();
void bar();
Java
public void foo();
public void bar();
虚函数
C++
virtual int foo();
Java
// 函数默认就是虚函数;使用final防止被重载
int foo();
抽象类
C++
// 只要包含一个纯虚函数
class Bar { public: virtual void foo() = 0; };
Java
// 可以用语法直接定义
abstract class Bar { public abstract void foo(); }
// 或者指定为接口
interface Bar { public void foo(); }
// 然后,用一个类实现implement
它:
class Chocolate implements Bar
{
public void foo() { /* do something */ }
}
内存管理
大致相同--new 分配, 不过因为Java著名的垃圾回收机制所以没有delete 。
NULL vs. null
C++
// 初始化指针为NULL
int *x = NULL;
Java
// 使用未初始化的引用会被计算机捕获,不过可以赋值为null指明引用为无效。
myClass x = null;
布尔值
Java要长一点,你得写boolean来代替简短的bool。
C++
bool foo;
Java
boolean foo;
常量
C++
const int x = 7;
Java
final int x = 7;
Throw说明
首先, Java在编译时强制要求有throw说明-如果一个方法要抛出一个异常你必须先说明它
C++
int foo() throw (IOException)
Java
int foo() throws IOException
数组
C++
int x[10];
// 或者
int *x = new x[10];
// 使用x然后收回内存
delete[] x;
Java
int[] x = new int[10];
// 使用x,内存由垃圾回收机制回收
集合和迭代
C++
迭代器是类成员,一个范围起始于<container>.begin(), 终止于<container>.end(). 使用++操作前进,使用*存取。
vector myVec;
for ( vector<int>::iterator itr = myVec.begin();
itr != myVec.end();
++itr )
{
cout << *itr;
}
Java
迭代器仅仅是一个接口。一个范围起始于<collection>.iterator, 接着使用itr.hasNext()检查确认是否已到末尾。使用itr.next()取得下一个数据。
ArrayList myArrayList = new ArrayList();
Iterator itr = myArrayList.iterator();
while ( itr.hasNext() )
{
System.out.println( itr.next() );
}
// 在Java 5中:
ArrayList myArrayList = new ArrayList();
for( Object o : myArrayList ) {
System.out.println( o );
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Export sms for wm6(with filter),短信导出工具
最近入手一台wm6.5的山寨机, 待机时间很长, 一般能达到4天左右, 运行速度也很快, 大体上比较满意, 唯一遗憾的地方是短信功能较弱, 阅读和删除都不方便, 更为变/态的是几乎所有第三方短信软件都无法正常运行,接管不了系统的短信. 我原来购买此机的初衷就是希望可以创建短信文件夹并自动归类,因为公司的报警短信太多, 以致于经常把个人短信淹没.
多次尝试无果后, 最终打算自己写个小程序来解决此问题, 今天花了一整天时间终于搞定, 原来是计划用POOM来读写短信的,后来发现好象没有对应的API,最终使用了MAPI .net来访问短信.开发环境是Visual Studio 2008(C#) + Windows Mobile Sdk 6.0,运行时需要在wm6.5上面安装.NET CF 3.5
此软件的作用是将系统短信导出到文本文件,可导出所有短信,也可以根据多个发件人来导出,导出后可删除原短信.
以下是截图和功能说明:
a.第一个区域,用于需导出的发件人列表,默认只导出这些号码发送的短信
b.第二个区域,用于配置导出的目的文件夹, 文件以YYYYMMDDHHmmss.txt命名
c.勾选"导出所有短信",由忽略第一个区域的发件人配置.
有需要的朋友,可以在本站下载,如果不会使用或对源码有兴趣的,可以给我发邮件.
理论上应该支持wm6.0, 但我本人并没有测试.
[file]attachment/201006/smsexport.zip[/file]
Export sms for wm6(with filter).
题外话:Visual Studio + C# + MSDN确实不错,几年没用也很容易上手.