需求:
判断系统拨号的每个状态,根据状态不同弹窗提示。
需求分析:
1、无卡开机要求提示用户:Emergency calls only. Please enter Emergency Number;
2、无网络覆盖情况,当户用拨打所有号码,界面上立即给出提示“No network coverage!";
3、飞行模式打开的情况下,用户拨打紧急号码时,弹出提示,提示用户要先关闭飞行模式;
4、当两张卡都处于有限服务状态的时候 拨打号码, 手机提示"Emergency call only, Please enter an Emergency number!"
目的:
通过需求了解去电的基本流程。
附上本次要分析的流程图,正常情况下就不分析了,为了满足需求,主要分析的是去电情况下的异常状态的处理机制。
上一篇笔记分析到了这个流程图的第一步,在这个方法中Telecom模块绑定了InCallUI这个进程,可以通过mInCallServices对通话界面的状态进行各种控制。这篇笔记接着这个方法开始分析。
第1步:
static void processOutgoingCallIntent(Context context, Intent intent) {
...
//首次绑定InCallUI进程。
CallsManager.getInstance().getInCallController().bind();
/// @}
...
//返回一个CALL对象,同时,startOutgoingCall()首次对InCallUI进行控制
Call call = getCallsManager().startOutgoingCall(handle, phoneAccountHandle, clientExtras);
...
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, getCallsManager(), call, intent, isDefaultDialer);
//进入拨号流程
final int result = broadcaster.processIntent();
final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
if (!success && call != null) {
disconnectCallAndShowErrorDialog(context, call, result);
}
}
}
第2、3步:
int processIntent() {
...
final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
//仅对系统拨号器情况下进行判断;
//紧急号码情况下,将Aciton 重写为 action = Intent.ACTION_CALL_EMERGENCY;
//非紧急号码情况下,将Aciton 重写为 action = Intent.ACTION_CALL;
//此时,第三方软件的Aciton一直是Intent.ACTION_CALL;
rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
action = intent.getAction();
// True for certain types of numbers that are not intended to be intercepted or modified
// by third parties (e.g. emergency numbers).
boolean callImmediately = false;
//如果是紧急号码,系统拨号Action不会是 Intent.ACTION_CALL,可以判定第三方拨打的紧急号码
if (Intent.ACTION_CALL.equals(action)) {
if (isPotentialEmergencyNumber) {
if (!mIsDefaultOrSystemPhoneApp) {
Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
+ "unless caller is system or default dialer.", number, intent);
launchSystemDialer(intent.getData());
return DisconnectCause.OUTGOING_CANCELED;
} else {
callImmediately = true;
}
}
} else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) { //系统拨打的紧急号码
...
callImmediately = true;
} else {
Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
return DisconnectCause.INVALID_NUMBER;
}
if (callImmediately) {
Log.i(this, "Placing call immediately instead of waiting for "
+ " OutgoingCallBroadcastReceiver: %s", intent);
String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;
boolean speakerphoneOn = mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
int videoState = mIntent.getIntExtra(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.VideoState.AUDIO_ONLY);
mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
speakerphoneOn, videoState);
// Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
// so that third parties can still inspect (but not intercept) the outgoing call. When
// the broadcast finally reaches the OutgoingCallBroadcastReceiver, we'll know not to
// initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.
}
//紧急号码情况在这个方法下会被屏蔽,上面已经处理过
broadcastIntent(intent, number, !callImmediately);
return DisconnectCause.NOT_DISCONNECTED;
}
这一步对号码以及Action做了区分,根据具体情况重写了Aciton ;
- 系统拨打紧急号码会立即进入拨号流程;
- 第三方拨打紧急号码会立即跳转至系统拨号盘;
- 其他情况发送广播执行拨号流程。
第4步:
void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn,
int videoState) {
...
boolean isEmergencyCall = TelephonyUtil.shouldProcessAsEmergency(mContext,
call.getHandle());
Log.i(this, "placeOutgoingCall isEmergencyCall = " + isEmergencyCall);
...
//如果是无卡状态,在这里就不会继续往下走了,上一篇判断的无卡状态,从log上看,走到这里就停止了。
if (call.getTargetPhoneAccount() != null || 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.
/// M: call control start. @{
// If already have an active call, need to hold active call first.
Call activeCall = getFirstCallWithState(CallState.ACTIVE);
if (activeCall == null
|| isPotentialMMICode(call.getHandle())
|| isPotentialInCallMMICode(call.getHandle())) {
Log.i(this, "Active call is null, start outgoing call %s.", call);
call.startCreateConnection(mPhoneAccountRegistrar);
} else if (activeCall.can(PhoneCapabilities.HOLD)) {
Log.i(this, "Holding active call %s before start outgoing call %s.",
activeCall, call);
mPendingCallActions.put(activeCall, new PendingCallAction(call,
PendingCallAction.PENDING_ACTION_OUTGOING,
VideoProfile.VideoState.AUDIO_ONLY));
activeCall.hold();
} else if (isEmergencyCall) {
mPendingCallActions.put(activeCall, new PendingCallAction(call,
PendingCallAction.PENDING_ACTION_OUTGOING,