第一部分:从java端发送at命令的处理流程。 拨出电话流程: 1、contacts的androidmanifest.xml android:process="android.process.acore"说明此应用程序运行在acore进程中。 DialtactsActivity的intent-filter的action属性设置为main,catelog属性设置为launcher,所以此activity能出现 在主菜单中,并且是点击此应用程序的第一个界面。dialtactsactivity包含四个tab,分别由TwelveKeyDialer、 RecentCallsListActivity,两个activity-alias DialtactsContactsEntryActivity和DialtactsFavoritesEntryActivity分别 表示联系人和收藏tab,但是正真的联系人列表和收藏是由ContactsListActivity负责。 2、进入TwelveKeyDialer OnClick方法,按住的按钮id为: R.id.digits,执 placecall() Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, Uri.fromParts("tel", number, null)) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); 3、intert.ACTION_CALL_PRIVILEGED实际字符串为android.intent.action.CALL_PRIVILEGED,通过查找知道了packegs/phone 下面的androidmanifest.xml中PrivilegedOutgoingCallBroadcaster activity-alias设置了intent-filter,所以需要找到其 targetactivity为OutgoingCallBroadcaster。所以进入OutgoingCallBroadcaster的 onCreate() //如果为紧急号码马上启动intent.setClass(this, InCallScreen.class); startActivity(intent); Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL); if (number != null) broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow); broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, intent.getData().toString()); if (LOGV) Log.v(TAG, "Broadcasting intent " + broadcastIntent + "."); sendOrderedBroadcast(broadcastIntent, PERMISSION, null, null, Activity.RESULT_OK, number, null); 4、Intent.ACTION_NEW_OUTGOING_CALL实际字符串为android.intent.action.NEW_OUTGOING_CALL,通过查找知道了packegs/phone 下面的androidmanifest.xml中OutgoingCallReceiver Receiver接收此intent消息。找到OutgoingCallReceiver,执行 onReceive()函数 Intent newIntent = new Intent(Intent.ACTION_CALL, uri); newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); newIntent.setClass(context, InCallScreen.class); newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 5、请求拨号的java部分流程 onCreate(第一次)/onNewIntent(非第一次) internalResolveIntent placeCall(intent); PhoneUtils.placeCall(mPhone, number, intent.getData()); phone.dial(number); mCT.dial(newDialString); dial(dialString, CommandsInterface.CLIR_DEFAULT); cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());//obtainCompleteMessage(EVENT_OPERATION_COMPLETE); send(rr); msg = mSender.obtainMessage(EVENT_SEND, rr); acquireWakeLock(); msg.sendToTarget(); RILSender.handleMessage() case EVENT_SEND: ... s.getOutputStream().write(dataLength); s.getOutputStream().write(data);//从这里流程跑到下面ril.cpp中监听部份 6 、请求拨号的c/c++部分流程 6.1、初始化事件循环,启动串口监听,注册socket监听。 rild.c->main() (1)、RIL_startEventLoop //建立事件循环线程 ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); //注册进程唤醒事件回调 ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL); rilEventAddWakeup (&s_wakeupfd_event); //建立事件循环 ril_event_loop for (;;) { ... n = select(nfds, &rfds, NULL, NULL, ptv); // Check for timeouts processTimeouts(); // Check for read-ready processReadReadies(&rfds, n); // Fire away firePending(); } (2)、funcs = rilInit(&s_rilEnv, argc, rilArgv);//实际是通过动态加载动态库的方式执行reference-ril.c中的RIL_Init //单独启动一个线程读取串口数据 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); fd = open (s_device_path, O_RDWR); ret = at_open(fd, onUnsolicited); ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr); RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); 在initializeCallback中执行的程序: setRadioState (RADIO_STATE_OFF); at_handshake(); at_send_command("ATE0Q0V1", NULL); at_send_command("ATS0=0", NULL); ... //注册rild socket端口事件监听到事件循环中 (3)、RIL_register(funcs); s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); ret = listen(s_fdListen, 4); ril_event_set (&s_listen_event, s_fdListen, false, listenCallback, NULL);//将此端口加入事件select队列 rilEventAddWakeup (&s_listen_event); 如果rild socket端口有数据来了将执行listencallback函数 listencallback //为此客户端连接创建新的监听句柄,s_fdListen继续监听其他客户端的连接。 s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen); ril_event_set (&s_commands_event, s_fdCommand, 1, processCommandsCallback, p_rs);//将此端口加入事件select队列 rilEventAddWakeup (&s_commands_event); 6.2、socket监听,收到dial的socket请求 processCommandsCallback //读数据到p_record中 ret = record_stream_get_next(p_rs, &p_record, &recordlen); processCommandBuffer(p_record, recordlen); p.setData((uint8_t *) buffer, buflen); // status checked at end status = p.readInt32(&request); status = p.readInt32 (&token);//请求队列中的序号 pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); pRI->token = token; pRI->pCI = &(s_commands[request]); pRI->p_next = s_pendingRequests; s_pendingRequests = pRI; pRI->pCI->dispatchFunction(p, pRI); //假设是接收了dial指令,pRI->PCI->dispatchFunction(p,pRI),调用dispatchDial (p,pRI) dispatchDial (p,pRI) s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeof(dial), pRI); in reference-ril.c onRequest() ... switch (request) { case RIL_REQUEST_DIAL: requestDial(data, datalen, t); asprintf(&cmd, "ATD%s%s;", p_dial->address, clir); ret = at_send_command(cmd, NULL); err = at_send_command_full (command, NO_RESULT, NULL, NULL, 0, pp_outResponse); err = at_send_command_full_nolock(command, type, responsePrefix, smspdu,timeoutMsec, sponse); err = writeline (command); //此处等待,直到收到成功应答或失败的应答,如:ok,connect,error cme等 err = pthread_cond_wait(&s_commandcond, &s_commandmutex); waiting.... waiting.... RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); errorOffset = p.dataPosition(); p.writeInt32 (e); if (e == RIL_E_SUCCESS) { ret = pRI->pCI->responseFunction(p, response, responselen); if (ret != 0) { p.setDataPosition(errorOffset); p.writeInt32 (ret); } } sendResponse(p); sendResponseRaw(p.data(), p.dataSize()); 6.4、串口监听收到atd命令的应答"OK"或"no carrier"等 readerLoop() line = readline(); processLine(line); handleFinalResponse(line); pthread_cond_signal(&s_commandcond);//至此,前面的等待结束,接着执行RIL_onRequestComplete函数 blockingWrite(fd, (void *)&header, sizeof(header)); blockingWrite(fd, data, dataSize);
6.5、java层收到应答后的处理,以dial为例子. ril.java->RILReceiver.run() for(;;) { ... length = readRilMessage(is, buffer); p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0); processResponse(p); type = p.readInt(); if (type == RESPONSE_SOLICITED) { processSolicited (p); serial = p.readInt(); rr = findAndRemoveRequestFromList(serial); rr.mResult.sendToTarget(); ...... } CallTracker.java->handleMessage (Message msg) switch (msg.what) { case EVENT_OPERATION_COMPLETE: ar = (AsyncResult)msg.obj; operationComplete(); cm.getCurrentCalls(lastRelevantPoll); 第二部分:unsolicited 消息从modem上报到java的流程。 c++部份 readerLoop() line = readline(); processLine(line); handleUnsolicited(line); if (s_unsolHandler != NULL) { s_unsolHandler (line1, line2);//实际执行的是void onUnsolicited (const char *s, const char *sms_pdu) if (strStartsWith(s,"+CRING:") || strStartsWith(s,"RING") || strStartsWith(s,"NO CARRIER") || strStartsWith(s,"+CCWA") ) RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); p.writeInt32 (RESPONSE_UNSOLICITED); p.writeInt32 (unsolResponse); ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen); ret = sendResponse(p); sendResponseRaw(p.data(), p.dataSize()); ret = blockingWrite(fd, (void *)&header, sizeof(header)); blockingWrite(fd, data, dataSize); java部份 ril.java->RILReceiver.run() for(;;) { ... length = readRilMessage(is, buffer); p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0); processResponse(p); processUnsolicited (p); response = p.readInt(); switch(response) { ... case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break; ... } switch(response) { case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: if (RILJ_LOGD) unsljLog(response); mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null)); ... } 第三部分、第四部分:猫相关的各种状态的监听和通知机制/通话相关的图标变换的工作原理。 网络状态,edge,gprs图标的处理
a、注册监听部分
==>SystemServer.java
init2()
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
ServerThread.run()
com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
sInstance = new StatusBarPolicy(context, service);
// phone_signal
mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mPhoneData = IconData.makeIcon("phone_signal",
null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
mPhoneIcon = service.addIcon(mPhoneData, null);
// register for phone state notifications.
((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTH
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
//实际是调用的是TelephonyRegistry.listen,此listen函数会将Iphonestatelistener添加到对应的的handler数组中,到时来了事件会轮询回调。 // data_connection
mDataData = IconData.makeIcon("data_connection",
null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
mDataIcon = service.addIcon(mDataData, null);
service.setIconVisibility(mDataIcon, false); b、 事件通知部分
==>PhoneFactory.java
makeDefaultPhones()
sPhoneNotifier = new DefaultPhoneNotifier();
useNewRIL(context);
phone = new GSMPhone(context, new RIL(context), sPhoneNotifier);
for example
==>DataConnectionTracker.java
notifyDefaultData(String reason)
phone.notifyDataConnection(reason);
mNotifier.notifyDataConnection(this, reason);
==>DefaultPhoneNotifier.java
mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
sender.getInterfaceName(null));
第五部分:gprs拨号上网的通路原理。 上层java程序调用gprs流程:
=>PhoneApp.java
onCreate()
PhoneFactory.makeDefaultPhones(this);
phone = new GSMPhone(context, new SimulatedCommands(), sPhoneNotifier);
mDataConnection = new DataConnectionTracker (this);
createAllPdpList();//建立缺省pdpconnection
pdp = new PdpConnection(phone);
dataLink = new PppLink(phone.mDataConnection);
dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null); dataLink = new PppLink(phone.mDataConnection);
dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null);

//某个条件触发执行
trySetupData(String reason)
setupData(reason);
pdp = findFreePdp();
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
pdp.connect(apn, msg);
phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password,
obtainMessage(EVENT_SETUP_PDP_DONE));

//收到EVENT_SETUP_PDP_DONE消息
=>pdpconnection.java
handleMessage()
case EVENT_SETUP_PDP_DONE:
dataLink.connect();//dataLink是pppLink.java
SystemService.start(SERVICE_PPPD_GPRS);//启动pppd_grps服务
poll.what = EVENT_POLL_DATA_CONNECTION;
sendMessageDelayed(poll, POLL_SYSFS_MILLIS);//启动轮询,看是否成功连接gprs
checkPPP()//每隔5秒轮询,看是否连接成功,或断开
//如果已经连接
mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP); //执行到pdpconnection.handleMessage()
case EVENT_LINK_STATE_CHANGED
onLinkStateChanged(ls);
case LINK_UP:
notifySuccess(onConnectCompleted);
onCompleted.sendToTarget();

//执行dataConnectionTracker.java的handleMessage()
case EVENT_DATA_SETUP_COMPLETE
notifyDefaultData(reason);
setupDnsProperties();
setState(State.CONNECTED);
phone.notifyDataConnection(reason);
startNetStatPoll();
resetPollStats();
1、读取发送出去的包数和接受到的包数
2、如果发送的数据包且没有收到应答包数n大于等于看门狗追踪的限定包数。
2.1、开始轮询pdp context list,尝试恢复网络连接
2.2、如果轮询24次后还没有联通网络则停止网络状态轮询,进行一次ping实验。
2.2.1、如果ping成功则,重新进行网络状态轮询,否则发送EVENT_START_RECOVERY事件。 // reset reconnect timer
nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
着重c++部分代码的角度分析 =>DataConnectionTracker.java
trySetupData(String reason)
setupData(reason);
=>PdpConnection.java
pdp.connect(apn, msg);
=>RIL.JAVA
phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password,
obtainMessage(EVENT_SETUP_PDP_DONE));
send(rr);
//send socket to RIL

