1 用户界面
用户打开拨号应用(Dialer)
拨号应用的主界面,通常包含一个DialpadFragment用于显示拨号键盘,以及一个ContactsFragment用于显示联系人列表。
/packages/apps/Dialer/java/com/android/dialer/dialpadview/DialpadFragment.java
DialpadFragment是显示拨号键盘的Fragment。它包含一个数字键盘和一个输入框,用于用户输入电话号码。
/packages/apps/Dialer/java/com/android/dialer/contactsfragment/ContactsFragment.java
ContactsFragment是显示联系人列表的Fragment。
public void onClick(View view) {
int resId = view.getId();
if (resId == R.id.dialpad_floating_action_button) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
handleDialButtonPressed();
} else if (resId == R.id.deleteButton) {
keyPressed(KeyEvent.KEYCODE_DEL);
} else if (resId == R.id.digits) {
if (!isDigitsEmpty()) {
digits.setCursorVisible(true);
}
} else if (resId == R.id.dialpad_overflow) {
overflowPopupMenu.show();
} else {
LogUtil.w("DialpadFragment.onClick", "Unexpected event from: " + view);
}
}
根据被点击的ID来执行不同操作:
- dialpad_floating_action_button:执行触觉反馈performHapticFeedback()并调用handleDialButtonPressed()方法来处理拨号按钮的点击事件。
- deleteButton:删除按键
- digits: 数字按钮区域
2 输入处理:
handleDialButtonPressed() 方法
当用户点击拨号按钮时,会调用 handleDialButtonPressed() 方法。这个方法主要做以下几件事:
检查输入的号码是否为空:如果号码为空,则根据当前电话的状态执行特定操作。
检查号码是否被禁止:如果号码符合被禁止的正则表达式模式,则显示错误并清除拨号盘。
拨打号码:如果号码不为空且不被禁止,则使用 PreCall.start() 方法发起通话。
空号码处理:如果号码为空,并且设备是CDMA类型且正在通话中,则发送一个空的Flash信号(用于某些CDMA网络的特殊处理)。否则,显示最后拨打的号码或发出错误提示音。
非空号码处理:如果号码不为空,它会创建一个 CallIntentBuilder 对象,用于构建发起通话的意图,并传递用户输入的号码。然后调用 PreCall.start() 方法来启动通话。
隐藏拨号盘:无论拨打成功与否,都会调用 hideAndClearDialpad() 方法来隐藏拨号盘并清除输入的号码。
private void handleDialButtonPressed() {
if (isDigitsEmpty()) { // No number entered.
// No real call made, so treat it as a click
PerformanceReport.recordClick(UiAction.Type.PRESS_CALL_BUTTON_WITHOUT_CALLING);
handleDialButtonClickWithEmptyDigits();
} else {
final String number = digits.getText().toString();
// "persist.radio.otaspdial" is a temporary hack needed for one carrier's automated
// test equipment.
// TODO: clean it up.
if (number != null
&& !TextUtils.isEmpty(prohibitedPhoneNumberRegexp)
&& number.matches(prohibitedPhoneNumberRegexp)) {
PerformanceReport.recordClick(UiAction.Type.PRESS_CALL_BUTTON_WITHOUT_CALLING);
LogUtil.i(
"DialpadFragment.handleDialButtonPressed",
"The phone number is prohibited explicitly by a rule.");
if (getActivity() != null) {
DialogFragment dialogFragment =
ErrorDialogFragment.newInstance(R.string.dialog_phone_call_prohibited_message);
dialogFragment.show(getFragmentManager(), "phone_prohibited_dialog");
}
// Clear the digits just in case.
clearDialpad();
} else {
PreCall.start(getContext(), new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD));
hideAndClearDialpad();
}
}
}
PreCall.start() 方法用于实际发起通话。它接受一个上下文和一个 CallIntentBuilder 对象,后者用于构建拨打电话的意图,CallIntentBuilder 类用于构建拨打电话的意图。它接受一个电话号码和通话初始化类型。