在android中添加布局的过程,Android 加载键盘布局文件过程

二、WindowManagerService.java的构造函数,在加载键盘布局方面做了两件事情:1.初始化,构造一个InputManager实例;2.启动,由InputManager.java

start()函数实现

private

WindowManagerService(Context

context, PowerManagerService pm,

……..

……..

mInputManager = new

InputManager(context,

this);

//构造InputManager实例

PolicyThread thr

= new PolicyThread(mPolicy, this, context, pm);

thr.start();

synchronized (thr)

{

while

(!thr.mRunning) {

try {

thr.wait();

} catch (InterruptedException e) {

}

}

}

mInputManager.start();

//调用InputManager.java start()函数

// Add ourself to the Watchdog monitors.

Watchdog.getInstance().addMonitor(this);

}

三、InputManager.java是本地c代码的包装类,对com_android_server_InputManager.cpp接口函数进行包装,以提供其他java文件调取。

1.初始化,InputManager.java构造函数中的init()最后调用nativeInit(mCallbacks),

public

InputManager(Context context,

WindowManagerService windowManagerService) {

this.mContext =

context;

this.mWindowManagerService = windowManagerService;

this.mCallbacks =

new Callbacks();

init();

//调用init()函数

}

private void init()

{

Slog.i(TAG, "Initializing input manager");

nativeInit(mCallbacks);

//java接口,由本地函数实现

}

2.

启动,InputManager.java的start()最后调用nativeStart():

public void start()

{

Slog.i(TAG, "Starting input manager");

nativeStart();

//java接口,由本地函数实现

}