//enter c++ layer
=>ril.cpp
processCommandsCallback (int fd, short flags, void *param)
processCommandBuffer(p_record, recordlen);
status = p.readInt32(&request);
pRI->pCI = &(s_commands[request]);
pRI->pCI->dispatchFunction(p, pRI);
dispatchStrings();
s_callbacks.onRequest(pRI->pCI->requestNumber, pStrings, datalen, pRI);
=>reference-ril.c
onRequest();
requestSetupDefaultPDP(data, datalen, t);
err = write_at_to_data_channel("ATD*99***1#",1);

//after a while.get "connect" from data channel,so need to send socket message to java layer.
p.writeInt32 (RESPONSE_SOLICITED);
p.writeInt32 (pRI->token);//the serial No in the request list.
errorOffset = p.dataPosition();
p.writeInt32 (e);
if (e == RIL_E_SUCCESS) {

ret = pRI->pCI->responseFunction(p, response, responselen);
if (ret != 0) {
p.setDataPosition(errorOffset);
p.writeInt32 (ret);
}
}
sendResponse(p);
sendResponseRaw(p.data(), p.dataSize());
ret = blockingWrite(fd, (void *)&header, sizeof(header));
blockingWrite(fd, data, dataSize);

=>RIL.JAVA
RILReceiver.run();
length = readRilMessage(is, buffer);
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
processResponse(p);
processSolicited (p);
serial = p.readInt();
error = p.readInt();
rr = findAndRemoveRequestFromList(serial);
ret = responseStrings(p);
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();
}

