Dialer
service/telecomm
service/telephony
framework/base/telecom 这个包中的全部可以给第三方调用
DialerUtils.java 的作用提供一些工具方法给Dialer进行处理
public static void startActivityWithErrorToast(
final Context context, final Intent intent, int msgId) {
try {
if ((Intent.ACTION_CALL.equals(intent.getAction()))) {
......
if (shouldWarnForOutgoingWps(context, intent.getData().getSchemeSpecificPart())) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.outgoing_wps_warning);//弹出对话框 拨打 WPS 电话会中断现有通话。
builder.setPositiveButton(
R.string.dialog_continue,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
placeCallOrMakeToast(context, intent);
}
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.create().show();
} else {
placeCallOrMakeToast(context, intent);//核心
}
} else {
context.startActivity(intent);
}
} catch (ActivityNotFoundException e) {
Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
}
}
private static void placeCallOrMakeToast(Context context, Intent intent) {
final boolean hasCallPermission = TelecomUtil.placeCall(context, intent);//核心入口
}
TelecomUtil.java 提供通话工具
public static boolean placeCall(Context context, Intent intent) {
if (hasCallPhonePermission(context)) {
// 核心,主过程 这个方法主要是调用TelecomManager.placeCall();//TelecomManager.java属于Framework/Telephony代码
getTelecomManager(context).placeCall(intent.getData(), intent.getExtras());
return true;
}
return false;
}
base/telecomm主要的作用是提供接口给外部进行调用,比如短信,联系人 等等.....
TelecomManager.java
public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService(); //获取到服务对象
if (service != null) {
if (address == null) {
Log.w(TAG, "Cannot place call to empty address.");
}
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}
进入System进程TelecomService是属于系统框架向外提供的服务,随着系统启动而启动,并由TelecomManager向外提供访问接。在TelecomSystem第一次绑定时(系统初始化的时候会进行绑定,并不是在打电话的时候才绑定),TelecomSystem会被初始化期间构建一些列必须资源,包括Phone和CI(和底层沟通的对象)的构建
@Override
public IBinder onBind(Intent intent) {
Log.d(this, "onBind");
initializeTelecomSystem(this);//系统初始化的时候就会进行绑定,并不是在打电话的时候才绑定),TelecomSystem 会被初始化,期间构建一些列必须资源,包括Phone和CI(和底层沟通的对象)的构建
synchronized (getTelecomSystem().getLock()) {
return getTelecomSystem().getTelecomServiceImpl().getBinder();
}
}
static void initializeTelecomSystem(Context context) {
if (TelecomSystem.getInstance() == null) {
.....
// TelecomSystem被初始化 构造都是在打电话前执行的
TelecomSystem.setInstance(
new TelecomSystem(
context,
new MissedCallNotifierImpl.MissedCallNotifierImplFactory() {
@Override
public MissedCallNotifierImpl makeMissedCallNotifierImpl(
Context context,
PhoneAccountRegistrar phoneAccountRegistrar,
DefaultDialerCache defaultDialerCache) {
return new MissedCallNotifierImpl(context,
phoneAccountRegistrar, defaultDialerCache);
}
},
.....
.......
........
}
if (BluetoothAdapter.getDefaultAdapter() != null) {
context.startService(new Intent(context, BluetoothPhoneService.class));
}
}
TelecomSystem 系统进程中,通话模块的核心
TelecomSystem 构造函数
public TelecomSystem(
Context context,
......) {
mContext = context.getApplicationContext();
......
.....
// 构建CallsManager
mCallsManager = new CallsManager(
mContext,
mLock,
mContactsAsyncHelper,
..........);
mIncomingCallNotifier = incomingCallNotifier;
incomingCallNotifier.setCallsManagerProxy(......)
mCallsManager.setIncomingCallNotifier(mIncomingCallNotifier);
mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
//注册广播
mContext.registerReceiver(mUserSwitchedReceiver, USER_SWITCHED_FILTER);
mContext.registerReceiver(mUserStartingReceiver, USER_STARTING_FILTER);
mContext.registerReceiver(mBootCompletedReceiver, BOOT_COMPLETE_FILTER);
mBluetoothPhoneServiceImpl = bluetoothPhoneServiceImplFactory.makeBluetoothPhoneServiceImpl(
mContext, mLock, mCallsManager, mPhoneAccountRegistrar);
// 构建CallIntentProcessor, 执行Intent的请求
mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);
mTelecomBroadcastIntentProcessor = new TelecomBroadcastIntentProcessor(
mContext, mCallsManager);
// Register the receiver for the dialer secret codes, used to enable extended logging.
mDialerCodeReceiver = new DialerCodeReceiver(mCallsManager);
mContext.registerReceiver(mDialerCodeReceiver, DIALER_SECRET_CODE_FILTER,
Manifest.permission.CONTROL_INCALL_EXPERIENCE, null);
// 构建TelecomServiceImpl,这个是TelecomSystem的真正实现,返回的binder由这里提供,
// 外部对TelecomService的操作实际上都是在TelecomServiceImpl里面进行的。
mTelecomServiceImpl = new TelecomServiceImpl(
mContext, mCallsManager, mPhoneAccountRegistrar,
new CallIntentProcessor.AdapterImpl(),
new UserCallIntentProcessorFactory() {
@Override
public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
return new UserCallIntentProcessor(context, userHandle);
}
},
defaultDialerCache,
new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
mLock);
Log.endSession();
}
上面的构造都是在打电话之前执行的,下面继续回到调起InCallUi流程
上面placeCall() 方法会进入到 TelecomServiceImpl.java中ITelecomService.Stub中的placeCall()方法,ITelecomService.Stub是一提供一个拨号入口。
@Override
public void placeCall(Uri handle, Bundle extras, String callingPackage) {
try {
Log.startSession("TSI.pC");
enforceCallingPackage(callingPackage);//权限检查,传入对应的调用位置(调用位置org.codeaurora.dialer)
PhoneAccountHandle phoneAccountHandle = null;
if (extras != null) {
phoneAccountHandle = extras.getParcelable(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
if (extras.containsKey(TelecomManager.EXTRA_IS_HANDOVER)) {
// This extra is for Telecom use only so should never be passed in.
extras.remove(TelecomManager.EXTRA_IS_HANDOVER);
}
}
boolean isSelfManaged = phoneAccountHandle != null &&
isSelfManagedConnectionService(phoneAccountHandle);
if (isSelfManaged) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_OWN_CALLS,
"Self-managed ConnectionServices require MANAGE_OWN_CALLS permission.");
if (!callingPackage.equals(
phoneAccountHandle.getComponentName().getPackageName())
&& !canCallPhone(callingPackage,
"CALL_PHONE permission required to place calls.")) {
throw new SecurityException("Self-managed ConnectionServices can only "
+ "place calls through their own ConnectionService.");
}
} else if (!canCallPhone(callingPackage, "placeCall")) {
throw new SecurityException("Package " + callingPackage
+ " is not allowed to place phone calls");
}
final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
PackageManager.PERMISSION_GRANTED;
final boolean hasCallPrivilegedPermission = mContext.checkCallingPermission(
CALL_PRIVILEGED) == PackageManager.PERMISSION_GRANTED;
synchronized (mLock) {
final UserHandle userHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
try {
final Intent intent = new Intent(hasCallPrivilegedPermission ?
Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, handle);
if (extras != null) {
extras.setDefusable(true);
intent.putExtras(extras);
}
// 核心,主过程
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, isSelfManaged ||
(hasCallAppOp && hasCallPermission),
true /* isLocalInvocation */);
} finally {
Binder.restoreCallingIdentity(token);
}
}
} finally {
Log.endSession();
}
}
接下来UserCallIntentProcessor.java主要处理一些 内部校验一些拨号的权限,以及其它操作权限看看是不是需要弹框拒绝。比如 《只允许打紧急电话,没有电话许可,此应用程序不能发出呼叫》
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency, boolean isLocalInvocation) {
// 确保无法调用的设备上没有处理调用意图。
if (!isVoiceCapable()) {
return;
}
String action = intent.getAction();
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
isLocalInvocation); //调用processOutgoingCallIntent()方法紧接着执行
}
}
// 核心,主过程 内部校验一些拨号的权限,以及其它操作权限看看是不是需要弹框拒绝。比如 《只允许打紧急电话,没有电话许可,此应用程序不能发出呼叫》
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency, boolean isLocalInvocation) {
Uri handle = intent.getData();
String scheme = handle.getScheme();
String uriString = handle.getSchemeSpecificPart();
// 确保使用TEL方案拨打的sip uri转换为sip方案。
if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) {
handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
}
//检查DISALLOW_OUTGOING_CALLS限制。注意:我们在托管配置文件用户中跳过此检查,因为总是可以通过复制和粘贴电话号码到个人拨号器来绕过此检查。
if (!UserUtil.isManagedProfile(mContext, mUserHandle)) {
// restriction. 只有使用DISALLOW_OUTGOING_CALLS限制的用户才允许使用紧急呼叫。
if (!TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
mUserHandle)) {
showErrorDialogForRestrictedOutgoingCall(mContext,
R.string.outgoing_call_not_allowed_user_restriction);
return;
} else if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
mUserHandle)) {
final DevicePolicyManager dpm =
mContext.getSystemService(DevicePolicyManager.class);
if (dpm == null) {
return;
}
final Intent adminSupportIntent = dpm.createAdminSupportIntent(
UserManager.DISALLOW_OUTGOING_CALLS);
if (adminSupportIntent != null) {
mContext.startActivity(adminSupportIntent);
}
return;
}
}
}
if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
showErrorDialogForRestrictedOutgoingCall(mContext,
R.string.outgoing_call_not_allowed_no_permission);
return;
}
int videoState = intent.getIntExtra(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY);
intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
isDefaultOrSystemDialer(callingPackageName));
//在将意图转发给主用户之前,保存当前用户的用户handle。
intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
// 核心,主过程 //检查一些权限后,执行那个下面代码发送广播
sendIntentToDestination(intent, isLocalInvocation);
}
/**
* rebroadcasting it. 潜在地将意图传递给仅作为主要用户运行的广播接收器。如果调用方是电信服务的本地调用方,我们将发送意图给电信,而不进行重播。
*/
private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation) {
intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setClass(mContext, PrimaryCallReceiver.class); // //开启广播 最后进入到 PrimaryCallReceiver
if (isLocalInvocation) {
synchronized (TelecomSystem.getInstance().getLock()) {
TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent);
}
} else {
mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); //发送广播
}
return true;
}
接下来进入关播PrimaryCallReceiver中 ,PrimaryCallReceiver作为拨号的单一入口,其收到消息后就转给TelecomSystem中的CallIntentProcessor进行处理
@Override
public void onReceive(Context context, Intent intent) {//作为拨号的单一入口, 其收到消息后,就转发给 TelecomSystem的
Log.startSession("PCR.oR");
synchronized (getTelecomSystem().getLock()) {
getTelecomSystem().getCallIntentProcessor().processIntent(intent);//调用所有呼出和呼入电话的单一入口
}
Log.endSession();
}
public void processIntent(Intent intent) {
final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);
Trace.beginSection("processNewCallCallIntent");
if (isUnknownCall) {//判断是否为空号码
processUnknownCallIntent(mCallsManager, intent);//如果是一个空号码执行这一步
} else {
processOutgoingCallIntent(mContext, mCallsManager, intent);//否则执行这一步
}
Trace.endSection();
}
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent) {
Uri handle = intent.getData();
String scheme = handle.getScheme();
String uriString = handle.getSchemeSpecificPart();
boolean isSkipSchemaParsing = intent.getBooleanExtra(
TelephonyProperties.EXTRA_SKIP_SCHEMA_PARSING, false);
Log.d(CallIntentProcessor.class, "isSkipSchemaParsing = " + isSkipSchemaParsing);
if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString) && !isSkipSchemaParsing) {
handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
}
PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
Bundle clientExtras = null;
if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
}
if (clientExtras == null) {
clientExtras = new Bundle();
}
if (isSkipSchemaParsing) {
clientExtras.putBoolean(TelephonyProperties.EXTRA_SKIP_SCHEMA_PARSING,
isSkipSchemaParsing);
handle = Uri.fromParts(PhoneAccount.SCHEME_TEL, handle.toString(), null);
}
boolean isConferenceUri = intent.getBooleanExtra(
TelephonyProperties.EXTRA_DIAL_CONFERENCE_URI, false);
Log.d(CallIntentProcessor.class, "isConferenceUri = "+isConferenceUri);
if (isConferenceUri) {
clientExtras.putBoolean(TelephonyProperties.EXTRA_DIAL_CONFERENCE_URI, isConferenceUri);
}
boolean isAddParticipant = intent.getBooleanExtra(
TelephonyProperties.ADD_PARTICIPANT_KEY, false);
Log.d(CallIntentProcessor.class, "isAddparticipant = "+isAddParticipant);
if (isAddParticipant) {
clientExtras.putBoolean(TelephonyProperties.ADD_PARTICIPANT_KEY, isAddParticipant);
}
if (intent.hasExtra(TelecomManager.EXTRA_CALL_SUBJECT)) {
String callsubject = intent.getStringExtra(TelecomManager.EXTRA_CALL_SUBJECT);
clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject);
}
final int callDomain = intent.getIntExtra(
QtiCallConstants.EXTRA_CALL_DOMAIN, QtiCallConstants.DOMAIN_AUTOMATIC);
Log.d(CallIntentProcessor.class, "callDomain = " + callDomain);
clientExtras.putInt(QtiCallConstants.EXTRA_CALL_DOMAIN, callDomain);
final int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY);
clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
if (!callsManager.isSelfManaged(phoneAccountHandle,
(UserHandle) intent.getParcelableExtra(KEY_INITIATING_USER))) {
boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent);
if (fixedInitiatingUser) {
Toast.makeText(context, R.string.toast_personal_call_msg, Toast.LENGTH_LONG).show();
}
} else {
Log.i(CallIntentProcessor.class,
"processOutgoingCallIntent: skip initiating user check");
}
UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);
TelecomManager telecomManager =
(TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
List mSubscriptionAccountHandles = telecomManager.getCallCapablePhoneAccounts();
boolean isDualCard = (mSubscriptionAccountHandles != null && mSubscriptionAccountHandles.size() > 1);
if(isDualCard) {
String phoneNumber = intent.getData().getSchemeSpecificPart();
phoneNumber = PhoneNumberUtils.stripSeparators(phoneNumber);
int simGroup = SimSelectDialog.getCardByNumber(context, phoneNumber) - 1;
if (simGroup >= 0) {
if (phoneAccountHandle == null) {
phoneAccountHandle = telecomManager.getUserSelectedOutgoingPhoneAccount();
}
if (phoneAccountHandle != null) {
if (!phoneAccountHandle.equals(mSubscriptionAccountHandles.get(simGroup))) {
......
}
/**end*/
// 创建一个call.startOutgoingCall 新建一个(或者重用) call, 将CallsManager绑定监听该 call, 然后通知 callsManager 的监听者, 添加了一个 call
// Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
Call call = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
intent);
//这是一个断点,因为下面将会详细地深入分析 callsManager.startOutgoingCall 的流程,下面分析 startOutgoingCall 完成后, 再从 NewOutgoingCallIntentBroadcaster.processIntent()往下分析
if (call != null) {
sendNewOutgoingCallIntent(context, call, callsManager, intent);//拿到上面创建的call, 进行下一步
}
}
这里重点看callsManager.startOutgoingCall(......);这里就是调起InCallUi的入口,startOutgoingCall新建一个(或者重用)call,将CallManager绑定监听该call,然后通知callsManager的监听,添加了一个call
sendNewOutgoingCallIntent()方法
static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,
Intent intent) {
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
isPrivilegedDialer);
final int result = broadcaster.processIntent(); //核心入口
......
}
@VisibleForTesting
public int processIntent() {
Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");
Intent intent = mIntent;
String action = intent.getAction();
final Uri handle = intent.getData();
if (handle == null) {
Log.w(this, "Empty handle obtained from the call intent.");
return DisconnectCause.INVALID_NUMBER;
}
boolean isVoicemailNumber = PhoneAccount.SCHEME_VOICEMAIL.equals(handle.getScheme());
if (isVoicemailNumber) {
if (Intent.ACTION_CALL.equals(action)
|| Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
// 语音邮件呼叫将由电话连接管理器直接处理
boolean speakerphoneOn = mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
placeOutgoingCallImmediately(mCall, handle, null, speakerphoneOn,
VideoProfile.STATE_AUDIO_ONLY);//核心入口
return DisconnectCause.NOT_DISCONNECTED;
} else {
Log.i(this, "Unhandled intent %s. Ignoring and not placing call.", intent);
return DisconnectCause.OUTGOING_CANCELED;
}
}
........
return DisconnectCause.NOT_DISCONNECTED;
}
private void placeOutgoingCallImmediately(Call call, Uri handle, GatewayInfo gatewayInfo,
boolean speakerphoneOn, int videoState) {
Log.i(this,
"Placing call immediately instead of waiting for OutgoingCallBroadcastReceiver");
// 准备开启广播进行呼叫
mCall.setNewOutgoingCallIntentBroadcastIsDone();
mCallsManager.placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState);//核心入口
}
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
boolean speakerphoneOn, int videoState) {
if (call == null) {
// 如果不存在就退出
return;
}
final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();
if (gatewayInfo == null) {
} else {
call.setHandle(uriHandle);
call.setGatewayInfo(gatewayInfo);
final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
R.bool.use_speaker_when_docked);
final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);
// Auto-enable speakerphone if the originating intent specified to do so, if the call
// is a video call, of if using speaker when docked
call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
|| (useSpeakerWhenDocked && useSpeakerForDock));
call.setVideoState(videoState);
if (speakerphoneOn) {
Log.i(this, "%s Starting with speakerphone as requested", call);
} else if (useSpeakerWhenDocked && useSpeakerForDock) {
Log.i(this, "%s Starting with speakerphone because car is docked.", call);
} else if (useSpeakerForVideoCall) {
Log.i(this, "%s Starting with speakerphone because its a video call.", call);
}
if (call.isEmergencyCall()) {
new AsyncEmergencyContactNotifier(mContext).execute();
}
final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_requireCallCapableAccountForHandle);
final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call,
call.getTargetPhoneAccount());
final String callHandleScheme =
call.getHandle() == null ? null : call.getHandle().getScheme();
if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
// If the account has been set, proceed to place the outgoing call.
// Otherwise the connection will be initiated when the account is set by the user.
if (call.isSelfManaged() && !isOutgoingCallPermitted) {
notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call);
} else {
if (call.isEmergencyCall()) {
// Drop any ongoing self-managed calls to make way for an emergency call
disconnectSelfManagedCalls("place emerg call" /* reason */);
}
if (mPendingMOEmerCall == null) {
//如果已设置帐户,则继续拨打呼出电话。否则,当用户设置帐户时将启动连接。
call.startCreateConnection(mPhoneAccountRegistrar);//核心入口
}
}
} else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
requireCallCapableAccountByHandle ? callHandleScheme : null, false,
call.getInitiatingUser()).isEmpty()) {
markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
"No registered PhoneAccounts"));
markCallAsRemoved(call);
}
}
//启动创建连接序列。完成后,应该存在通过连接服务的活动连接(
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
if (mCreateConnectionProcessor != null) {
return;
}
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext); //Call 由 CallsManager 维护的拨号,或者来电实例
mCreateConnectionProcessor.process();//核心入口
}
@VisibleForTesting
public void process() {
Log.v(this, "process");
clearTimeout();
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
if (!mCall.isSelfManaged()) {
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());
}
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();//核心入口
}
private void attemptNextPhoneAccount() {
......
if (mCallResponse != null && attempt != null) {
Log.i(this, "Trying attempt %s", attempt);
PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
mService = mRepository.getService(phoneAccount.getComponentName(),
phoneAccount.getUserHandle());// 取到一个 ConnectionServiceWrapper (有缓存)
if (mService == null) {
Log.i(this, "Found no connection service for attempt %s", attempt);
attemptNextPhoneAccount();
} else {
mConnectionAttempt++;
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(mService);
setTimeoutIfNeeded(mService, attempt);
if (mCall.isIncoming()) {
mService.createConnection(mCall, CreateConnectionProcessor.this); // 开始进行链接,核心过程
} else {
// Start to create the connection for outgoing call after the ConnectionService
// of the call has gained the focus.
mCall.getConnectionServiceFocusManager().requestFocus(
mCall,
new CallsManager.RequestCallback(new CallsManager.PendingAction() {
@Override
public void performAction() {
Log.d(this, "perform create connection");
mService.createConnection(
mCall,
CreateConnectionProcessor.this);
}
}));
}
}
} else {
DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?
mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);
notifyCallConnectionFailure(disconnectCause);
}
}
ConnectionServiceWrapper 负责和 Telephony 沟通 framework/base/telephony
创建链接就是一个绑定服务的过程
/**
* 为新的传出呼叫或附加到现有的传入呼叫创建新连接。
*/
@VisibleForTesting
public void createConnection(final Call call, final CreateConnectionResponse response) {//创建链接就是一个绑定服务的过程
Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {// 链接创建成功后 onSuccess 会被调用
@Override
public void onSuccess() {
.......
........
try {
mServiceInterface.createConnection( // 通过远程接口创建链接 利用远程接口创建一个通话链接
call.getConnectionManagerPhoneAccount(),
callId,
connectionRequest,
call.shouldAttachToExistingConnection(),
call.isUnknown(),
Log.getExternalSession());
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
mPendingResponses.remove(callId).handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
}
}
@Override
public void onFailure() {
....
}
};
//绑定
mBinder.bind(callback, call);
}
进入mBinder.bind中 ConnectionSerivceWrapper.java是ServiceBinder的子类
bind是进行绑定服务,回调里面的BindCallbak才会创建
void bind(BindCallback callback, Call call) {
......
//在类里面绑定成功后mBinder.bind(callback, call);在父类ServiceBinder类里面mCallbacks.add(callback);吧回调用集合给装载起来,然后进行便利数据
//成功获取到aidl接口后将其赋值mServiceInterface,
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection(call);
final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
final boolean isBound;
if (mUserHandle != null) {// 进行绑定
isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags, //如果绑定成功调用connection方法 这里绑定是绑定了framework/telepony
mUserHandle);
} else {
isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
}
if (!isBound) {
handleFailedConnection();
return;
}
} else {
Log.d(ServiceBinder.this, "Service is already bound.");
Preconditions.checkNotNull(mBinder);
handleSuccessfulConnection();
}
}
}
这里绑定的是ConnectionSerivce 如果绑定成功调用connection方法 这里绑定的是framework/telecomm中的ConnectionSerivce
执行到bindSerivce就已经初始化ConnectionSerivce了 ,然后回调connection,connection继承了SeviceConnection,所以连接成功后会回调回来。
private final class ServiceBinderConnection implements ServiceConnection {
/**
* 绑定服务的初始调用。
*/
private Call mCall;
ServiceBinderConnection(Call call) {
mCall = call;
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
Log.startSession("SBC.oSC");
synchronized (mLock) {
Log.i(this, "Service bound %s", componentName);
Log.addEvent(mCall, LogUtils.Events.CS_BOUND, componentName);
mCall = null;
// 取消绑定请求被排队,因此立即取消绑定。
if (mIsBindingAborted) {
clearAbort();
logServiceDisconnected("onServiceConnected");
mContext.unbindService(this);
handleFailedConnection();
return;
}
if (binder != null) {
mServiceDeathRecipient = new ServiceDeathRecipient(componentName);
try {
binder.linkToDeath(mServiceDeathRecipient, 0);
mServiceConnection = this;
// 设置 mServiceInterface
// 会触发 ConnectionServiceWrapper.setServiceInterface ==> ConnectionServiceWrapper.addConnectionServiceAdapter
// 通过mServiceInterface,给绑定的服务,提供一个访问自己的接口
setBinder(binder);// 触发bind(BindCallback callback, Call call) 中 callback 的 onSuccess
handleSuccessfulConnection(); //回调进入子类
//整个绑定过程,只做2件事,一是给远程服务提供访问自己的接口,二是利用远程接口创建一个通话链接。
// 这2件事都是跨进程进行的。远程服务访问自己的接口是
} catch (RemoteException e) {
Log.w(this, "onServiceConnected: %s died.");
if (mServiceDeathRecipient != null) {
mServiceDeathRecipient.binderDied();
}
}
}
}
} finally {
Log.endSession();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {//连接失败
........
}
}
private void setBinder(IBinder binder) {
if (mBinder != binder) {
if (binder == null) {
......
} else {
mBinder = binder;
setServiceInterface(binder);//进入子类
}
}
}
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess(); //回调传入的callback
}
mCallbacks.clear();
}
这里的setBinder();
这个方法主要是调用子类去与ConnectionService进行绑定 ,绑定成功后可以进行随时改变InCallUI的状态 。
绑定的入口在ConnectionServiceWrapper.java中开始绑入口,在哪createConnection方法中
先看流程图 流程图从ConnectionSerivceWrapper中的createConnection入口
链接:https://blog.csdn.net/qq_35427437/article/details/101067804
ConnectionServiceWrapper.java中的BindCallback里面的onSuccess方法
public void onSuccess() {
.....
try {
mServiceInterface.createConnection( // 通过远程接口创建链接 利用远程接口创建一个通话链接
call.getConnectionManagerPhoneAccount(),
callId,
connectionRequest,
call.shouldAttachToExistingConnection(),
call.isUnknown(),
Log.getExternalSession());
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
mPendingResponses.remove(callId).handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
}
}
利用远程接口创建一个通话链接完成,进入createConnection中进行处理电话
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CREATE_CONN);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneAccount;
args.arg2 = id;
args.arg3 = request;
args.arg4 = Log.createSubsession();
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
} finally {
Log.endSession();
}
}
传递给Handler
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_CREATE_CONNECTION: { // 创建链接
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
try {
final PhoneAccountHandle connectionManagerPhoneAccount =
(PhoneAccountHandle) args.arg1;
final String id = (String) args.arg2;
final ConnectionRequest request = (ConnectionRequest) args.arg3;
final boolean isIncoming = args.argi1 == 1;
final boolean isUnknown = args.argi2 == 1;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init request %s", id);
mPreInitializationConnectionRequests.add(
new android.telecom.Logging.Runnable(
SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR",
null /*lock*/) {
@Override
public void loggedRun() {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
}.prepare());
} else {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
} finally {
args.recycle();
Log.endSession();
}
break;
}
}
进入createConnection()方法
private void createConnection(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
boolean isLegacyHandover = request.getExtras() != null &&
request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER, false);
boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
"isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b",
callManagerAccount, callId, request, isIncoming, isUnknown, isLegacyHandover,
isHandover);
Connection connection = null;
if (isHandover) {
PhoneAccountHandle fromPhoneAccountHandle = request.getExtras() != null
? (PhoneAccountHandle) request.getExtras().getParcelable(
TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT) : null;
if (!isIncoming) {
connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);
} else {
connection = onCreateIncomingHandoverConnection(fromPhoneAccountHandle, request);
}
} else {
connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);//onCreateOutgoingConnection拨号入口
}
if (connection == null) {
Log.i(this, "createConnection, implementation returned null connection.");
connection = Connection.createFailedConnection(
new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"));
}
connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
// 监听 Connection 的状态变化,通知 system 进程(CallsManager)更新
// 通过 system 进程提供的 adapter 实现
addConnection(request.getAccountHandle(), callId, connection);
}
Uri address = connection.getAddress();
String number = address == null ? "null" : address.getSchemeSpecificPart();
Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
//mAdapter.handleCreateConnectionComplete 调用回到 ConnectionServiceWrapper 的 handleCreateConnectionComplete,
// 然后回到 Call 的 handleCreateConnectionSuccess
mAdapter.handleCreateConnectionComplete(// 通知 system 进程(即CallsManager) 电话链接已经创建完成
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
connection.getSupportedAudioRoutes(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
connection.getCallerDisplayNamePresentation(),
connection.getVideoProvider() == null ?
null : connection.getVideoProvider().getInterface(),
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
connection.getConnectTimeMillis(),
connection.getConnectElapsedTimeMillis(),
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables()),
connection.getExtras()));
if (isIncoming && request.shouldShowIncomingCallUi() &&
(connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) ==
Connection.PROPERTY_SELF_MANAGED) {
// Tell ConnectionService to show its incoming call UX.
connection.onShowIncomingCallUi();
}
if (isUnknown) {
triggerConferenceRecalculate();
}
}
进入onCreateOutgoingConnection()方法这个方法在子类实现,而子类在packeger/service/telephony里面
TelephonyConnectionService.java
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
.....
....
if (resultConnection instanceof TelephonyConnection) {
if (request.getExtras() != null && request.getExtras().getBoolean(
TelecomManager.EXTRA_USE_ASSISTED_DIALING, false)) {
((TelephonyConnection) resultConnection).setIsUsingAssistedDialing(true);
}
placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);//进行拨号流程,主流程
return resultConnection;
}
}
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
placeOutgoingConnection(connection, phone, request.getVideoState(), request.getExtras());
}
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
String number = connection.getAddress().getSchemeSpecificPart();
boolean isAddParticipant = (extras != null) && extras
.getBoolean(TelephonyProperties.ADD_PARTICIPANT_KEY, false);
Log.d(this, "placeOutgoingConnection isAddParticipant = " + isAddParticipant);
updatePhoneAccount(connection, phone);
com.android.internal.telephony.Connection originalConnection = null;
try {
if (phone != null) {
if (isAddParticipant) {
phone.addParticipant(number);// 为紧急号码做一些处理
return;
} else {
originalConnection = phone.dial(number, new ImsPhone.ImsDialArgs.Builder() //呼叫
.setVideoState(videoState)
.setIntentExtras(extras)
.setRttTextStream(connection.getRttTextStream())
.build());
}
}
} catch (CallStateException e) { // 失败处理
Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
if (e.getError() == CallStateException.ERROR_OUT_OF_SERVICE) {
cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
} else if (e.getError() == CallStateException.ERROR_POWER_OFF) {
cause = android.telephony.DisconnectCause.POWER_OFF;
}
connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
cause, e.getMessage(), phone.getPhoneId()));
connection.clearOriginalConnection();
connection.destroy();
return;
}
if (originalConnection == null) { // 失败处理
int telephonyDisconnectCause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
// On GSM phones, null connection means that we dialed an MMI code
if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
Log.d(this, "dialed MMI code");
int subId = phone.getSubId();
Log.d(this, "subId: "+subId);
telephonyDisconnectCause = android.telephony.DisconnectCause.DIALED_MMI;
final Intent intent = new Intent(this, MMIDialogActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
}
startActivity(intent);
}
Log.d(this, "placeOutgoingConnection, phone.dial returned null");
connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
telephonyDisconnectCause, "Connection is null", phone.getPhoneId()));
connection.clearOriginalConnection();
connection.destroy();
} else {
connection.setOriginalConnection(originalConnection); // TelephonyConnection 监听 phone, 更新时,从originalConnection里面取。
//TelephonyConnection.setOriginalConnection 的实现, 目的主要是为将 mHandler 注册注册到
//phone 的监听者列表里面, phone 变化, 会触发 mHandler 里面的handleMessage 被调用。
}
}
placeOutgoingConnection只做2件事,一是使用对应的phone创建对应的连接,二是让TelephonyConnectijon和连接建立起关联,一个TelephonyConnection维护一个连接,Original变化会引起TelephonyCnnnection变化。
现在流程回到 phone.dial 只分析GSM类型的phone, GSMPhone.dial 如下
@Override
public Connection dial(String dialString, @NonNull DialArgs dialArgs)
throws CallStateException {
if (!isPhoneTypeGsm() && dialArgs.uusInfo != null) {
throw new CallStateException("Sending UUS information NOT supported in CDMA!");
}
boolean isEmergency = isEmergencyNumber(dialString);
Phone imsPhone = mImsPhone;
CarrierConfigManager configManager =
(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
boolean alwaysTryImsForEmergencyCarrierConfig = configManager.getConfigForSubId(getSubId())
.getBoolean(CarrierConfigManager.KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL);
boolean useImsForCall = isImsUseEnabled()
&& imsPhone != null
&& (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
(imsPhone.isVideoEnabled() && VideoProfile.isVideo(dialArgs.videoState)))
&& (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
&& !shallDialOnCircuitSwitch(dialArgs.intentExtras);
boolean useImsForEmergency = imsPhone != null
&& isEmergency
&& alwaysTryImsForEmergencyCarrierConfig
&& ImsManager.getInstance(mContext, mPhoneId).isNonTtyOrTtyOnVolteEnabled()
&& imsPhone.isImsAvailable();
String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
stripSeparators(dialString));
boolean isUt = (dialPart.startsWith("*") || dialPart.startsWith("#"))
&& dialPart.endsWith("#");
boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
if (DBG) {
logd("useImsForCall=" + useImsForCall
+ ", useImsForEmergency=" + useImsForEmergency
+ ", useImsForUt=" + useImsForUt
+ ", isUt=" + isUt
+ ", imsPhone=" + imsPhone
+ ", imsPhone.isVolteEnabled()="
+ ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")
+ ", imsPhone.isVowifiEnabled()="
+ ((imsPhone != null) ? imsPhone.isWifiCallingEnabled() : "N/A")
+ ", imsPhone.isVideoEnabled()="
+ ((imsPhone != null) ? imsPhone.isVideoEnabled() : "N/A")
+ ", imsPhone.getServiceState().getState()="
+ ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));
}
Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mPhoneId, mContext);
if ((useImsForCall && !isUt) || (isUt && useImsForUt) || useImsForEmergency) {
try {
if (DBG) logd("Trying IMS PS call");
return imsPhone.dial(dialString, dialArgs);
} catch (CallStateException e) {
if (DBG) logd("IMS PS call exception " + e +
"useImsForCall =" + useImsForCall + ", imsPhone =" + imsPhone);
// Do not throw a CallStateException and instead fall back to Circuit switch
// for emergency calls and MMI codes.
if (Phone.CS_FALLBACK.equals(e.getMessage()) || isEmergency) {
logi("IMS call failed with Exception: " + e.getMessage() + ". Falling back "
+ "to CS.");
} else {
CallStateException ce = new CallStateException(e.getMessage());
ce.setStackTrace(e.getStackTrace());
throw ce;
}
}
}
if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
&& mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
throw new CallStateException("cannot dial in current state");
}
// Check non-emergency voice CS call - shouldn't dial when POWER_OFF
if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */
&& !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
&& !isEmergency /* non-emergency call */
&& !(isUt && useImsForUt) /* not UT */) {
throw new CallStateException(
CallStateException.ERROR_POWER_OFF,
"cannot dial voice call in airplane mode");
}
// Check for service before placing non emergency CS voice call.
// Allow dial only if either CS is camped on any RAT (or) PS is in LTE service.
if (mSST != null
&& mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE /* CS out of service */
&& !(mSST.mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
&& ServiceState.isLte(mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE */
&& !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
&& !isEmergency /* non-emergency call */) {
throw new CallStateException(
CallStateException.ERROR_OUT_OF_SERVICE,
"cannot dial voice call in out of service");
}
if (DBG) logd("Trying (non-IMS) CS call");
if (isPhoneTypeGsm()) {
return dialInternal(dialString, new DialArgs.Builder<>()
.setIntentExtras(dialArgs.intentExtras)
.build());
} else {
return dialInternal(dialString, dialArgs);
}
}
进入dialInternal方法
@Override
protected Connection dialInternal(String dialString, DialArgs dialArgs)
throws CallStateException {
return dialInternal(dialString, dialArgs, null);
}
protected Connection dialInternal(String dialString, DialArgs dialArgs,
ResultReceiver wrappedCallback)
throws CallStateException {
// Need to make sure dialString gets parsed properly
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
if (isPhoneTypeGsm()) {
// handle in-call MMI first if applicable
if (handleInCallMmiCommands(newDialString)) {
return null;
}
// Only look at the Network portion for mmi
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
mUiccApplication.get(), wrappedCallback);
if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
if (mmi == null) { //return mCT.dial(newDialString, uusInfo, intentExtras);
return mCT.dial(newDialString, dialArgs.uusInfo, dialArgs.intentExtras); // 流程会进入这里, mCT 是 GsmCdmaCallTracker
} else if (mmi.isTemporaryModeCLIR()) {
return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), dialArgs.uusInfo,
dialArgs.intentExtras);
} else { // MTK 为了支持VT加入的代码
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
mmi.processCode();
return null;
}
} else {
return mCT.dial(newDialString);
}
}
GsmCallTracker 调用CI 执行指令,返回结果,通知GSMPhone
GsmCallTracker 会借助 mCi 发送指令,这里面会将包含 mCi 执行结果的 Message 提前发送出去,等到 mCi 执行完毕后, Message 会被发送到对应的 Handler 里面去。
//GSM
/**
* clirMode is one of the CLIR_ constants 呼出入口
*/
public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,
Bundle intentExtras)
throws CallStateException {
// note that this triggers call state changed notif
clearDisconnected();
if (!canDial()) {
throw new CallStateException("cannot dial in current state");
}
String origNumber = dialString;
dialString = convertNumberIfNecessary(mPhone, dialString);
// The new call must be assigned to the foreground call.
// That call must be idle, so place anything that's
// there on hold
if (mForegroundCall.getState() == GsmCdmaCall.State.ACTIVE) {
// this will probably be done by the radio anyway
// but the dial might fail before this happens
// and we need to make sure the foreground call is clear
// for the newly dialed connection
switchWaitingOrHoldingAndActive();
// This is a hack to delay DIAL so that it is sent out to RIL only after
// EVENT_SWITCH_RESULT is received. We've seen failures when adding a new call to
// multi-way conference calls due to DIAL being sent out before SWITCH is processed
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// do nothing
}
// Fake local state so that
// a) foregroundCall is empty for the newly dialed connection
// b) hasNonHangupStateChanged remains false in the
// next poll, so that we don't clear a failed dialing call
fakeHoldForegroundBeforeDial();
}
if (mForegroundCall.getState() != GsmCdmaCall.State.IDLE) {
//we should have failed in !canDial() above before we get here
throw new CallStateException("cannot dial in current state");
}
boolean isEmergencyCall = PhoneNumberUtils.isLocalEmergencyNumber(mPhone.getContext(),
dialString);
mPendingMO = new GsmCdmaConnection(mPhone, checkForTestEmergencyNumber(dialString),
this, mForegroundCall, isEmergencyCall);
mHangupPendingMO = false;
mMetrics.writeRilDial(mPhone.getPhoneId(), mPendingMO, clirMode, uusInfo);
if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0
|| mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {
// Phone number is invalid 电话号码无效
mPendingMO.mCause = DisconnectCause.INVALID_NUMBER;
// handlePollCalls() will notice this call not present
// and will mark it as dropped.
pollCallsWhenSafe();
} else {
// Always unmute when initiating a new call
setMute(false);// 拨号时设置不能静音
boolean isPhoneInEcmMode = EcbmHandler.getInstance().isInEcm();
// In Ecm mode, if another emergency call is dialed, Ecm mode will not exit.
if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {
mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());// 正常拨号// 需要注意, EVENT_DIAL_CALL_RESULT 是对应操作的一个句柄, 等到结果返回时, 会让 Handler 进行处理
} else {
EcbmHandler emergencyHandler = EcbmHandler.getInstance();
try {
emergencyHandler.exitEmergencyCallbackMode();
} catch (Exception e) {
e.printStackTrace();
}
emergencyHandler.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null);
mPendingCallClirMode = clirMode;
mPendingCallUusInfo = uusInfo;
mPendingCallInEcm = true;
}
}
if (mNumberConverted) {
mPendingMO.setConverted(origNumber);
mNumberConverted = false;
}
updatePhoneState();
mPhone.notifyPreciseCallStateChanged();
return mPendingMO;
}
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_OPERATION_COMPLETE:
// 再次获取最新信息
operationComplete();
break;
省略.......
}
}
private void operationComplete() {
mPendingOperations--;
if (DBG_POLL) log("operationComplete: pendingOperations=" +
mPendingOperations + ", needsPoll=" + mNeedsPoll);
if (mPendingOperations == 0 && mNeedsPoll) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);//EVENT_POLL_CALLS_RESULT 在调用Handler
mCi.getCurrentCalls(mLastRelevantPoll);//获取最新状态
} else if (mPendingOperations < 0) {
// this should never happen
Rlog.e(LOG_TAG,"GsmCdmaCallTracker.pendingOperations < 0");
mPendingOperations = 0;
}
}
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
if (msg == mLastRelevantPoll) {
if (DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
mNeedsPoll = false;
mLastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);//handlePollCalls 处理4种状态后,通知 phone 更新状态。
}
break;
}
}
@Override
protected synchronized void handlePollCalls(AsyncResult ar) {//handlePollCalls 处理4种状态后,通知 phone 更新状态。
List polledCalls;
.....
//CDMA
boolean noConnectionExists = true;
for (int i = 0, curDC = 0, dcSize = polledCalls.size()
; i < mConnections.length; i++) {
GsmCdmaConnection conn = mConnections[i];
DriverCall dc = null;
// polledCall list is sparse
if (curDC < dcSize) {
dc = (DriverCall) polledCalls.get(curDC);
if (dc.index == i+1) {
curDC++;
} else {
dc = null;
}
}
//CDMA
if (conn != null || dc != null) {// 新的电话
noConnectionExists = false;
}
if (DBG_POLL) log("poll: conn[i=" + i + "]=" +
conn+", dc=" + dc);
if (conn == null && dc != null) {
// Connection appeared in CLCC response that we don't know about
if (mPendingMO != null && mPendingMO.compareTo(dc)) {
......
if (mHangupPendingMO) {
......
}
} else {
.....
}
hasNonHangupStateChanged = true;
} else if (conn != null && dc == null) { // 旧的电话消失,可能时挂断
if (isPhoneTypeGsm()) {
// Connection missing in CLCC response that we were
// tracking.
mDroppedDuringPoll.add(conn);
} else {
.....
}
// Dropped connections are removed from the CallTracker
// list but kept in the Call list
mConnections[i] = null;
} else if (conn != null && dc != null && !conn.compareTo(dc) && isPhoneTypeGsm()) {
// Connection in CLCC response does not match what
// we were tracking. Assume dropped call and new call
mDroppedDuringPoll.add(conn);
mConnections[i] = new GsmCdmaConnection (mPhone, dc, this, i);
if (mConnections[i].getCall() == mRingingCall) {
newRinging = mConnections[i];
} // else something strange happened
hasNonHangupStateChanged = true;
} else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */ // 旧的电话更新, 正在打的电话时,状态更新
......
}
if (REPEAT_POLLING) {
......
}
}
if (!isPhoneTypeGsm() && noConnectionExists) {
checkAndEnableDataCallAfterEmergencyCallDropped();
}
if (mPendingMO != null) {
Rlog.d(LOG_TAG, "Pending MO dropped before poll fg state:"
+ mForegroundCall.getState());
mDroppedDuringPoll.add(mPendingMO);
mPendingMO = null;
mHangupPendingMO = false;
if (!isPhoneTypeGsm()) {
if( mPendingCallInEcm) {
mPendingCallInEcm = false;
}
checkAndEnableDataCallAfterEmergencyCallDropped();
}
}
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);
}
// clear the "local hangup" and "missed/rejected call"
// cases from the "dropped during poll" list
// These cases need no "last call fail" reason
ArrayList locallyDisconnectedConnections = new ArrayList<>();
for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) {
GsmCdmaConnection conn = mDroppedDuringPoll.get(i);
//CDMA
boolean wasDisconnected = false;
if (conn.isIncoming() && conn.getConnectTime() == 0) {
// Missed or rejected call
int cause;
if (conn.mCause == DisconnectCause.LOCAL) {
cause = DisconnectCause.INCOMING_REJECTED;
} else {
cause = DisconnectCause.INCOMING_MISSED;
}
if (Phone.DEBUG_PHONE) {
log("missed/rejected call, conn.cause=" + conn.mCause);
log("setting cause to " + cause);
}
mDroppedDuringPoll.remove(i);
hasAnyCallDisconnected |= conn.onDisconnect(cause);
wasDisconnected = true;
locallyDisconnectedConnections.add(conn);
} else if (conn.mCause == DisconnectCause.LOCAL
|| conn.mCause == DisconnectCause.INVALID_NUMBER) {
mDroppedDuringPoll.remove(i);
hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause);
wasDisconnected = true;
locallyDisconnectedConnections.add(conn);
}
if (!isPhoneTypeGsm() && wasDisconnected && unknownConnectionAppeared
&& conn == newUnknownConnectionCdma) {
unknownConnectionAppeared = false;
newUnknownConnectionCdma = null;
}
}
if (locallyDisconnectedConnections.size() > 0) {
mMetrics.writeRilCallList(mPhone.getPhoneId(), locallyDisconnectedConnections);
}
/* Disconnect any pending Handover connections */
for (Iterator it = mHandoverConnections.iterator();
it.hasNext();) {
.....
}
// Any non-local disconnects: determine cause
if (mDroppedDuringPoll.size() > 0) {
mCi.getLastCallFailCause(
obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));
}
if (needsPollDelay) {// 过一会在获取最新状态
pollCallsAfterDelay();
}
.....
if (VDBG) log("handlePollCalls calling updatePhoneState()");
updatePhoneState(); // 更新 phone 的状态
if (unknownConnectionAppeared) {
......
}
if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
mPhone.notifyPreciseCallStateChanged(); // 通知 GSMPhone 状态更新
updateMetrics(mConnections);
}
}
private void updatePhoneState() {
PhoneConstants.State oldState = mState;
if (mRingingCall.isRinging()) {
mState = PhoneConstants.State.RINGING;
} else if (mPendingMO != null ||
!(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {
mState = PhoneConstants.State.OFFHOOK;
} else {
Phone imsPhone = mPhone.getImsPhone();
if ( mState == PhoneConstants.State.OFFHOOK && (imsPhone != null)){
imsPhone.callEndCleanupHandOverCallIfAny();
}
mState = PhoneConstants.State.IDLE;
}
if (mState == PhoneConstants.State.IDLE && oldState != mState) {
mVoiceCallEndedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
} else if (oldState == PhoneConstants.State.IDLE && oldState != mState) {
mVoiceCallStartedRegistrants.notifyRegistrants (
new AsyncResult(null, null, null));
}
if (Phone.DEBUG_PHONE) {
log("update phone state, old=" + oldState + " new="+ mState);
}
if (mState != oldState) {
mPhone.notifyPhoneStateChanged();// 更新 phone 的状态
mMetrics.writePhoneState(mPhone.getPhoneId(), mState);
}
}
mPhone.notifyPhoneStateChanged => mNotifier.notifyPhoneState , mNotifier 是一个 DefaultPhoneNotifier , notifyPhoneState 会通知 telephony.registry 更新,telephony.registry 会通知所有调用了TelephonyManager.listen 的监听者, 实际上,这是提供给第三方APP监听Phone状态的一个接口,当前没用!!。
@Override
public void notifyPhoneState(Phone sender) {
Call ringingCall = sender.getRingingCall();
int subId = sender.getSubId();
int phoneId = sender.getPhoneId();
String incomingNumber = "";
if (ringingCall != null && ringingCall.getEarliestConnection() != null) {
incomingNumber = ringingCall.getEarliestConnection().getAddress();
}
try {
if (mRegistry != null) {
// mRegistry 是一个远程接口 (TelephonyRegistry)
// protected DefaultPhoneNotifier() {
//mRegistry
=ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
// "telephony.registry"));
mRegistry.notifyCallStateForPhoneId(phoneId, subId,
PhoneConstantConversions.convertCallState(
sender.getState()), incomingNumber);
}
} catch (RemoteException ex) {
// system process is dead
}
}
mPhone.notifyPreciseCallStateChanged() ==> PhoneBase.notifyPreciseCallStateChangedP() 这里会通知 TelephonyConnection 更新。 触发 TelephonyConnection 的 updateState()
转态更新后返回Message 回调mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage()),接下来流程来到了 mCi.dial, mCi 是一个 CommandsInterface 接口, 由 GsmCallTracker 的构造可知, GsmCallTracker 的 mCi 来自于 GSMPhone 的 mCi, 即 RIL。
进入RIL.java
@Override
public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
IRadio radioProxy = getRadioProxy(result);
Log.v("liwangjiangDialerRil","Ril address = "+address);
if (radioProxy != null) {
RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,
mRILDefaultWorkSource);
Dial dialInfo = new Dial();
dialInfo.address = convertNullToEmptyString(address);
dialInfo.clir = clirMode;
if (uusInfo != null) {
UusInfo info = new UusInfo();
info.uusType = uusInfo.getType();
info.uusDcs = uusInfo.getDcs();
info.uusData = new String(uusInfo.getUserData());
dialInfo.uusInfo.add(info);
}
if (RILJ_LOGD) {
// Do not log function arg for privacy
riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
}
try {
radioProxy.dial(rr.mSerial, dialInfo);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "dial", e);
}
}
}
RIL通讯主要由RILSender和RILReceiver构成,用于通讯传输的载体的有 RILRequest,
Registrant(RegistrantList)。
Log需要打开才能看,当前没有编过,敬请期待!!
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????