/**
* Processes the supplied intent and starts the outgoing call broadcast process relevant to the
* intent.
*
* This method will handle three kinds of actions:
*
* - CALL (intent launched by all third party dialers)
* - CALL_PRIVILEGED (intent launched by system apps e.g. system Dialer, voice Dialer)
* - CALL_EMERGENCY (intent launched by lock screen emergency dialer)
*
* @return {@link CallActivity#OUTGOING_CALL_SUCCEEDED} if the call succeeded, and an
* appropriate {@link DisconnectCause} if the call did not, describing why it failed.
*/
final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
rewriteCallIntentAction(intent, isPotentialEmergencyNumber);//重写action值
void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn,
int videoState) {
if (call == null) {
// don't do anything if the call no longer exists
Log.i(this, "Canceling unknown call.");
return;
}
final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();
if (gatewayInfo == null) {
Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle));
} else {
Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
Log.pii(uriHandle), Log.pii(handle));
}
call.setHandle(uriHandle);
call.setGatewayInfo(gatewayInfo);
call.setStartWithSpeakerphoneOn(speakerphoneOn);
call.setVideoState(videoState);
boolean isEmergencyCall = TelephonyUtil.shouldProcessAsEmergency(mContext,
call.getHandle());
if (isEmergencyCall) {
// Emergency -- CreateConnectionProcessor will choose accounts automatically
call.setTargetPhoneAccount(null);
}
if (call.getTargetPhoneAccount() != null || isEmergencyCall) {
if (!isEmergencyCall) {
updateLchStatus(call.getTargetPhoneAccount().getId());
}
// 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.
call.startCreateConnection(mPhoneAccountRegistrar);
}
}
void process() {
Log.v(this, "process");
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency();
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
}
// If we are possibly attempting to call a local emergency number, ensure that the
// plain PSTN connection services are listed, and nothing else.
private void adjustAttemptsForEmergency() {
if (TelephonyUtil.shouldProcessAsEmergency(mContext, mCall.getHandle())) {
Log.i(this, "Emergency number detected");
mAttemptRecords.clear();
List<PhoneAccount> allAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();//获得所有账户(SIM/SIP/IMS等)
if (allAccounts.isEmpty()) {//如果是空的话
// If the list of phone accounts is empty at this point, it means Telephony hasn't
// registered any phone accounts yet. Add a fallback emergency phone account so
// that emergency calls can still go through. We create a new ArrayLists here just
// in case the implementation of PhoneAccountRegistrar ever returns an unmodifiable
// list.
allAccounts = new ArrayList<PhoneAccount>();
allAccounts.add(TelephonyUtil.getDefaultEmergencyPhoneAccount());
//如果是空的话,那么我么赋予一个默认的紧急拨号账户}
// First, add SIM phone accounts which can place emergency calls.
for (PhoneAccount phoneAccount : allAccounts) {
if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) &&
phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
Log.i(this, "Will try PSTN account %s for emergency",
//PSTN?phoneAccount.getAccountHandle());
mAttemptRecords.add(
new CallAttemptRecord(
phoneAccount.getAccountHandle(),
phoneAccount.getAccountHandle()));
}
}
// Next, add the connection manager account as a backup if it can place emergency calls.
PhoneAccountHandle callManagerHandle = mPhoneAccountRegistrar.getSimCallManager();
if (callManagerHandle != null) {
PhoneAccount callManager = mPhoneAccountRegistrar
.getPhoneAccount(callManagerHandle);
if (callManager.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle,
mPhoneAccountRegistrar.
getDefaultOutgoingPhoneAccount(mCall.getHandle().getScheme())
);
if (!mAttemptRecords.contains(callAttemptRecord)) {
Log.i(this, "Will try Connection Manager account %s for emergency",
callManager);
mAttemptRecords.add(callAttemptRecord);
}
}
}
}
}
/**
* @return fallback {@link PhoneAccount} to be used by Telecom for emergency calls in the
* rare case that Telephony has not registered any phone accounts yet. Details about this
* account are not expected to be displayed in the UI, so the description, etc are not
* populated.
*/
static PhoneAccount getDefaultEmergencyPhoneAccount() {
return PhoneAccount.builder(DEFAULT_EMERGENCY_PHONE_ACCOUNT_HANDLE, "E")
.setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS).build();
}
/**
* Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM
* subscription.
* <p>
* Only the Android framework can register a {@code PhoneAccount} having this capability.
* <p>
* See {@link #getCapabilities}
*/
public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
C:\Users\admin\Desktop\MO_Log\112 with simcard.txt (3 hits)
07-23 13:04:52.020 4146-4146/com.android.server.telecom I/Telecom﹕ Call: setTargetPhoneAccount
ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, 5
C:\Users\admin\Desktop\MO_Log\112 with no sim card.txt (4 hits)
07-23 13:06:06.409 4146-4146/com.android.server.telecom I/Telecom﹕ Call: setTargetPhoneAccount
ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, E (这个稍后会变成-1)
C:\Users\admin\Desktop\MO_Log\112 airplane mode.txt (3 hits)
07-23 13:08:57.877 4146-4146/com.android.server.telecom I/Telecom﹕ Call: setTargetPhoneAccount
ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, 3
C:\Users\admin\Desktop\MO_Log\MO.txt (1 hit)
04-04 14:25:02.677: I/Telecom(4147): Call: setTargetPhoneAccount
ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, 2
770: 07-23 13:08:58.351 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: EmergencyCallHelper constructor.
770: 07-23 13:08:58.351 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: EmergencyCallHelper constructor.
772: 07-23 13:08:58.352 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: startTurnOnRadioSequence
788: 07-23 13:08:58.358 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: startSequenceInternal()
790: 07-23 13:08:58.358 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: cleanup()
794: 07-23 13:08:58.358 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: powerOnRadio().
798: 07-23 13:08:58.359 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: ==> Turning off airplane mode.
1720: 07-23 13:08:58.787 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: onServiceStateChanged(), new state = 1 1 home null null null Unknown Unknown CSS not supported -1 -1 RoamInd=-1 DefRoamInd=-1 EmergOnly=false.
1722: 07-23 13:08:58.787 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: onServiceStateChanged: not ready to call yet, keep waiting.
1976: 07-23 13:08:59.019 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: onServiceStateChanged(), new state = 0 1 home CHN-UNICOM UNICOM 46001 GSM Unknown CSS supported -1 -1 RoamInd=-1 DefRoamInd=-1 EmergOnly=false.
1978: 07-23 13:08:59.020 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: onServiceStateChanged: ok to call!
2160: 07-23 13:08:59.092 4171-4171/com.android.phone D/Telephony﹕ EmergencyCallHelper: cleanup()
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
...
boolean useEmergencyCallHelper = false;
if (isEmergencyNumber) {
mRequest = request;
if (state == ServiceState.STATE_POWER_OFF) {//如果radio没有开
useEmergencyCallHelper = true;
}
}
...
if (useEmergencyCallHelper) {
if (mEmergencyCallHelper == null) {
mEmergencyCallHelper = new EmergencyCallHelper(this);
}
mEmergencyCallHelper.startTurnOnRadioSequence(phone,//打开radio,进而如果是开启了飞行模式的话则关闭飞行模式
new EmergencyCallHelper.Callback() {
@Override
public void onComplete(boolean isRadioReady) {
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// If the connection has already been disconnected, do nothing.
} else if (isRadioReady) {
connection.setInitialized();
placeOutgoingConnection(connection,//打开radio后
PhoneFactory.getPhone(getPhoneIdForECall()), request);
} else {
Log.d(this, "onCreateOutgoingConnection, failed to turn on radio");
connection.setDisconnected(
DisconnectCauseUtil.toTelecomDisconnectCause(
android.telephony.DisconnectCause.POWER_OFF,
"Failed to turn on radio."));
connection.destroy();
}
}
});
}else {
placeOutgoingConnection(connection, phone, request);//如果radio本来就可用的话
}
}
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
String number = connection.getAddress().getSchemeSpecificPart();
PhoneAccountHandle pHandle = TelecomAccountRegistry.makePstnPhoneAccountHandle(phone);
// For ECall handling on MSIM, till the request reaches here(i.e PhoneApp)
// we dont know on which phone account ECall can be placed, once after deciding
// the phone account for ECall we should inform Telecomm so that
// the proper sub information will be displayed on InCallUI.
if (!Objects.equals(pHandle, request.getAccountHandle())) {
Log.i(this, "setPhoneAccountHandle, account = " + pHandle);
connection.setPhoneAccountHandle(pHandle);
}
Bundle bundle = request.getExtras();
boolean isAddParticipant = (bundle != null) && bundle
.getBoolean(TelephonyProperties.ADD_PARTICIPANT_KEY, false);
Log.d(this, "placeOutgoingConnection isAddParticipant = " + isAddParticipant);
com.android.internal.telephony.Connection originalConnection;
try {
if (isAddParticipant) {
phone.addParticipant(number);
return;
} else {
originalConnection = phone.dial(number, request.getVideoState(), bundle);
// 拨号}
} catch (CallStateException e) {
Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUTGOING_FAILURE,
e.getMessage()));
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");
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);
startActivity(intent);
}
Log.d(this, "placeOutgoingConnection, phone.dial returned null");
connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
telephonyDisconnectCause, "Connection is null"));
} else {
connection.setOriginalConnection(originalConnection);
}
}
07-23 13:06:06.950 4171-4171/com.android.phone D/Telephony﹕ TelephonyConnectionService: Adding IMS connection to conference controller: [TelephonyConnection objId:612117509 type:ims state:STATE_INITIALIZING capabilities:[Capabilities: SUPPORT_HOLD MUTE] address:[c751ce91522518e4613bf659f18549fefbb76424] originalConnection:[ImsPhoneConnection objId: 489542255 address:[601ca99d55f00a2e8e736676b606a4d31d374fdd] ImsCall:com.android.ims.ImsCall@137a9b7c] partOfConf:N]OriginalConnection is[ImsPhoneConnection objId: 489542255 address:[601ca99d55f00a2e8e736676b606a4d31d374fdd] ImsCall:com.android.ims.ImsCall@137a9b7c]
07-24 14:25:16.036 3846-3846/? D/Telephony﹕ TelephonyConnectionService: Adding GSM connection to conference controller: [TelephonyConnection objId:870157190 type:gsm state:STATE_INITIALIZING capabilities:[Capabilities: SUPPORT_HOLD MUTE] address:[ea5d6942dec97279729796b6e1627dc33a42a105] originalConnection: incoming: false state: DIALING post dial state: NOT_STARTED partOfConf:N]OriginalConnection is incoming: false state: DIALING post dial state: NOT_STARTED