四、com_android_server_InputManager.cpp实现InutManager.java的nativeInit(mCallbacks和nativeStart(),当然还实现了其他功能的接口函数,这里不再介绍,对于android如何实现java和c之间的转换,我想对于了解jni的来说不难理解。不懂的可以看此文章学习:http://hi.baidu.com/kellyvivian/blog/item/09cfb541179d2f3387947397.html

1.初始化,android_server_InputManager_nativeInit在被执行的时候会new一个NativeInputManager(callbacks)实例,NativeInputManager(callbacks)接着又会new一个InputManager(eventHub,

this, this)实例

static void

android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,

jobject callbacks) {

if (gNativeInputManager == NULL) {

gNativeInputManager

= new NativeInputManager(callbacks);

} else {

LOGE("Input manager already

initialized.");

jniThrowRuntimeException(env, "Input

manager already initialized.");

}

}

NativeInputManager::NativeInputManager(jobject

callbacksObj) :

mFilterTouchEvents(-1),

mFilterJumpyTouchEvents(-1),

mVirtualKeyQuietTime(-1),

mMaxEventsPerSecond(-1)

{

JNIEnv* env = jniEnv();

mCallbacksObj = env->NewGlobalRef(callbacksObj);

…….

sp eventHub = new

EventHub();

mInputManager = new

InputManager(eventHub, this,

this);

}

2.启动,android_server_InputManager_nativeStart中gNativeInputManager->getInputManager()->start()最终调用的是InputManager.cpp的start()函数

static void

android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {

if (checkInputManagerUnitialized(env)) {

return;

}

status_t result

= gNativeInputManager->getInputManager()->start();

if (result) {

jniThrowRuntimeException(env, "Input

manager could not be started.");

}

}

五、InputManager.cpp中主要有三个函数:initialize()初始化函数,在构造函数中调用;start()开启线程函数;stop()取消线程函数,在虚构函数中调用。

1.初始化,InputManager.cpp构造函数调用initialize(),期间new一个InputReaderThread线程

InputManager::InputManager(

const sp& eventHub,

const sp& readerPolicy,

const sp& dispatcherPolicy) {

mDispatcher = new

InputDispatcher(dispatcherPolicy);

mReader = new

InputReader(eventHub,

readerPolicy, mDispatcher);

initialize();

}

void

InputManager::initialize() {

mReaderThread = new

InputReaderThread(mReader);

mDispatcherThread = new

InputDispatcherThread(mDispatcher);

}

2.启动,mReaderThread->run("InputReader",

PRIORITY_URGENT_DISPLAY)开启初始化时new的InputReaderThread线程

status_t InputManager::start()

{

……..

result = mReaderThread->run("InputReader",

PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE("Could not start

InputReader thread due to error %d.", result);

mDispatcherThread->requestExit();

return

result;

}

return

OK;

}

六、InputReader.cpp中定义了InputReaderThread类,继承于Thread类

1.初始化,InputReaderThread构造函数,初始化一个Thread类

InputReaderThread::InputReaderThread(const

sp& reader) :

Thread( true),

mReader(reader)

{

}

2.启动,run启动线程,Thread

run()方法又调用InputReaderThread

的虚函数threadLoop(),接着调用InputReader的loopOnce()方法,最后调用EventHub.cpp的getEvent(& rawEvent)方法

bool

InputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

void InputReader::loopOnce()

{

RawEvent rawEvent;

mEventHub->getEvent(&

rawEvent);

#if

DEBUG_RAW_EVENTS

LOGD("Input event: device=%d

type=0x%x scancode=%d keycode=%d value=%d",

rawEvent.deviceId, rawEvent.type, rawEvent.scanCode,

rawEvent.keyCode,

rawEvent.value);

#endif

process(&

rawEvent);

}

七、EventHub.cpp是android输入系统的硬件抽象层,维护输入设备的运行,包括Keyboard、

TouchScreen、TraceBall等。

EventHub.cpp中依次执行getEvent()–>openPlatformInput()–>scanDir(DEVICE_PATH)–> openDevice(devname)

bool

EventHub::openPlatformInput(void) {

int res, fd;

………

// Reserve fd index 0 for inotify.

struct pollfd pollfd;

pollfd.fd = fd;

pollfd.events =

POLLIN;

pollfd.revents =

0;

mFds.push(pollfd);

mDevices.push(NULL);

res = scanDir(DEVICE_PATH);

//DEVICE_PATH =

"/dev/input"

if(res < 0) {

LOGE("scan dir failed for

%s\n",

DEVICE_PATH);

}

return

true;

}

int

EventHub::scanDir(const char

*dirname)

{

……

openDevice(devname);

}

closedir(dir);

return 0;

}

openDevice方法会打开/dev/input目录下的所有设备文件,读取name、version、id等设备信息,然后执行loadConfiguration()方法,如果键盘设备就会执行loadKeyMap()这个方法

int

EventHub::openDevice(const char

*devicePath) {

……

// Load the configuration file for the device.

loadConfiguration(device);

……

if

((device->classes &

INPUT_DEVICE_CLASS_KEYBOARD) !=

0) {

// Load the keymap for the device.

status_t status

= loadKeyMap(device);

……

}

……

}

Honeycomb与之前版本不同之处是加入loadConfiguration()方法,它获取与当前设备驱动Vendor、Product、Version匹配的配置文件名,或者是Vendor、Product匹配的配置文件名,具体可查看Input.cpp中getInputDeviceConfigurationFilePathByDeviceIdentifie和getInputDeviceConfigurationFilePathByName方法。

如: kernel/

drivers/input/keyboard/atkbd.c键盘驱动中定义了

input_dev->id.vendor = 0×0001;

input_dev->id.product = 0×0001;

input_dev->id.version = 0xab41,那么与之对应的配置名为Vendor_0001_Product_0001_Version_ad41.idc,返回这个文件的全路径并赋值给device->configurationFile。如果/system/user/idc下存在此文件,接下来调用PropertyMap.cpp的load()方法解析该配置文件并将解析后的信息保存到device->configuration中。

void

EventHub::loadConfiguration(Device* device) {

device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(

device->identifier,

INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);

if (device->configurationFile.isEmpty())

{

LOGD("No input device

configuration file found for device ‘%s’.",

device->identifier.name.string());

} else {

status_t status

= PropertyMap::load(device->configurationFile,

&device->configuration);

if

(status) {

LOGE("Error loading input

device configuration file for device ‘%s’. "

"Using default

configuration.",

device->identifier.name.string());

}

}

}

EventHub.cpp中loadKeyMap又调用了Keyboard.cpp的KeyMap::load()方法

status_t

EventHub::loadKeyMap(Device*

device) {

return device->keyMap.load(device->identifier,

device->configuration);

}

八、在Keyboard.cpp的load方法中,首先判断deviceConfiguration参数是否为空,deviceConfiguration的赋值就是上面loadConfiguration()方法所做的工作。

如果有.idc的配置文件,那么获取key为keyboard.layout的value给keyLayoutName和key为keyboard.characterMap的value给keyCharacterMapName,最后调用loadKeyLayout和loadKeyCharacterMap方法加载此键盘布局文件;如果没有对应的.idc配置文件,则deviceConfiguration为空,就会接着执行probeKeyMap(deviceIdenfifier,

String8("Generic"))方法

status_t

KeyMap::load(const

InputDeviceIdentifier& deviceIdenfifier,

const PropertyMap* deviceConfiguration) {

// Use the configured key layout if available.

if (deviceConfiguration) {

String8 keyLayoutName;

if

(deviceConfiguration->tryGetProperty(String8("keyboard.layout"),

keyLayoutName)) {

status_t status

= loadKeyLayout(deviceIdenfifier, keyLayoutName);

if

(status == NAME_NOT_FOUND) {

LOGE("Configuration for

keyboard device ‘%s’ requested keyboard layout ‘%s’ but

"

"it was not found.",

deviceIdenfifier.name.string(),

keyLayoutName.string());

}

}

String8 keyCharacterMapName;

if

(deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),

keyCharacterMapName)) {

status_t status

= loadKeyCharacterMap(deviceIdenfifier,

keyCharacterMapName);

if

(status == NAME_NOT_FOUND) {

LOGE("Configuration for

keyboard device ‘%s’ requested keyboard character "

"map ‘%s’ but it was not

found.",

deviceIdenfifier.name.string(),

keyLayoutName.string());

}

}

if

(isComplete()) {

return

OK;

}

}

……

if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {

return

OK;

}

……

}

probeKeyMap方法判断名为Gerneric的布局文件是否存在,若存在就会调用loadKeyLayout和loadKeyCharacterMap方法加载此键盘布局文件

bool

KeyMap::probeKeyMap(const

InputDeviceIdentifier& deviceIdentifier,

const String8& keyMapName) {

if (!haveKeyLayout()) {

loadKeyLayout(deviceIdentifier,

keyMapName);

}

if (!haveKeyCharacterMap()) {

loadKeyCharacterMap(deviceIdentifier, keyMapName);

}

return isComplete();

}

至此,Android

Honeycomb已经正确加载了键盘布局文件,那么我们如何定制和使用自己的键盘布局文件呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值