在源码下写程序可以摆脱SDK的限制,毕竟SDK开放的API有限,比如我们实现模拟按键时,需要用到IWindowManager这个类,但是SDK中是不提供这个类的。
首先下载编译源码,然后在源码的frameworks/base/cmds下新建一个文件夹作为你新扩展模块的一个目录。比如叫做autotest,在autotest下创建一个java文件,比如AutoTest.java。编写你的程序代码,在此你可以使用IWindowManager类,在此,我模拟了按键key,长按键keypress,点触笔touch,点触笔长按touchpress,以及移动move等,代码如下:
import android.view.MotionEvent; import android.view.KeyEvent; import android.view.IWindowManager; import android.os.ServiceManager; import android.os.SystemClock; import android.os.RemoteException; import android.util.Log; public class AutoTest { public static void main(String args[])throws Exception { String[] mArgs = args; try { String opt = mArgs[0]; if(opt.equals("touch")) { float x = Float.valueOf(mArgs[1]); float y = Float.valueOf(mArgs[2]); MotionEvent e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0); sendPointerSync(e); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0); sendPointerSync(e); } else if(opt.equals("move")) { float x = Float.valueOf(mArgs[1]); float y = Float.valueOf(mArgs[2]); float x2 = Float.valueOf(mArgs[3]); float y2 = Float.valueOf(mArgs[4]); MotionEvent e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0); sendPointerSync(e); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, x, y, 0); sendPointerSync(e); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, x, y, 0); sendPointerSync(e); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, x2, y2, 0); sendPointerSync(e); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, x2, y2, 0); sendPointerSync(e); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x2, y2, 0); sendPointerSync(e); } else if(opt.equals("key")) { int keycode = Integer.valueOf(mArgs[1]); KeyEvent k = new KeyEvent(KeyEvent.ACTION_DOWN,keycode); sendKeySync(k); k = new KeyEvent(KeyEvent.ACTION_UP,keycode); sendKeySync(k); } else if(opt.equals("wait")) { int millsecond = Integer.valueOf(mArgs[1]); Thread.sleep(millsecond); } else if(opt.equals("keypress")) { int keycode = Integer.valueOf(mArgs[1]); int millsecond = Integer.valueOf(mArgs[2]); KeyEvent k = new KeyEvent(KeyEvent.ACTION_DOWN,keycode); sendKeySync(k); Thread.sleep(millsecond); k = new KeyEvent(KeyEvent.ACTION_UP,keycode); sendKeySync(k); } else if(opt.equals("touchpress")) { float x = Float.valueOf(mArgs[1]); float y = Float.valueOf(mArgs[2]); int millsecond = Integer.valueOf(mArgs[3]); MotionEvent e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0); sendPointerSync(e); Thread.sleep(millsecond); e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0); sendPointerSync(e); } else System.err.println("** Error: Unknown option: " + opt); } catch (RuntimeException ex){} Thread.sleep(2000); } private static void sendPointerSync(MotionEvent event) { try { (IWindowManager.Stub.asInterface(ServiceManager.getService("window"))).injectPointerEvent(event, true); } catch (RemoteException e) {} } private static void sendKeySync(KeyEvent event) { try { (IWindowManager.Stub.asInterface(ServiceManager.getService("window"))).injectKeyEvent(event, true); } catch (RemoteException e) {} } }在与java文件同级创建Android.mk文件,内容如下:
# Copyright 2008 The Android Open Source Project LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ AutoTest.java LOCAL_MODULE := autotest LOCAL_MODULE_TAGS := eng include $(BUILD_JAVA_LIBRARY)
//**********************************Android.mk 文件详解
1、LOCAL_PATH:一个Android.mk 首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk文件的目录)。
2、CLEAR_VARS 由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
3、LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'HcSyncml'的共享库模块,将会生成'libHcSyncml.so'文件。
4、LOCAL_C_INCLUDES := $(LOCAL_PATH)/extra_inc$(LOCAL_PATH)/main_inc4、
LOCAL_C_INCLUDES 中加入所需要包含的头文件路径【针对C文件来说的】
5、 LOCAL_SRC_FILES: LOCAL_SRC_FILES中加入源文件路径(需要编译的文件),多个文件用 ‘\’ 隔开//**************************************
在终端命令行下进入autotest文件夹,输入mm命令,如果报错,则返回Android源码主目录,输入如下命令:
. build/envsetup.sh# Script to start "monkey" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/autotest.jar
exec app_process $base/bin AutoTest $*
将autotest文件放在/system/bin下,用chmod修改文件属性(777)===========================================================
以上过程中出现的问题解析:
一、/system没有空间:
1、启动模拟器时,用命令 android sdk tools目录下 emulator -avd my_avd -partition-size 512 启动后 system目录的空间就变为了512M
2、获得root权限 adb root
3、设置/system为可读写 adb remount //解决可读写的问题
二、启动emulator时 ,有如下 错误提示
ERROR: You did not specify a virtual device name, and the system
directory could not be found.
If you are an Android SDK user, please use '@<name>' or '-avd <name>'
to start a given virtual device (see -help-avd for details).
Otherwise, follow the instructions in -help-disk-images to start the emulator
原因是你没有建立avd,建立方法如下:
1、终端中输入 ./android 执行该脚本,启动 Android SDK Manager -> Tools -> Manage AVDs -> 打开 Android Virtual Device Manager 后,新建一个avd,然后再执行emulator -avd my_avd -partition-size 512 便可正常。
三、在tools目录下,用adb push 把相应的文件push到指定目录下,便可在emulator下的shell中执行autotest key 24命令,把指定的键值推送给android系统了。
adb push /home/yinjk/Android/Android-source-code/djasdjaskdj/autotest /system/bin/