`
zhangziyangup
  • 浏览: 1082315 次
文章分类
社区版块
存档分类
最新评论

froyo源码 来电中的键盘锁、分拨盘、Menu解读

 
阅读更多

下面是针对frameworks层的,我有时间写app的phone

DTMFTwelveKeyDialer implements

SlidingDrawer.OnDrawerOpenListener,
SlidingDrawer.OnDrawerCloseListener
从上面可以看出针对抽屉实现的实现方法。

流层DialerOpen
DTMFTwelveKeyDialer class onDrawerOpened method-----> TMFTwelveKeyDialer class onDialerOpen method------> InCallScreen class onDialerOpen method
------>InCallScreen class resetTouchLockTimer method------>InCallScreen classmHandler properties sendEmptyMessageDelayed(TOUCH_LOCK_TIMER, touchLockDelay)
method------>InCallScreen classmHandler propertiesTOUCH_LOCK_TIMERcase touchLockTimerExpired method------>InCallScreen class enableTouchLock method
------>
mTouchLockOverlay.setVisibility(View.VISIBLE);mTouchLockOverlay.startAnimation(mTouchLockFadeIn);
or mTouchLockOverlay.setVisibility(View.GONE);

InCallScreen implements View.OnClickListener, View.OnTouchListener

流层Touch
InCallScreen class onTouch method------>InCallScreen class resetTouchLockTimer&&enableTouchLock(false)------>InCallScreen class initTouchLock method------>OnTouchListener(this)

键盘锁布局
<RelativeLayout android:id="@+id/touchLockOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="#8000"
>
<!-- Layout note: we could use android:layout_centerInParent="true"
here to center the lock icon exactly in the middle of the screen.
But it actually looks better to have the lock roughly in the
middle of the dialpad key area, so instead we position it a
fixed distance from the bottom of the screen. -->
<TextView android:id="@+id/touchLockIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="70dip"
android:text="@string/touchLockText"
android:textAppearance="?android:attr/textAppearanceLarge"
android:background="@drawable/dialpad_lock"
/>
</RelativeLayout>

private void onDialerClose() {
if (DBG) log("onDialerClose()...");

// reset back to a short delay for the poke lock.
PhoneApp app = PhoneApp.getInstance();
app.updateWakeState();//针对电源

mPhone.unregisterForDisconnect(mHandler);//不注册连接广播 PhoneProxy

// Give the InCallScreen a chance to do any necessary UI updates.
if (mInCallScreen != null) {
mInCallScreen.onDialerClose();
}
}

具体的电源资料见:http://fanwei51880.blog.163.com/ ... 402010108105416798/

android的PowerManager和PowerManager.WakeLock

工作学习 2010-11-08 10:54:16 阅读286 评论0 字号:大中小 订阅
前言

  学习android一段时间了,为了进一步了解android的应用是如何设计开发的,决定详细研究几个开源的android应用。从一些开源应用中吸收点东西,一边进行量的积累,一边探索android的学习研究方向。这里我首先选择了jwood的 Standup Timer 项目。本文将把研究的内容笔记整理,建立一个索引列表。
PowerManager.WakeLock

  PowerManager.WakerLock是我分析Standup Timer源代码时发现的一个小知识点,Standup Timer 用WakeLock保证程序运行时保持手机屏幕的恒亮(程序虽小但也做得相当的细心,考虑的很周到)。PowerManager 和PowerManager.WakerLock7用于对Android设备的电源进行管理。
  PowerManager:This class gives you control of the power state of the device.
  PowerManager.WakeLock: lets you say that you need to have the device on.
  Android中通过各种Lock锁对电源进行控制,需要注意的是加锁和解锁必须成对出现。先上一段Standup Timer里的代码然后进行说明。
代码
private void acquireWakeLock() {
if (wakeLock == null) {
Logger.d("Acquiring wake lock");
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, this.getClass().getCanonicalName());
wakeLock.acquire();
}

}


private void releaseWakeLock() {
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
wakeLock = null;
}

}


acquireWakeLock()方法中获取了 SCREEN_DIM_WAKE_LOCK锁,该锁使 CPU 保持运转,屏幕保持亮度(可以变灰)。这个函数在Activity的 onResume中被调用。releaseWakeLock()方法则是释放该锁。它在Activity的 onPause中被调用。利用Activiy的生命周期,巧妙的让 acquire()和release()成对出现。
@Override
protected void onResume()
{
super.onResume();
//获取锁,保持屏幕亮度
acquireWakeLock();
startTimer();
}
代码
protected void onPause()
{
super.onPause();
synchronized(this) {
cancelTimer();
releaseWakeLock();

if (finished) {
clearState();
} else {
saveState();
}
}
}


PowerManager和WakeLock的操作步骤
  PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);通过 Context.getSystemService().方法获取PowerManager实例。
  然后通过PowerManager的newWakeLock((int flags, String tag)来生成WakeLock实例。int Flags指示要获取哪种WakeLock,不同的Lock对cpu 、屏幕、键盘灯有不同影响。
  获取WakeLock实例后通过acquire()获取相应的锁,然后进行其他业务逻辑的操作,最后使用release()释放(释放是必须的)。
关于int flags

  各种锁的类型对CPU 、屏幕、键盘的影响:
PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。

SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯

SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯

FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度

ACQUIRE_CAUSES_WAKEUP:Normal wake locks don't actually turn on the illumination. Instead, they cause the illumination to remain on once it turns on (e.g. from user activity). This flag will force the screen and/or keyboard to turn on immediately, when the WakeLock is acquired. A typical use would be for notifications which are important for the user to see immediately.

ON_AFTER_RELEASE:f this flag is set, the user activity timer will be reset when the WakeLock is released, causing the illumination to remain on a bit longer. This can be used to reduce flicker if you are cycling between wake lock conditions.

权限获取

要进行电源的操作需要在AndroidManifest.xml中声明该应用有设置电源管理的权限。
<uses-permission android:name="android.permission.WAKE_LOCK" />
你可能还需要
<uses-permission android:name="android.permission.DEVICE_POWER" />
另外WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。

InCallScreen

/* package */ void onDialerClose() {
if (DBG) log("onDialerClose()...");

final PhoneApp app = PhoneApp.getInstance();

// OTA-specific cleanup upon closing the dialpad.
if ((mInCallScreenMode == InCallScreenMode.OTA_NORMAL)
|| (mInCallScreenMode == InCallScreenMode.OTA_ENDED)
|| ((app.cdmaOtaScreenState != null)
&& (app.cdmaOtaScreenState.otaScreenState ==
CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION))) {
mDialer.setHandleVisible(false);//分拨盘不显示
if (otaUtils != null) {
otaUtils.otaShowProperScreen(); 这个方法的注释还是有点不清楚的,ota空中下载技术,这个是猜测是出现界面针对下载的界面指导步骤界面。
}
}

// Dismiss the "touch lock" overlay if it was visible.
// (The overlay is only ever used on top of the dialpad).
enableTouchLock(false);隐藏了initTouchLock初始化

// Update the in-call touch UI (which may need to re-show itself.)
updateInCallTouchUi();// mInCallTouchUi.updateState(mPhone)

// Update the visibility of the dialpad itself (and any other
// onscreen UI elements that depend on it.)
updateDialpadVisibility();

// This counts as explicit "user activity".
app.getInstance().pokeUserActivity();
}

看到下面这个就清楚点了针对上面的问题
<!-- Main frame containing the main set of in-call UI elements. -->
<FrameLayout android:id="@+id/mainFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dip"
android:paddingLeft="6dip"
android:paddingRight="6dip"
>

<!-- (1) inCallPanel: the main set of in-call UI elements.
We update this view's background to indicate the state of the
current call; see updateInCallPanelBackground(). -->
<RelativeLayoutandroid:id="@+id/inCallPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!-- The "Call Card", which displays info about the currently
active phone call(s) on the device.See call_card.xml. -->
<com.android.phone.CallCardandroid:id="@+id/callCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout><!-- End of inCallPanel -->

<!-- Contains all OTA-related UI elements for CDMA -->
<ViewStub android:id="@+id/otaCallCardStub"
android:layout="@layout/otacall_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</FrameLayout><!-- End of mainFrame -->

查看otacall_card.xml中涉及到string资源内容的:
<string name="network_message" msgid="5673682885938122239">"网络讯息"</string>
<string name="ota_title_activate" msgid="8616918561356194398">"激活您的手机"</string>
<string name="ota_touch_activate" msgid="6553212803262586244">"需要拨打特别号码才能激活您的手机服务。"/n/n"在按下“激活”后,按照语音提示激活您的手机。"</string>
<string name="ota_touch_activate_new" msgid="4508197891732183852">"触摸“激活”将拨出特殊呼叫,在运营商的移动网络中激活您的手机,这样您就可拨打电话和连接移动数据网络了。"</string>
<string name="ota_skip_activation_dialog_title" msgid="2943366608272261306">"略过激活步骤?"</string>
<string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"如果您略过激活步骤,就无法拨打电话或连接到移动数据网络(不过您可以连接到 Wi-Fi 网络)。如果您不激活手机,每次开机时都会收到激活提示。"</string>
<string name="ota_skip_activation_dialog_skip_label" msgid="3458532775091563208">"略过"</string>
<string name="ota_skip_activation_dialog_continue_label" msgid="4343765820509664362">"激活"</string>
<string name="ota_activate" msgid="1368528132525626264">"激活"</string>
<string name="ota_title_activate_success" msgid="3344632328991980578">"手机已激活!"</string>
<string name="ota_title_problem_with_activation" msgid="7095824491970084367">"激活时遇到问题"</string>
<string name="ota_listen" msgid="162923839877584937">"按照语音提示操作,直至提示手机已激活。"</string>
<string name="ota_dialpad" msgid="3530900997110658409">"键盘"</string>
<string name="ota_speaker" msgid="6904589278542719647">"免提"</string>
<string name="ota_progress" msgid="4644512049143969504">"正在向您的手机中写入程序,请耐心等待。"</string>
<string name="ota_failure" msgid="8600027551822478181">"编程失败"</string>
<string name="ota_successful" msgid="1880780692887077407">"您的手机已激活。最多 15 分钟即可开始使用服务。"</string>
<string name="ota_unsuccessful" msgid="623361244652068739">"您的手机尚未激活。"/n"您可能需要找一个手机信号更好的位置(窗户附近或室外)。"/n/n"再试一次,或呼叫客户服务中心寻求更多解决方法。"</string>
<string name="ota_spc_failure" msgid="3909983542575030796">"SPC 故障太多"</string>
<string name="ota_call_end" msgid="4537279738134612388">"上一步"</string>
<string name="ota_try_again" msgid="7685477206465902290">"重试"</string>
<string name="ota_next" msgid="3904945374358235910">"下一步"</string>
<string name="ota_back" msgid="2190038043403850052">"上一步"</string>

updateInCallTouchUi();------>mInCallTouchUi.updateState(mPhone);------》 updateInCallControls(phone)|| showIncomingCallWidget()||hideIncomingCallWidget()

厘清 mInCallControls.setVisibility(showInCallControls ? View.VISIBLE : View.GONE);
mInCallControls = findViewById(R.id.inCallControls);


// Regular (single-tap) buttons, where we listen for click events:
// Main cluster of buttons:
mAddButton = (Button) mInCallControls.findViewById(R.id.addButton);
mAddButton.setOnClickListener(this);
mMergeButton = (Button) mInCallControls.findViewById(R.id.mergeButton);
mMergeButton.setOnClickListener(this);
mEndButton = (Button) mInCallControls.findViewById(R.id.endButton);
mEndButton.setOnClickListener(this);
。。。。。。




/**
* Updates the enabledness and "checked" state of the buttons on the
* "inCallControls" panel, based on the current telephony state.
*/
updateInCallControls(phone)针对菜单项button的一些选项是否显示根据电话状态


showIncomingCallWidget()------》mIncomingCallWidget.setVisibility(View.VISIBLE);


@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (DBG) log("InCallTouchUi onFinishInflate(this = " + this + ")...");


// Look up the various UI elements.


// "Dial-to-answer" widget for incoming calls.
mIncomingCallWidget= (SlidingTab) findViewById(R.id.incomingCallWidget);
mIncomingCallWidget.setLeftTabResources(
R.drawable.ic_jog_dial_answer,
com.android.internal.R.drawable.jog_tab_target_green,
com.android.internal.R.drawable.jog_tab_bar_left_answer,
com.android.internal.R.drawable.jog_tab_left_answer

);
mIncomingCallWidget.setRightTabResources(
R.drawable.ic_jog_dial_decline,
com.android.internal.R.drawable.jog_tab_target_red,
com.android.internal.R.drawable.jog_tab_bar_right_decline,
com.android.internal.R.drawable.jog_tab_right_decline

);


// For now, we only need to show two states: answer and decline.
mIncomingCallWidget.setLeftHintText(R.string.slide_to_answer_hint);
mIncomingCallWidget.setRightHintText(R.string.slide_to_decline_hint);


mIncomingCallWidget.setOnTriggerListener(this);

/*mIncomingCallWidget.setOnTriggerListener(new OnTriggerListener(){



public void
onTrigger(View v, int whichHandle) {

// TODO Auto-generated method stub



}




public void onGrabbedStateChange(View v, int grabbedState) {


// TODO Auto-generated method stub



}});*/







/**
* Handles "Answer" and "Reject" actions for an incoming call.
* We get this callback from the SlidingTab
* when the user triggers an action.
*
* To answer or reject the incoming call, we call
* InCallScreen.handleOnscreenButtonClick() and pass one of the
* special "virtual button" IDs:
* - R.id.answerButton to answer the call
* or
* - R.id.rejectButton to reject the call
.
*/
public voidonTrigger(View v, int whichHandle) {
log("onDialTrigger(whichHandle = " + whichHandle + ")...");


switch (whichHandle) {
case SlidingTab.OnTriggerListener.LEFT_HANDLE:
if (DBG) log("LEFT_HANDLE: answer!");


hideIncomingCallWidget();


// ...and also prevent it from reappearing right away.
// (This covers up a slow response from the radio; see updateState().)
mLastIncomingCallActionTime = SystemClock.uptimeMillis();


// Do the appropriate action.
if (mInCallScreen != null) {
// Send this to the InCallScreen as a virtual "button click" event:
mInCallScreen.handleOnscreenButtonClick(R.id.answerButton);
} else {
Log.e(LOG_TAG, "answer trigger: mInCallScreen is null");
}
break;


case SlidingTab.OnTriggerListener.RIGHT_HANDLE:
if (DBG) log("RIGHT_HANDLE: reject!");


hideIncomingCallWidget();


// ...and also prevent it from reappearing right away.
// (This covers up a slow response from the radio; see updateState().)
mLastIncomingCallActionTime = SystemClock.uptimeMillis();


// Do the appropriate action.
if (mInCallScreen != null) {
// Send this to the InCallScreen as a virtual "button click" event:
mInCallScreen.handleOnscreenButtonClick(R.id.rejectButton);
} else {
Log.e(LOG_TAG, "reject trigger: mInCallScreen is null");
}
break;


default:
Log.e(LOG_TAG, "onDialTrigger: unexpected whichHandle value: " + whichHandle);
break;
}


// Regardless of what action the user did, be sure to clear out
// the hint text we were displaying while the user was dragging.
mInCallScreen.updateSlidingTabHint(0, 0);
}


<!-- (1) incomingCallWidget: the UI displayed while an incoming call is ringing. -->
<com.android.internal.widget.SlidingTab
android:id="@+id/incomingCallWidget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_alignParentBottom="true"
android:layout_marginBottom="180dip"
/>

/**
* Updates the visibility of the DTMF dialpad (and its onscreen
* "handle", if applicable), based on the current state of the phone
* and/or the current InCallScreenMode.
*/
private void updateDialpadVisibility() {
//
// (1) The dialpad itself:
//
// If an incoming call is ringing, make sure the dialpad is
// closed.(We do this to make sure we're not covering up the
// "incoming call" UI, and especially to make sure that the "touch
// lock" overlay won't appear.)
if (mPhone.getState() == Phone.State.RINGING) {
mDialer.closeDialer(false);// don't do the "closing" animation

// Also, clear out the "history" of DTMF digits you may have typed
// into the previous call (so you don't see the previous call's
// digits if you answer this call and then bring up the dialpad.)
//
// TODO: it would be more precise to do this when you *answer* the
// incoming call, rather than as soon as it starts ringing, but
// the InCallScreen doesn't keep enough state right now to notice
// that specific transition in onPhoneStateChanged().
mDialer.clearDigits();
}

//
// (2) The onscreen "handle":
//
// The handle is visible only if it's OK to actually open the
// dialpad.(Note this is meaningful only on platforms that use a
// SlidingDrawer as a container for the dialpad.)
mDialer.setHandleVisible(okToShowDialpad());

//
// (3) The main in-call panel (containing the CallCard):
//
// On some platforms(*) we need to hide the CallCard (which is a
// child of mInCallPanel) while the dialpad is visible.
//
// (*) We need to do this when using the dialpad from the
// InCallTouchUi widget, but not when using the
// SlidingDrawer-based dialpad, because the SlidingDrawer itself
// is opaque.)
if (!mDialer.usingSlidingDrawer()) {
if (mDialerView != null) {
mDialerView.setKeysBackgroundResource(
isBluetoothAudioConnected() ? R.drawable.btn_dial_blue
: R.drawable.btn_dial_green);
}

if (isDialerOpened()) {
mInCallPanel.setVisibility(View.GONE);
} else {
// Dialpad is dismissed; bring back the CallCard if
// it's supposed to be visible.
if ((mInCallScreenMode == InCallScreenMode.NORMAL)
|| (mInCallScreenMode == InCallScreenMode.CALL_ENDED)) {
mInCallPanel.setVisibility(View.VISIBLE);
}
}
}
}

认识抽屉SlidingDrawer

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<!-- Sliding drawer widget containing the in-call DTMF dialpad.

On devices that do *not* use an onscreen InCallTouchUi
widget, the dialpad is contained within a SlidingDrawer
(which provides a "handle" that the user must drag open
to access the dialpad.)

See non_drawer_dialpad.xml for the corresponding layout file
for devices that *do* use an InCallTouchUi widget.
-->
<SlidingDrawer
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialer_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:topOffset="5dp"
android:bottomOffset="7dp"
android:handle="@+id/dialer_tab"
android:content="@+id/dtmf_dialer"
android:allowSingleTap="false"
android:visibility="gone"
>

<!-- Drawer handle -->
<LinearLayout
android:id="@id/dialer_tab"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:focusable="true"
>
<ImageView
android:layout_width="1dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scaleType="fitXY"
android:duplicateParentState="true"
android:src="@drawable/tray_handle_strip"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dtmfDialpadHandleLabel"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold"
android:shadowDy="1"
android:shadowRadius="0.9"
android:shadowColor="#ffffffff"
android:duplicateParentState="true"
android:background="@drawable/tray_handle_tab"/>
<ImageView
android:layout_width="1dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scaleType="fitXY"
android:src="@drawable/tray_handle_strip"
android:duplicateParentState="true"
/>
</LinearLayout>

<!-- drawer content dialer view -->
<com.android.phone.DTMFTwelveKeyDialerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dtmf_dialer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginTop="1dip"
android:background="@color/dtmf_dialer_background">

<!-- Number Display Field, padded for correct text alignment -->
<EditText android:id="@+id/dtmfDialerField"
android:layout_width="match_parent"
android:layout_height="66dp"
android:layout_marginTop="14dp"
android:layout_marginBottom="6dp"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:paddingRight="16dp"
android:paddingLeft="16dp"
android:maxLines="1"
android:scrollHorizontally="true"
android:textSize="28sp"
android:freezesText="true"
android:background="@drawable/btn_dial_textfield_normal_full"
android:textColor="@color/dtmf_dialer_display_text"
android:focusableInTouchMode="false"
android:clickable="false"/>

<!-- Keypad section -->
<include layout="@layout/dialpad" />

<!-- Dummy element to pad below the dialpad -->
<View android:layout_height="1dp"
android:layout_width="match_parent"
android:layout_weight="1"/>

</com.android.phone.DTMFTwelveKeyDialerView>

</SlidingDrawer>

SlidingDrawer初始化在InCallScreen SlidingDrawer dialerDrawer;
if (isTouchUiEnabled()) {
// This is a "full touch" device.
mDialerView = (DTMFTwelveKeyDialerView) findViewById(R.id.non_drawer_dtmf_dialer);
if (DBG) log("- Full touch device!Found dialerView: " + mDialerView);
dialerDrawer = null;// No SlidingDrawer used on this device.
} else {
// Use the old-style dialpad contained within the SlidingDrawer.
mDialerView = (DTMFTwelveKeyDialerView) findViewById(R.id.dtmf_dialer);
if (DBG) log("- Using SlidingDrawer-based dialpad.Found dialerView: " + mDialerView);
dialerDrawer = (SlidingDrawer) findViewById(R.id.dialer_container);
if (DBG) log("...and the SlidingDrawer: " + dialerDrawer);
}
// Sanity-check that (regardless of the device) at least the
// dialer view is present:
if (mDialerView == null) {
Log.e(LOG_TAG, "onCreate: couldn't find dialerView", new IllegalStateException());
}
// Finally, create the DTMFTwelveKeyDialer instance.
mDialer = new DTMFTwelveKeyDialer(this, mDialerView, dialerDrawer);


流层:分拨数字
DTMFTwelveKeyDialer------>onTouch(View v, MotionEvent event)------>processDtmf(char c)------> startTone(c)------>startDtmfTone(c)||startToneCdma(c)-------> [mPhone.startDtmf(tone)&&mToneGenerator.startTone(mToneMap.get(tone))]||[[sendShortDtmfToNetwork (tone)||mPhone.startDtmf(tone)]&&startLocalToneCdma(tone)]

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// if (DBG) log("onKeyDown(keycode " + keyCode + ")...");

switch (keyCode) {

case KeyEvent.KEYCODE_MENU:
// Special case for the MENU key: if the "touch lock"
// overlay is up (over the DTMF dialpad), allow MENU to
// dismiss the overlay just as if you had double-tapped
// the onscreen icon.
// (We do this because MENU is normally used to bring the
// UI back after the screen turns off, and the touch lock
// overlay "feels" very similar to the screen going off.
// This is also here to be "backward-compatibile" with the
// 1.0 behavior, where you *needed* to hit MENU to bring
// back the dialpad after 6 seconds of idle time.)
if (mDialer.isOpened() && isTouchLocked()) {
if (VDBG) log("- allowing MENU to dismiss touch lock overlay...");
// Take down the touch lock overlay, but post a
// message in the future to bring it back later.
enableTouchLock(false);
resetTouchLockTimer();
return true;
}
break;

}

menu的菜单项初始化
Override onCreatePanelView(), in order to get complete control
over the UI that comes up when the user presses MENU.

This callback allows me to return a totally custom View hierarchy
(with custom layout and custom "item" views) to be shown instead
of a standard android.view.Menu hierarchy.

This gets called (with featureId == FEATURE_OPTIONS_PANEL) every
time we need to bring up the menu.(And in cases where we return
non-null, that means that the "standard" menu callbacks
onCreateOptionsMenu() and onPrepareOptionsMenu() won't get called
at all.)


覆盖onCreatePanelView(),以得到完全控制
在用户界面,来了当用户按下菜单。

此回调让我回到一个完全自定义视图层次
(自定义的布局和自定义“项目“视图),而不是要显示
一个标准android.view.Menu层次。

这被调用(用featureId== FEATURE_OPTIONS_PANEL)每
我们需要时间来调出菜单。 (在情况下,我们的回报
非空,这意味着“标准”菜单回调
onCreateOptionsMenu()和onPrepareOptionsMenu()不会被调用
在所有)。



@Override
public View onCreatePanelView(int featureId) {
if (VDBG) log("onCreatePanelView(featureId = " + featureId + ")...");

// We only want this special behavior for the "options panel"
// feature (i.e. the standard menu triggered by the MENU button.)
if (featureId != Window.FEATURE_OPTIONS_PANEL) {
return null;
}

// For now, totally disable the in-call menu on devices where we
// use onscreen touchable buttons instead.
// TODO: even on "full touch" devices we may still ultimately need
// a regular menu in some states.Need UI spec.
if (isTouchUiEnabled()) {
return null;
}

// TODO: May need to revisit the wake state here if this needs to be
// tweaked.

// Make sure there are no pending messages to *dismiss* the menu.
mHandler.removeMessages(DISMISS_MENU);

if (mInCallMenu == null) {
if (VDBG) log("onCreatePanelView: creating mInCallMenu (first time)...");
mInCallMenu = new InCallMenu(this);
mInCallMenu.initMenu();
}

boolean okToShowMenu = mInCallMenu.updateItems(mPhone);
return okToShowMenu ? mInCallMenu.getView() : null;
}

onCreatePanelView在PhoneWindow的preparePanel(PanelFeatureState st, KeyEvent event) 被调用具体部分代码如下:
final Callback cb = getCallback();


if (cb != null) {
st.createdPanelView = cb.onCreatePanelView(st.featureId);
}
关于回调03-18 18:31:50.377: INFO/COMING_PHONE_MENU(341): PhoneWindow class : dispatchKeyEvent method start
03-18 18:31:50.377: INFO/COMING_PHONE_MENU(341): InCallScreen class : dispatchKeyEvent method start
03-18 18:31:50.397: INFO/COMING_PHONE_MENU(341): PhoneWindow class : onKeyDown method start
03-18 18:31:50.397: INFO/COMING_PHONE_MENU(341): PhoneWindow class : onKeyDownPanel method start
03-18 18:31:50.407: INFO/COMING_PHONE_MENU(341): PhoneWindow class : preparePanel method start
03-18 18:31:50.407: INFO/COMING_PHONE_MENU(341): InCallScreen class : onCreatePanelView method start
03-18 18:31:50.597: INFO/COMING_PHONE_MENU(341): PhoneWindow class : dispatchKeyEvent method start
03-18 18:31:50.607: INFO/COMING_PHONE_MENU(341): InCallScreen class : dispatchKeyEvent method start
03-18 18:31:50.607: INFO/COMING_PHONE_MENU(341): PhoneWindow class : onKeyUp method start
03-18 18:31:50.607: INFO/COMING_PHONE_MENU(341): PhoneWindow class : onKeyUpPanel method start
03-18 18:31:50.607: INFO/COMING_PHONE_MENU(341): PhoneWindow class : preparePanel method start

PhoneWindow extends Window implements MenuBuilder.Callback
boolean dispatchKeyEvent(KeyEvent event) {......
final Callback cb = getCallback();
final boolean handled = cb != null && mFeatureId < 0 ?cb.dispatchKeyEvent(event)
: super.dispatchKeyEvent(event);

......
return isDown ?PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
:PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); //在此处show

}
这次主要涉及到界面,这个framework层的几个类的方法回调关系以后再看

onCreatePanelView方法中
if (mInCallMenu == null) {
if (VDBG) log("onCreatePanelView: creating mInCallMenu (first time)...");
mInCallMenu = new InCallMenu(this);
mInCallMenu.initMenu();这里全是动态加载布局通过代码跟下面的incall_screen_ui中的布局没有关系
}


<LinearLayout android:id="@+id/bottomButtons"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:paddingBottom="4dip"
>

<LinearLayout android:id="@+id/inCallControlsRow1"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<!-- The buttons in the top row all have an icon *and* a
text label, so we use a <Button> with a "top"
compound drawable (rather than an ImageButton, which
can't have a label.)Some buttons set the icon image
here; others do it from Java if the image depends on
the current state of the call. -->

<!-- The upper-left button in the main cluster is either
"Add" or "Merge", depending on the state of the call. -->
<FrameLayout
android:layout_width="1dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip"
>
<!-- "Add Call" -->
<Button android:id="@+id/addButton"
style="@style/InCallTouchButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dip"
android:layout_marginBottom="0dip"
android:layout_marginLeft="0dip"
android:layout_marginRight="0dip"
android:text="@string/onscreenAddCallText"
android:drawableTop="@drawable/ic_in_call_touch_add_call"
/>
<!-- "Merge calls" -->
<!-- This button is used only on GSM devices, where we know
that "Add" and "Merge" are never available at the same time.
The "Merge" button for CDMA devices is "cdmaMergeButton" above. -->
<Button android:id="@+id/mergeButton"
style="@style/InCallTouchButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dip"
android:layout_marginBottom="0dip"
android:layout_marginLeft="0dip"
android:layout_marginRight="0dip"
android:text="@string/onscreenMergeCallsText"
android:drawableTop="@drawable/ic_in_call_touch_merge_call"
/>
</FrameLayout>

<!-- "End call" -->
<Button android:id="@+id/endButton"
style="@style/InCallTouchButton"
android:layout_width="1dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="@string/onscreenEndCallText"
android:drawableTop="@drawable/ic_in_call_touch_end"
android:textColor="@color/incall_endButtonLabel"
/>

<!-- "Dialpad" -->
<Button android:id="@+id/dialpadButton"
style="@style/InCallTouchButton"
android:layout_width="1dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="@string/onscreenShowDialpadText"
/>
</LinearLayout>
<LinearLayout android:id="@+id/inCallControlsRow2"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<!-- "Bluetooth" -->
<ToggleButton android:id="@+id/bluetoothButton"
style="@style/InCallTouchToggleButton"
android:layout_width="1dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textOn="@string/onscreenBluetoothText"
android:textOff="@string/onscreenBluetoothText"
/>
<!-- "Mute" -->
<ToggleButton android:id="@+id/muteButton"
style="@style/InCallTouchToggleButton"
android:layout_width="1dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textOn="@string/onscreenMuteText"
android:textOff="@string/onscreenMuteText"
/>
<!-- "Speaker" -->
<ToggleButton android:id="@+id/speakerButton"
style="@style/InCallTouchToggleButton"
android:layout_width="1dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textOn="@string/onscreenSpeakerText"
android:textOff="@string/onscreenSpeakerText"
/>
</LinearLayout>

</LinearLayout>


加载代码布局:
/* package */ void initMenu() {
if (DBG) log("initMenu()...");

// Explicitly use the "icon menu" theme for the Views we create.
Context wrappedContext = new ContextThemeWrapper(
mInCallScreen,
com.android.internal.R.style.Theme_IconMenu);

mInCallMenuView = new InCallMenuView(wrappedContext, mInCallScreen);

//
// Create all possible InCallMenuView objects.
//

mManageConference = new InCallMenuItemView(wrappedContext);
mManageConference.setId(R.id.menuManageConference);
mManageConference.setOnClickListener(mInCallScreen);
mManageConference.setText(R.string.menu_manageConference);
mManageConference.setIconResource(com.android.internal.R.drawable.ic_menu_allfriends);

mShowDialpad = new InCallMenuItemView(wrappedContext);
mShowDialpad.setId(R.id.menuShowDialpad);
mShowDialpad.setOnClickListener(mInCallScreen);
mShowDialpad.setText(R.string.menu_showDialpad); // or "Hide dialpad" if it's open
mShowDialpad.setIconResource(R.drawable.ic_menu_dial_pad);

mEndCall = new InCallMenuItemView(wrappedContext);
mEndCall.setId(R.id.menuEndCall);
mEndCall.setOnClickListener(mInCallScreen);
mEndCall.setText(R.string.menu_endCall);
mEndCall.setIconResource(R.drawable.ic_menu_end_call);

mAddCall = new InCallMenuItemView(wrappedContext);
mAddCall.setId(R.id.menuAddCall);
mAddCall.setOnClickListener(mInCallScreen);
mAddCall.setText(R.string.menu_addCall);
mAddCall.setIconResource(android.R.drawable.ic_menu_add);

mSwapCalls = new InCallMenuItemView(wrappedContext);
mSwapCalls.setId(R.id.menuSwapCalls);
mSwapCalls.setOnClickListener(mInCallScreen);
mSwapCalls.setText(R.string.menu_swapCalls);
mSwapCalls.setIconResource(R.drawable.ic_menu_swap_calls);

mMergeCalls = new InCallMenuItemView(wrappedContext);
mMergeCalls.setId(R.id.menuMergeCalls);
mMergeCalls.setOnClickListener(mInCallScreen);
mMergeCalls.setText(R.string.menu_mergeCalls);
mMergeCalls.setIconResource(R.drawable.ic_menu_merge_calls);

// TODO: Icons for menu items we don't have yet:
// R.drawable.ic_menu_answer_call
// R.drawable.ic_menu_silence_ringer

mBluetooth = new InCallMenuItemView(wrappedContext);
mBluetooth.setId(R.id.menuBluetooth);
mBluetooth.setOnClickListener(mInCallScreen);
mBluetooth.setText(R.string.menu_bluetooth);
mBluetooth.setIndicatorVisible(true);

mSpeaker = new InCallMenuItemView(wrappedContext);
mSpeaker.setId(R.id.menuSpeaker);
mSpeaker.setOnClickListener(mInCallScreen);
mSpeaker.setText(R.string.menu_speaker);
mSpeaker.setIndicatorVisible(true);

mMute = new InCallMenuItemView(wrappedContext);
mMute.setId(R.id.menuMute);
mMute.setOnClickListener(mInCallScreen);
mMute.setText(R.string.menu_mute);
mMute.setIndicatorVisible(true);

mHold = new InCallMenuItemView(wrappedContext);
mHold.setId(R.id.menuHold);
mHold.setOnClickListener(mInCallScreen);
mHold.setText(R.string.menu_hold);
mHold.setIndicatorVisible(true);

mAnswerAndHold = new InCallMenuItemView(wrappedContext);
mAnswerAndHold.setId(R.id.menuAnswerAndHold);
mAnswerAndHold.setOnClickListener(mInCallScreen);
mAnswerAndHold.setText(R.string.menu_answerAndHold);

mAnswerAndEnd = new InCallMenuItemView(wrappedContext);
mAnswerAndEnd.setId(R.id.menuAnswerAndEnd);
mAnswerAndEnd.setOnClickListener(mInCallScreen);
mAnswerAndEnd.setText(R.string.menu_answerAndEnd);

mAnswer = new InCallMenuItemView(wrappedContext);
mAnswer.setId(R.id.menuAnswer);
mAnswer.setOnClickListener(mInCallScreen);
mAnswer.setText(R.string.menu_answer);

mIgnore = new InCallMenuItemView(wrappedContext);
mIgnore.setId(R.id.menuIgnore);
mIgnore.setOnClickListener(mInCallScreen);
mIgnore.setText(R.string.menu_ignore);

//
// Load all the items into the correct "slots" in the InCallMenuView.
//
// Row 0 is the topmost row onscreen, item 0 is the leftmost item in a row.
//
// Individual items may be disabled or hidden, but never move between
// rows or change their order within a row.
//
// TODO: these items and their layout ought be specifiable
// entirely in XML (just like we currently do with res/menu/*.xml
// files.)
//

// Row 0:
// This usually has "Show/Hide dialpad", but that gets replaced by
// "Manage conference" if a conference call is active.
PhoneApp app = PhoneApp.getInstance();
// As managing conference is only valid for GSM and not for CDMA
int phoneType = app.phone.getPhoneType();
if (phoneType == Phone.PHONE_TYPE_GSM) {
mInCallMenuView.addItemView(mManageConference, 0);
}
mInCallMenuView.addItemView(mShowDialpad, 0);

// Row 1:
mInCallMenuView.addItemView(mSwapCalls, 1);
mInCallMenuView.addItemView(mMergeCalls, 1);
mInCallMenuView.addItemView(mAddCall, 1);
mInCallMenuView.addItemView(mEndCall, 1);

// Row 2:
// In this row we see *either*bluetooth/speaker/mute/hold
// *or* answerAndHold/answerAndEnd, but never all 6 together.
// For CDMA only Answer or Ignore option is valid for a Call Waiting scenario
if (phoneType == Phone.PHONE_TYPE_CDMA) {
mInCallMenuView.addItemView(mAnswer, 2);
mInCallMenuView.addItemView(mIgnore, 2);
} else if (phoneType == Phone.PHONE_TYPE_GSM) {
mInCallMenuView.addItemView(mHold, 2);
mInCallMenuView.addItemView(mAnswerAndHold, 2);
mInCallMenuView.addItemView(mAnswerAndEnd, 2);
} else {
throw new IllegalStateException("Unexpected phone type: " + phoneType);
}
mInCallMenuView.addItemView(mMute, 2);
mInCallMenuView.addItemView(mSpeaker, 2);
mInCallMenuView.addItemView(mBluetooth, 2);

mInCallMenuView.dumpState();
}

根据上面InCallMenu的 mShowDialpad.setOnClickListener(mInCallScreen);来找到mInCallScreen的onClick这里没写this。呵呵。


找到InCallScreen的onClick方法:
//
// Callbacks for buttons / menu items.
//


public void onClick(View view) {
int id = view.getId();
if (VDBG) log("onClick(View " + view + ", id " + id + ")...");
if (VDBG && view instanceof InCallMenuItemView) {
InCallMenuItemView item = (InCallMenuItemView) view;
log("==> menu item! " + item);
}


// Most menu items dismiss the menu immediately once you click
// them.But some items (the "toggle" buttons) are different:
// they want the menu to stay visible for a second afterwards to
// give you feedback about the state change.
boolean dismissMenuImmediate = true;


switch (id) {
case R.id.menuAnswerAndHold:
if (VDBG) log("onClick: AnswerAndHold...");
internalAnswerCall();// Automatically holds the current active call
break;


case R.id.menuAnswerAndEnd:
if (VDBG) log("onClick: AnswerAndEnd...");
internalAnswerAndEnd();
break;


case R.id.menuAnswer:
if (DBG) log("onClick: Answer...");
internalAnswerCall();
break;


case R.id.menuIgnore:
if (DBG) log("onClick: Ignore...");
internalHangupRingingCall();
break;


case R.id.menuSwapCalls:
if (DBG) log("onClick: SwapCalls...");
internalSwapCalls();
break;


case R.id.menuMergeCalls:
if (VDBG) log("onClick: MergeCalls...");
PhoneUtils.mergeCalls(mPhone);
break;


case R.id.menuManageConference:
if (VDBG) log("onClick: ManageConference...");
// Show the Manage Conference panel.
setInCallScreenMode(InCallScreenMode.MANAGE_CONFERENCE);
break;


case R.id.menuShowDialpad:
if (VDBG) log("onClick: Show/hide dialpad...");
onShowHideDialpad();
break;


case R.id.manage_done:// mButtonManageConferenceDone
if (VDBG) log("onClick: mButtonManageConferenceDone...");
// Hide the Manage Conference panel, return to NORMAL mode.
setInCallScreenMode(InCallScreenMode.NORMAL);
break;


case R.id.menuSpeaker:
if (VDBG) log("onClick: Speaker...");
onSpeakerClick();
// This is a "toggle" button; let the user see the new state for a moment.
dismissMenuImmediate = false;
break;


case R.id.menuBluetooth:
if (VDBG) log("onClick: Bluetooth...");
onBluetoothClick();
// This is a "toggle" button; let the user see the new state for a moment.
dismissMenuImmediate = false;
break;


case R.id.menuMute:
if (VDBG) log("onClick: Mute...");
onMuteClick();
// This is a "toggle" button; let the user see the new state for a moment.
dismissMenuImmediate = false;
break;


case R.id.menuHold:
if (VDBG) log("onClick: Hold...");
onHoldClick();
// This is a "toggle" button; let the user see the new state for a moment.
dismissMenuImmediate = false;
break;


case R.id.menuAddCall:
if (VDBG) log("onClick: AddCall...");
PhoneUtils.startNewCall(mPhone);// Fires off an ACTION_DIAL intent
break;


case R.id.menuEndCall:
if (VDBG) log("onClick: EndCall...");
internalHangup();
break;


default:
if((mInCallScreenMode == InCallScreenMode.OTA_NORMAL
|| mInCallScreenMode == InCallScreenMode.OTA_ENDED)
&& otaUtils != null) {
otaUtils.onClickHandler(id);
} else {
Log.w(LOG_TAG,
"Got click from unexpected View ID " + id + " (View = " + view + ")");
}
break;
}


EventLog.writeEvent(EventLogTags.PHONE_UI_BUTTON_CLICK,
(view instanceof TextView) ? ((TextView) view).getText() : "");


// If the user just clicked a "stateful" menu item (i.e. one of
// the toggle buttons), we keep the menu onscreen briefly to
// provide visual feedback.Since we want the user to see the
// *new* current state, force the menu items to update right now.
//
// Note that some toggle buttons ("Hold" in particular) do NOT
// immediately change the state of the Phone.In that case, the
// updateItems() call below won't have any visible effect.
// Instead, the menu will get updated by the updateScreen() call
// that happens from onPhoneStateChanged().


if (!dismissMenuImmediate) {
// TODO: mInCallMenu.updateItems() is a very big hammer; it
// would be more efficient to update *only* the menu item(s)
// we just changed.(Doing it this way doesn't seem to cause
// a noticeable performance problem, though.)
if (VDBG) log("- onClick: updating menu to show 'new' current state...");
boolean okToShowMenu = mInCallMenu.updateItems(mPhone);
if (!okToShowMenu) {
// Uh oh.All we tried to do was update the state of the
// menu items, but the logic in InCallMenu.updateItems()
// just decided the menu shouldn't be visible at all!
// (That probably means that the call ended asynchronously
// while the menu was up.)
//
// That's OK; just make sure to take the menu down ASAP.
if (VDBG) log("onClick: Tried to update menu, but now need to take it down!");
dismissMenuImmediate = true;
}
}


// Any menu item counts as explicit "user activity".
PhoneApp.getInstance().pokeUserActivity();


// Finally, *any* action handled here closes the menu (either
// immediately, or after a short delay).
//
// Note that some of the clicks we handle here aren't even menu
// items in the first place, like the mButtonManageConferenceDone
// button.That's OK; if the menu is already closed, the
// dismissMenu() call does nothing.
dismissMenu(dismissMenuImmediate);
}

上面是debug的结果,但是我却有了疑问,因为发现有重复的地方。
onCreate-----initInCallScreen------>initInCallTouchUi------>
mInCallTouchUi = (InCallTouchUi) findViewById(R.id.inCallTouchUi);mInCallTouchUi.setInCallScreenInstance(this);

上面还没真正的初始化

在incall_screen 布局中</FrameLayout>整体布局的内部
<!-- In-call onscreen touch controls, used on some platforms. -->
<!-- TODO: if this widget ends up being totally unused on some platforms,
then this should probably be a ViewStub. -->
<com.android.phone.InCallTouchUi
android:id="@+id/inCallTouchUi"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

而这个的初始化
publicInCallTouchUi(Context context, AttributeSet attrs) {
super(context, attrs);

if (DBG) log("InCallTouchUi constructor...");
if (DBG) log("- this = " + this);
if (DBG) log("- context " + context + ", attrs " + attrs);

// Inflate our contents, and add it (to ourself) as a child.
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(
R.layout.incall_touch_ui,// resource
this, // root
true);

mApplication = PhoneApp.getInstance();

// The various touch UI features are enabled on a per-product
// basis.(These flags in config.xml may be overridden by
// product-specific overlay files.)

mAllowIncomingCallTouchUi = getResources().getBoolean(R.bool.allow_incoming_call_touch_ui);
if (DBG) log("- incoming call touch UI: "
+ (mAllowIncomingCallTouchUi ? "ENABLED" : "DISABLED"));
mAllowInCallTouchUi = getResources().getBoolean(R.bool.allow_in_call_touch_ui);
if (DBG) log("- regular in-call touch UI: "
+ (mAllowInCallTouchUi ? "ENABLED" : "DISABLED"));
}

关乎这个布局的 // View.OnClickListener implementation
public void onClick(View view) {
int id = view.getId();
if (DBG) log("onClick(View " + view + ", id " + id + ")...");

switch (id) {
case R.id.addButton:
case R.id.mergeButton:
case R.id.endButton:
case R.id.dialpadButton:
case R.id.bluetoothButton:
case R.id.muteButton:
case R.id.speakerButton:
case R.id.holdButton:
case R.id.swapButton:
case R.id.cdmaMergeButton:
// Clicks on the regular onscreen buttons get forwarded
// straight to the InCallScreen.
mInCallScreen.handleOnscreenButtonClick(id);
break;

default:
Log.w(LOG_TAG, "onClick: unexpected click: View " + view + ", id " + id);
break;
}
}


/* package */ void handleOnscreenButtonClick(int id) {
if (DBG) log("handleOnscreenButtonClick(id " + id + ")...");

switch (id) {
// TODO: since every button here corresponds to a menu item that we
// already handle in onClick(), maybe merge the guts of these two
// methods into a separate helper that takes an ID (of either a menu
// item *or* touch button) and does the appropriate user action.

// Actions while an incoming call is ringing:
case R.id.answerButton:
internalAnswerCall();
break;
case R.id.rejectButton:
internalHangupRingingCall();
break;

// The other regular (single-tap) buttons used while in-call:
case R.id.holdButton:
onHoldClick();
break;
case R.id.swapButton:
internalSwapCalls();
break;
case R.id.endButton:
internalHangup();
break;
case R.id.dialpadButton:
onShowHideDialpad();
break;
case R.id.bluetoothButton:
onBluetoothClick();
break;
case R.id.muteButton:
onMuteClick();
break;
case R.id.speakerButton:
onSpeakerClick();
break;
case R.id.addButton:
PhoneUtils.startNewCall(mPhone);// Fires off an ACTION_DIAL intent
break;
case R.id.mergeButton:
case R.id.cdmaMergeButton:
PhoneUtils.mergeCalls(mPhone);
break;
case R.id.manageConferencePhotoButton:
// Show the Manage Conference panel.
setInCallScreenMode(InCallScreenMode.MANAGE_CONFERENCE);
break;

default:
Log.w(LOG_TAG, "handleOnscreenButtonClick: unexpected ID " + id);
break;
}

// Just in case the user clicked a "stateful" menu item (i.e. one
// of the toggle buttons), we force the in-call buttons to update,
// to make sure the user sees the *new* current state.
//
// (But note that some toggle buttons may *not* immediately change
// the state of the Phone, in which case the updateInCallTouchUi()
// call here won't have any visible effect.Instead, those
// buttons will get updated by the updateScreen() call that gets
// triggered when the onPhoneStateChanged() event comes in.)
//
// TODO: updateInCallTouchUi() is overkill here; it would be
// more efficient to update *only* the affected button(s).
// Consider adding API for that.(This is lo-pri since
// updateInCallTouchUi() is pretty cheap already...)
updateInCallTouchUi();
}

debug日志看出setContentView(R.layout.incall_screen);这个开始初始化InCallTouchUi构造方法
<com.android.phone.InCallTouchUi
android:id="@+id/inCallTouchUi"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

在后期发现那个onCreate永远进不去了,因为它只加载一次。

03-31 13:02:11.653: INFO/Archermind(119): InCallScreen class onCreate method start
03-31 13:02:48.553: INFO/Archermind(119): InCallTouchUi class InCallTouchUi method start
03-31 13:03:25.783: INFO/Archermind(119): InCallTouchUi class InCallTouchUi method end
03-31 13:03:31.734: INFO/Archermind(119): InCallTouchUi class onFinishInflate method start
03-31 13:03:32.024: INFO/Archermind(119): InCallTouchUi class onFinishInflate method end
03-31 13:03:32.283: INFO/Archermind(119): InCallScreen class initInCallScreen method start
03-31 13:03:32.283: INFO/Archermind(119): InCallScreen class initInCallTouchUi method start
03-31 13:03:32.303: INFO/Archermind(119): InCallScreen class initInCallTouchUi method end
03-31 13:03:32.303: INFO/Archermind(119): InCallScreen class initInCallScreen method end
03-31 13:03:32.423: INFO/Archermind(119): InCallScreen class onCreate method end


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics