android系统学习笔记四
Android 的GUI 系统
Android GUI 系统综述
C 语言部分包括:
pixelFlinger(下层工具库)
头文件/system/core/include/pixelflinger 其生成的动态库libpixelflinger.so 只连接
C语言库libcutils
Format.h提供像素格式的定义,
Pixelflinger.h提供接口功能的定义
源代码/system/core/libpixelflinger
Libui(GUI的框架库)
头文件: /system/core/libpixelflinger/ui
源代码: /frameworks/base/libs/ui
编译后生成 libui.so 连接libpiselflinger.so
包含了颜色格式 头文件:pixelformat.h point.h region.h rect.h displayinfo.h
egl窗口(用于显示)
按健及事件处理(key/Event)头文件:eventhub.h keycodelabels.h
keycharactermap.h
Suface(显示界面)
overlay(显示叠加层接口) iOverlay.h Overlay.h
camera(照像机接口)
SurfaceFlinger(surface的管理和处理)
Skia图形图像引擎
OpenGL 3D 引擎
各种JNI接口
GUI系统的几个本地库中, libui是提供接口的框架库, 所涉及的java 框架层的主要内容:
Android.graphics(对应Skia底层库,提供绘图接口)
Android .view.surface(构建显示界面)
Android .view.view( 各种UI元素有基类)
Javax.microdition.khronos.opengles(标准OpenGL接口)
输入/输出与硬件的接口
显示输出的硬件接口
对于android 的显示部分,需要实现的接口是: egl_mative_window_t (是一个OPENGL结构)
也给libEGL使用
输入的硬件接口
向上层提供统一的按键码(keyCode),这个按键码是一个整数,在libui中,通过标准的input
驱动 来处理input的值转按成android系统的按键码,按键码参考KeyCharacterMap.h
/frameworks/base/include/ui/ KeycodeLabels.h 按键码的对照
struct KeycodeLabel {
const char *literal;
int value;
};
static const KeycodeLabel KEYCODES[] = {
{ "SOFT_LEFT", 1 },
{ "SOFT_RIGHT", 2 },
{ "HOME", 3 },
{ "BACK", 4 },
{ "CALL", 5 },
{ "ENDCALL", 6 },
{ "0", 7 },
{ "1", 8 },
{ "2", 9 },
{ "3", 10 },
{ "4", 11 },
{ "5", 12 },
{ "6", 13 },
{ "7", 14 },
{ "8", 15 },
{ "9", 16 },
{ "STAR", 17 },
{ "POUND", 18 },
{ "DPAD_UP", 19 },
{ "DPAD_DOWN", 20 },
{ "DPAD_LEFT", 21 },
{ "DPAD_RIGHT", 22 },
{ "DPAD_CENTER", 23 },
{ "VOLUME_UP", 24 },
{ "VOLUME_DOWN", 25 },
{ "POWER", 26 },
{ "CAMERA", 27 },
{ "CLEAR", 28 },
{ "A", 29 },
{ "B", 30 },
{ "C", 31 },
{ "D", 32 },
{ "E", 33 },
{ "F", 34 },
{ "G", 35 },
{ "H", 36 },
{ "I", 37 },
{ "J", 38 },
{ "K", 39 },
{ "L", 40 },
{ "M", 41 },
{ "N", 42 },
{ "O", 43 },
{ "P", 44 },
{ "Q", 45 },
{ "R", 46 },
{ "S", 47 },
{ "T", 48 },
{ "U", 49 },
{ "V", 50 },
{ "W", 51 },
{ "X", 52 },
{ "Y", 53 },
{ "Z", 54 },
{ "COMMA", 55 },
{ "PERIOD", 56 },
{ "ALT_LEFT", 57 },
{ "ALT_RIGHT", 58 },
{ "SHIFT_LEFT", 59 },
{ "SHIFT_RIGHT", 60 },
{ "TAB", 61 },
{ "SPACE", 62 },
{ "SYM", 63 },
{ "EXPLORER", 64 },
{ "ENVELOPE", 65 },
{ "ENTER", 66 },
{ "DEL", 67 },
{ "GRAVE", 68 },
{ "MINUS", 69 },
{ "EQUALS", 70 },
{ "LEFT_BRACKET", 71 },
{ "RIGHT_BRACKET", 72 },
{ "BACKSLASH", 73 },
{ "SEMICOLON", 74 },
{ "APOSTROPHE", 75 },
{ "SLASH", 76 },
{ "AT", 77 },
{ "NUM", 78 },
{ "HEADSETHOOK", 79 },
{ "FOCUS", 80 },
{ "PLUS", 81 },
{ "MENU", 82 },
{ "NOTIFICATION", 83 },
{ "SEARCH", 84 },
{ "MEDIA_PLAY_PAUSE", 85 },
{ "MEDIA_STOP", 86 },
{ "MEDIA_NEXT", 87 },
{ "MEDIA_PREVIOUS", 88 },
{ "MEDIA_REWIND", 89 },
{ "MEDIA_FAST_FORWARD", 90 },
{ "MUTE", 91 },
{ "PAGE_UP", 92 },
{ "PAGE_DOWN", 93 },
{ "PICTSYMBOLS", 94 },
{ "SWITCH_CHARSET", 95 },
{ "BUTTON_A", 96 },
{ "BUTTON_B", 97 },
{ "BUTTON_C", 98 },
{ "BUTTON_X", 99 },
{ "BUTTON_Y", 100 },
{ "BUTTON_Z", 101 },
{ "BUTTON_L1", 102 },
{ "BUTTON_R1", 103 },
{ "BUTTON_L2", 104 },
{ "BUTTON_R2", 105 },
{ "BUTTON_THUMBL", 106 },
{ "BUTTON_THUMBR", 107 },
{ "BUTTON_START", 108 },
{ "BUTTON_SELECT", 109 },
{ "BUTTON_MODE", 110 },
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
{ NULL, 0 }
};
// See also policy flags in Input.h.
static const KeycodeLabel FLAGS[] = {
{ "WAKE", 0x00000001 },
{ "WAKE_DROPPED", 0x00000002 },
{ "SHIFT", 0x00000004 },
{ "CAPS_LOCK", 0x00000008 },
{ "ALT", 0x00000010 },
{ "ALT_GR", 0x00000020 },
{ "MENU", 0x00000040 },
{ "LAUNCHER", 0x00000080 },
{ "VIRTUAL", 0x00000100 },
{ NULL, 0 }
};
EventHub.cpp定义设备节点所在的路径
Static const char *device_path="/dev/input" //输入设备的目录
处理时,搜索路径下面的所有input 在bool EventHub::openPlatformInput(void)
{
/*
* Open platform-specific input device(s).
*/
int res;
mFDCount = 1;
mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
mFDs[0].events = POLLIN;
mFDs[0].revents = 0;
mDevices[0] = NULL;
#ifdef HAVE_INOTIFY
mFDs[0].fd = inotify_init();
res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
if(res < 0) {
LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
}
#else
/*
* The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
* We allocate space for it and set it to something invalid.
*/
mFDs[0].fd = -1;
#endif
res = scanDir(device_path);//查找设备
if(res < 0) {
LOGE("scan dir failed for %s\n", device_path);
}
return true;
}
从目录中查找设备
int EventHub::scanDir(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
openDevice(devname); //打开设备
}
closedir(dir);
return 0;
}
事件的处理主要是在getEvent()方法中, 处理过程是一个无限循环,调用阻塞函数来等待事件
部分代码如下:
int pollResult = poll(mFDs, mFDCount, -1);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
if (pollResult <= 0) {
if (errno != EINTR) {
LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
}
Android的事件处理一般经过两个步骤
1 将input设备的整数类型事件转换成表示按键的字符串
键盘布局文件(*.kl)完成第一步的转换, 路径为目标文件系统的system/usr/keylayout
Qwert.kl全键盘对应键值,其中第二列的整数表示驱动程序中Event事件的名称,
第三列表示在KEYCODESK数组中对应的literal
这里完成了驱动程序的事件到字符串的转换
2 将表示按建的字符串转换成android 的键盘码
keycodelable.h(记录键值,位于/frameworks/base/include/ui)
通过查KEYCODES数组(keyCharacterMap.h, 其目录为/framework/base/core./java/android/view/keyevent.java),将literal 字符串转换成value 整数值
不同系统的开发,对于不同的硬件, 只需要写不同的键盘布局即可(让驱动程序中的整数值对应到android的按键名称上)
如果需要增加按键在用户程序中进行处理,除了keyCharacterMap.h和KeyEvent.java两个文件。还需要改 tools/puppet_master/puppetMaster.nav_keys.py
/frameworks/base/core/res/res/values/attrs.xml
Surface系统
关系如下:
Libui提供本地的surface 系统框架
Sufacefilnger完成本地接口的实现
Java框架层主要调用surface向UI提供接口
本地部分可以使用ISurface接口
Surface系统的本地接口 未看完?????
surfaceFlinger本地代码(未看完?????????)
整体结构
SurfaceFilinger是surface部分的本地实现,
代码路径为:/frameworks/base/libs/surfaceflinger_client/surfaceFlinger
生成目标的动态库为:libsurfaceflinger.so 没有头文件,外部进行调用的接口是libui的头文
件
Skia和2D图形系统
Android 的2D系统的底层由skia本地库实现,通过JNI向java层提供图形功能接口,
Skia 底层库(是一个底层的图形,图像,动画,SVG,文本等多方面的图形库,是一个c++本地库)
代码路径为:external/skia
包含三个库:
Libcorecg.so Core Cg 核心图形库 (调试信息,数学计算,内存管理,)
Liblibsgl.so GL(Skia图形库,)
其原码文件主要在:
Libskiagl.so skia-opengl glue library
Android 图形系统的JNI接口
路径为:
/frameworks/base/core/jni/android/graphics
Canvas中的initRaater()和initGl()两个函数与skia本地库联系起来
static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
}
static SkCanvas* initGL(JNIEnv* env, jobject) {
return new SkGLCanvas;
}
Android 的图形包
路径为;
/frameworks/base/graphics/java/android/graphics
当draw内容时需要的四个组件:
Bitmap 保持像素
Canvas 处理调用
(rect,path,text,bitmap) 绘制内容
Paint 用来描述颜色和样式
Android 的 OpenGL 系统和3D图形系统
本地代码
头文件四路径为:/frameworks/base/opengl/include/EGL
/frameworks/base/opengl/include/GLES
源代码的目录为:/frameworks/base/opengl/libagl
/frameworks/base/opengl/libs
编译后,本地代码将会产生三个库:
libGLESv1_CM.so 对应GLES
libEGL.so 对应EGL
Java 框架代码
Android 的OpenGL的实现方式
使用软件库 (libagl.so)
使用硬件库(libhgl.so)
Egl.cpp文件中 gl-hooks_t结构描述了OpenGL所支持的各种API
实际的符号在gl_entries.in t
函数的定义形:
GL_ENTRY(void,// 返回值
glColor4f,// 名称
GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)//参数列表
Egl_entries.in
函数定义形式:
Android 的OpenGL的本地测试代码
测试代码的路径为:
/frameworks/base/opengl/tests
Angeles filter finish textures tritex
OpenGL的JNI代码
OpenGL 引擎向上提供的JNI接口, 供java调用,主要由两个文件提供
/frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp(管理功能)
/frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp (功能函数)
openGl中的java类
openGl的java标准类是javax中的一部分,路径分别是:
/frameworks/base/opengl/java/javax/microedition/khronos/opengles/ 主要文件是:GL10和GL11
/frameworks/base/opengl/java/javax/microedition/khronos/egl 主要文件是:EGL10和EGL11
Android 中继承方法实现OpenGL标准类,路径为:
/frameworks/base/opengl/java/com/google/android/gles_jni
该路径下的文件的各个类对java标准类的继承关系为:
Public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack{}
public class EGLSurfaceImpl extends EGLSurface{}
public class EGLImpl implements EGL10 EGLConfigImpl. Extends EGLConfig{}
public class EGLConfigImpl extends EGLConfig{}
public class EGLContextImpl extends EGLContext{}
在android 的java应用层 ,不会调用com.google.android.gles_jni路径下的类,
只会调用/frameworks/base/opengl/java/javax/microedition/khronos/opengles下的接口
openGL 标准接口到android 系统的媒介(通过调用com.google.android.gles_jn下的类和android基础gui系统的类实现了GLsurfaceView)
/frameworks/base/opengl/java/android/opengl
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback{}
所以GLSurfaceView()也是一个ui元素
如果是在应用层使用openGL,就是继承 GLSurfaceView类并调用OpenGL的标准接口