=>pdpConnection.java
handleMessage()
case EVENT_SETUP_PDP_DONE:
...
dataLink.connect();
=>pppLink.java
SystemProperties.set(PROPERTY_PPPD_EXIT_CODE, "");
SystemService.start(SERVICE_PPPD_GPRS);//启动pppd_grps服务 poll.what = EVENT_POLL_DATA_CONNECTION;
sendMessageDelayed(poll, POLL_SYSFS_MILLIS);
dataConnection.state = State.CONNECTING;
handleMessage()
case EVENT_POLL_DATA_CONNECTION
checkPPP();
if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length)
|| ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING,
UNKNOWN_ASCII_STRING.length)
&& dataConnection.state == State.CONNECTING)
if (mLinkChangeRegistrant != null) {
mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP);
=>pdpConnection.java
handleMessage()
case EVENT_LINK_STATE_CHANGED:
DataLink.LinkState ls = (DataLink.LinkState) ar.result;
onLinkStateChanged(ls);
case LINK_UP:
notifySuccess(onConnectCompleted);
AsyncResult.forMessage(onCompleted);
onCompleted.sendToTarget();

=>DataConnectionTracker.java
handleMessage()
case EVENT_DATA_SETUP_COMPLETE:
...
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
notifyDefaultData(reason);
setupDnsProperties();//设置dns,gw,我们的实现方式是在pppd中设置的,不用pppd拨号的适用。
setState(State.CONNECTED);
phone.notifyDataConnection(reason);
mNotifier.notifyDataConnection(this, reason);
=>DefaultPhoneNotifier.java
//mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));构造函数中初始化了mRegistry
mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
sender.getInterfaceName(null));
startNetStatPoll();
} 第六部分:通话相关的语音通路切换原理、震动接口 6、语音通路 6.1、设置语音通路的路由 目前我们有两处处理: a、CallTracker.java中 handlePollCalls() 检测到+clcc返回的电话列表中有状态为DriverCall.State.ALERTING(表示拨打电话后,对方已经振铃),此时需要设置语音通路为MODE_IN_CALL b、PhoneUtils.java中setAudioMode()函数 c、调用通路分析 AudioManager audioManager = (AudioManager) context.getSystemService (Context.AUDIO_SERVICE); audioManager.setMode(mode); AudioManager.setMode(mode); AudioService.setMode(mode); AudioSystem.setMode(mode);(native function) android_media_AudioSystem.cpp==>android_media_AudioSystem_setMode() AudioSystem.cpp==>setMode() const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); binder = sm->getService(String16("media.audio_flinger")); ... gAudioFlinger = interface_cast<IAudioFlinger>(binder); ... return gAudioFlinger; 通过查找“media.audio_flinger”发现AudioFlinger.cpp==>instantiate()//Main_mediaserver.cpp中被实例化。 defaultServiceManager()->addService(String16("media.audio_flinger"), new AudioFlinger()); mAudioHardware = AudioHardwareInterface::create(); LOGV("Creating Vendor Specific AudioHardware"); hw = createAudioHardware(); return new AudioHardwareMarvell(); return af->setMode(mode); AudioHardwareLittle.cpp==>setMode(mode) doRouting(); enable_incall_headphone()//or others... system("alsactl -f /etc/alsactl/asound.state_none restore"); system("alsactl -f /etc/alsactl/asound.state_headset_r_s restore"); 6.2、来电播放振铃,挂断或接听停止振铃。 ==>Phone.app onCreate() ringer = new Ringer(phone); Vibrator mVibrator = new Vibrator(); mService = IHardwareService.Stub.asInterface(ServiceManager.getService("hardware")); notifier = new CallNotifier(this, phone, ringer, mBtHandsfree); mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null); mPhone.registerForPhoneStateChanged(this, PHONE_STATE_CHANGED, null); mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null); ... case PHONE_INCOMING_RING: mRinger.ring(); mHardwareService.setAttentionLight(true); mVibratorThread.start(); while (mContinueVibrating) { mVibrator.vibrate(VIBRATE_LENGTH); SystemClock.sleep(VIBRATE_LENGTH + PAUSE_LENGTH); } ... makeLooper(); mRingHandler.sendEmptyMessage(PLAY_RING_ONCE); ... case PLAY_RING_ONCE: PhoneUtils.setAudioMode(mContext, AudioManager.MODE_RINGTONE); r.play(); ... case PHONE_DISCONNECT: case PHONE_STATE_CHANGED: ... mRinger.stopRing(); Message msg = mRingHandler.obtainMessage(STOP_RING); msg.obj = mRingtone; mRingHandler.sendMessage(msg); case STOP_RING: r.stop(); getLooper().quit(); ... mVibrator.cancel(); 第七部分:通话相关的notification服务 7、通话相关的notification服务。 7.1、NotificationMgr ==>PhoneApp.java onCreate() NotificationMgr.init(this)//NotificationMgr.java//此类主要负责电话通知的具体表现(通知和取消通知),未接图标、通话中、蓝牙激活中、保持中,静音、免提等。封装了简单的瞬间显示文本消息的功能。提供漫游数据连接禁止的通知封装和漫游数据连接允许时取消通知 sMe = new NotificationMgr(context); mNotificationMgr = (NotificationManager context.getSystemService(Context.NOTIFICATION_SERVICE); mStatusBar = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); //主要用于显示静音和speaker状态的图表(在状态条右边显示) sMe.updateNotifications();//主要功能是: 1、查询是否有未读的未接听电话,并显示到状态栏图标,和通知列表 2、根据是否是电话状态,更新状态栏图表和通知列表(可能是激活,蓝牙,保持等) 7.2、CallNotifier ==>PhoneApp.java onCreate() notifier = new CallNotifier(this, phone, ringer, mBtHandsfree);//此类主要是监听通话相关的事件,然后进行例如来电播放铃声,震动。挂断、接听停止振铃等(调用Ringer类实现此功能),根据不同的状态调用调用NotificationMgr进行具体的通知和取消通知。 第八部分: 通话相关的各种server 电话通信相关的服务:
(1)、从ServiceManager得到的:
a、wifiService
b、PhoneInterfaceManager
c、PhoneSubInfo
d、SimPhoneBookInterfaceManager
e、SimSmsInterfaceManager
f、TelephonyRegistry
g、NetStatService
h、ConnectivityService
(2)、从ApplicationContext得到的:
a、TelephonyManager

更多相关文章

  1. Android输入事件InputReader和InputDispatcher分析
  2. android 事件传递机制
  3. Android(安卓)View框架总结(九)KeyEvent事件分发机制
  4. Android事件分发机制的探索与发现之ViewGroup篇
  5. Android(安卓)View的onClick回调机制
  6. android滑动事件监听
  7. 一步一步学android之事件篇——长按事件
  8. Android(安卓)基础-1.0 按钮4种点击事件
  9. Android(安卓)获取、移除 View 的 OnClickListener

随机推荐

  1. 浅谈Android系统启动过程
  2. Knowledge structure in Android src dev
  3. Unity3d调用android中的方法
  4. 使用Android(安卓)Google Map
  5. Android画图学习总结(四)——Animation(下)
  6. NetBeans 7.0 安装 Android SDK 开发 And
  7. Android使用json对中文进行编码 使用php
  8. Android获取当前已连接的wifi信号强度的
  9. Android 数据存储与IO (一)
  10. View事件分发机制