/**
* @author 江忠锦
* http://blog.csdn.net/u012913972
* 我的新浪博客: 奋进的江
*/
在DialpadFragment 中执行dialButtonPressed()方法:
/**
* Called by the containing Activity to tell this Fragment that the dial button has been
* pressed.
*/
public void dialButtonPressed() {
mHaptic.vibrate();
handleDialButtonPressed();
}
震动一下后,开始执行handleDialButtonPressed();
private void handleDialButtonPressed() {
if (isDigitsEmpty() && (mRecipients == null || !mRecipients.isShown())) {
// No number entered.
handleDialButtonClickWithEmptyDigits();
} else {
boolean isDigitsShown = mDigits.isShown();
final String number = isDigitsShown ? mDigits.getText().toString() :
mRecipients.getText().toString().trim();
if (isDigitsShown && isDigitsEmpty()) {
handleDialButtonClickWithEmptyDigits();
} else if (mAddParticipant && isDigitsEmpty() && mRecipients.isShown()
&& isRecipientEmpty()) {
// mRecipients must be empty
// TODO add support for conference URI in last number dialed
// use ErrorDialogFragment instead? also see
// android.app.AlertDialog
android.widget.Toast.makeText(getActivity(),
"Error: Cannot dial. Please provide conference recipients.",
android.widget.Toast.LENGTH_SHORT).show();
} else {
// "persist.radio.otaspdial" is a temporary hack needed for one carrier's automated
// test equipment.
// TODO: clean it up.
if (number != null
&& !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
&& number.matches(mProhibitedPhoneNumberRegexp)) {
Log.i(TAG, "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 {
final Intent intent = CallUtil.getCallIntent(number,
(getActivity() instanceof DialtactsActivity ?
((DialtactsActivity) getActivity()).getCallOrigin() : null));
if (!isDigitsShown) {
// must be dial conference add extra
intent.putExtra(TelephonyProperties.EXTRA_DIAL_CONFERENCE_URI, true);
}
intent.putExtra(ADD_PARTICIPANT_KEY, mAddParticipant);
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
hideAndClearDialpad(false);
}
}
}
}
上面大部分是处理一些特殊的情况,比如在未按号码就按拨号,或则一些特殊的号码的情况,此刻我只关注最一般的情况就是最后一个else的情况:
else {
final Intent intent = CallUtil.getCallIntent(number,
(getActivity() instanceof DialtactsActivity ?
((DialtactsActivity) getActivity()).getCallOrigin() : null));
if (!isDigitsShown) {
// must be dial conference add extra
intent.putExtra(TelephonyProperties.EXTRA_DIAL_CONFERENCE_URI, true);
}
intent.putExtra(ADD_PARTICIPANT_KEY, mAddParticipant);
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
hideAndClearDialpad(false);
}
在此启动了一个activity,它去了哪里呢?
现看CallUtil
import com.android.contacts.common.CallUtil;
这个类来自ContactsCommon,在这个类的getCallIntent方法
/**
* A variant of {@link #getCallIntent(android.net.Uri)} but also accept a call
* origin and {@code Account} and {@code VideoCallProfile} state.
* For more information about call origin, see comments in Phone package (PhoneApp).
*/
public static Intent getCallIntent(
Uri uri, String callOrigin, PhoneAccountHandle accountHandle, int videoState) {
final Intent intent = new Intent(Intent.ACTION_CALL, uri);
intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
if (callOrigin != null) {
intent.putExtra(PhoneConstants.EXTRA_CALL_ORIGIN, callOrigin);
}
if (accountHandle != null) {
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
}
return intent;
}
获得的是一个ACTION_CALL的intent,而与之对应的Activity是Telephony中的OutgoingCallBroadcaster
AndroidManifest.xml中
<activity android:name="OutgoingCallBroadcaster"
android:enabled="false"
android:theme="@style/OutgoingCallBroadcasterTheme"
android:permission="android.permission.CALL_PHONE"
android:screenOrientation="nosensor"
android:configChanges="orientation|screenSize|keyboardHidden"
android:excludeFromRecents="true">
<!-- CALL action intent filters, for the various ways
of initiating an outgoing call. -->
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
<intent-filter android:icon="@drawable/ic_launcher_sip_call">
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sip" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="voicemail" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/phone" />
<data android:mimeType="vnd.android.cursor.item/phone_v2" />
<data android:mimeType="vnd.android.cursor.item/person" />
</intent-filter>
</activity>
OutgoingCallBroadcaster继承与Activity 是一个没有界面的Activity,起到路由过滤的作用:
在其onCreate中最重要的工作就是执行processIntent(intent);
在此方法中会判断去电是个什么类型,是紧急拨号还是正常去电还是Sip去电等,其中控制正常拨号的流程是通过发送广播出去
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
if (number != null) {
broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
}
CallGatewayManager.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());
// Need to raise foreground in-call UI as soon as possible while allowing 3rd party app
// to intercept the outgoing call.
broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
if (DBG) Log.v(TAG, " - Broadcasting intent: " + broadcastIntent + ".");
// Set a timer so that we can prepare for unexpected delay introduced by the broadcast.
// If it takes too much time, the timer will show "waiting" spinner.
// This message will be removed when OutgoingCallReceiver#onReceive() is called before the
// timeout.
mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,
OUTGOING_CALL_TIMEOUT_THRESHOLD);
sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
PERMISSION, new OutgoingCallReceiver(),
null, // scheduler
Activity.RESULT_OK, // initialCode
number, // initialData: initial value for the result data
null); // initialExtras
接收该广播的是它的内部类 OutgoingCallReceiver