三.Call的建立和传送
先来看下代码
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent) {
......
// 拨打电话状态依旧为语音通话
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);
// 是否是系统默认电话应用
final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent);
......
UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);
// Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
// 调用CallsManager的startOutgoingCall方法,初始化Call对象
Call call = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
if (call != null) {
// Asynchronous calls should not usually be made inside a BroadcastReceiver because once
// onReceive is complete, the BroadcastReceiver's process runs the risk of getting
// killed if memory is scarce. However, this is OK here because the entire Telecom
// process will be running throughout the duration of the phone call and should never
// be killed.
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
isPrivilegedDialer);
final int result = broadcaster.processIntent();
......
}
}
此处主要是做了两件事
(一)CallsManager的startOutgoingCall方法分析
先查看一下其代码
Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
UserHandle initiatingUser) {
boolean isReusedCall = true;
Call call = reuseOutgoingCall(handle);
// Create a call with original handle. The handle may be changed when the call is attached
// to a connection service, but in most cases will remain the same.
if (call == null) {
call = new Call(getNextCallId(), mContext,
this,
mLock,
mConnectionServiceRepository,
mContactsAsyncHelper,
mCallerInfoAsyncQueryFactory,
mPhoneNumberUtilsAdapter,
handle,
null /* gatewayInfo */,
null /* connectionManagerPhoneAccount */,
null /* phoneAccountHandle */,
Call.CALL_DIRECTION_OUTGOING /* callDirection */,
false /* forceAttachToExistingConnection */,
false /* isConference */
);
call.initAnalytics();
call.setInitiatingUser(initiatingUser);
isReusedCall = false;
}
......
List accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
Log.v(this, "startOutgoingCall found accounts = " + accounts);
......
if (phoneAccountHandle == null && accounts.size() > 0) {
// No preset account, check if default exists that supports the URI scheme for the
// handle and verify it can be used.
if(accounts.size() > 1) {
PhoneAccountHandle defaultPhoneAccountHandle =
mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme(), initiatingUser);
if (defaultPhoneAccountHandle != null &&
accounts.contains(defaultPhoneAccountHandle)) {
phoneAccountHandle = defaultPhoneAccountHandle;
}
} else {
// Use the only PhoneAccount that is available
phoneAccountHandle = accounts.get(0);
}
}
call.setTargetPhoneAccount(phoneAccountHandle);
......
// Do not support any more live calls. Our options are to move a call to hold, disconnect
// a call, or cancel this call altogether. If a call is being reused, then it has already
// passed the makeRoomForOutgoingCall check once and will fail the second time due to the
// call transitioning into the CONNECTING state.
if (!isPotentialInCallMMICode && (!isReusedCall &&
!makeRoomForOutgoingCall(call, call.isEmergencyCall()))) {
// just cancel at this point.
Log.i(this, "No remaining room for outgoing call: %s", call);
if (mCalls.contains(call)) {
// This call can already exist if it is a reused call,
// See {@link #reuseOutgoingCall}.
call.disconnect();
}
return null;
}
boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
!call.isEmergencyCall();
if (needsAccountSelection) {
// This is the state where the user is expected to select an account
call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
// Create our own instance to modify (since extras may be Bundle.EMPTY)
extras = new Bundle(extras);
extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
} else {
call.setState(
CallState.CONNECTING,
phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
}
setIntentExtrasAndStartTime(call, extras);
// Do not add the call if it is a potential MMI code.
if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
......
} else if (!mCalls.contains(call)) {
......
addCall(call);
}
return call;
}
从这个方法中,可以看到
private List constructPossiblePhoneAccounts(Uri handle, UserHandle user) {
......
List allAccounts =
mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user);
......
return allAccounts;
}
可以看到,是调用PhoneAccountRegistrarD的getCallCapablePhoneAccounts方法返回的
public List getCallCapablePhoneAccounts(
String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle) {
return getPhoneAccountHandles(
PhoneAccount.CAPABILITY_CALL_PROVIDER,
PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY /*excludedCapabilities*/,
uriScheme, null, includeDisabledAccounts, userHandle);
}
private List getPhoneAccountHandles(
int capabilities,
int excludedCapabilities,
String uriScheme,
String packageName,
boolean includeDisabledAccounts,
UserHandle userHandle) {
List handles = new ArrayList<>();
for (PhoneAccount account : getPhoneAccounts(
capabilities, excludedCapabilities, uriScheme, packageName,
includeDisabledAccounts, userHandle)) {
handles.add(account.getAccountHandle());
}
return handles;
}
OK,是通过getPhoneAccounts的getAccountHandle得到的
private List getPhoneAccounts(
int capabilities,
int excludedCapabilities,
String uriScheme,
String packageName,
boolean includeDisabledAccounts,
UserHandle userHandle) {
List accounts = new ArrayList<>(mState.accounts.size());
for (PhoneAccount m : mState.accounts) {
......
accounts.add(m);
}
return accounts;
}
mState是什么?查看整个PhoneAccountRegistrar的代码,发现,这个mState是在PhoneAccountRegistrar的初始化的时候写入的,来看它的代码
public PhoneAccountRegistrar(Context context, String fileName,
DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy) {
mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
mState = new State();
mContext = context;
mUserManager = UserManager.get(context);
mDefaultDialerCache = defaultDialerCache;
mSubscriptionManager = SubscriptionManager.from(mContext);
mAppLabelProxy = appLabelProxy;
mCurrentUserHandle = Process.myUserHandle();
read();
}
read方法
private void read() {
final InputStream is;
try {
is = mAtomicFile.openRead();
} catch (FileNotFoundException ex) {
return;
}
boolean versionChanged = false;
XmlPullParser parser;
try {
parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(is), null);
parser.nextTag();
mState = readFromXml(parser, mContext);
versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
} catch (IOException | XmlPullParserException e) {
Log.e(this, e, "Reading state from XML file");
mState = new State();
} finally {
try {
is.close();
} catch (IOException e) {
Log.e(this, e, "Closing InputStream");
}
}
// Verify all of the UserHandles.
List badAccounts = new ArrayList<>();
for (PhoneAccount phoneAccount : mState.accounts) {
UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
if (userHandle == null) {
Log.w(this, "Missing UserHandle for %s", phoneAccount);
badAccounts.add(phoneAccount);
} else if (mUserManager.getSerialNumberForUser(userHandle) == -1) {
Log.w(this, "User does not exist for %s", phoneAccount);
badAccounts.add(phoneAccount);
}
}
mState.accounts.removeAll(badAccounts);
// If an upgrade occurred, write out the changed data.
if (versionChanged || !badAccounts.isEmpty()) {
write();
}
}
原来,它是读取xml文件得到的数据,那么xml文件里面有哪些数据呢?下面是我从高通的某平台的O版本的项目中导出的phone-account-registrar-state.xml
0
com.android.phone/com.android.services.telephony.TelephonyConnectionService
89860081101750717452
0
com.android.phone/com.android.services.telephony.TelephonyConnectionService
E
0
tel:
tel:
182
AAAAAQGJUE5HDQoaCgAAAA1JSERSAAAAJgAAADAIBgAAAH2yCCgAAAAEc0JJVAgICAh8CGSIAAAB
6UlEQVRYhe2YO47TUBRAz72JRMEvMkJQ0iGlBQmQEIqABigonOcsgWWQhi0wQ5WgNGgspoCCNhuY
BWS2gESbgsSXwjZxJgPkoWT8Cp/Gha2ro/OebdmCB865VpqmyyRJEjP7CFwqTonPnHPIgFMz+yAi
79M0/bn1wF6v155Op4t+v/9aRCbAlR1JrSEio06n86a1zcXD4VDH4/HSOfdKRI6Ay3uQMmAJ3JvP
59//ObgslSTJSzP7BFwlT687lCrJiuPsr8Odc61i+V6YWVpI2Z6kKOYqcPePxSqlnpvZZ+Aa+yt1
ruEGlVLPKlL7LLXBRrGylHPuKXAMXCfflFvdKLtirUBZyjn3GEgLqeyipaBSrLKnnpjZMXCDGkqV
KKyVelSRqqVUiZSlBoPBwyzLvgA3qbHUbzGAOI7vq+pX4Db53bfT18z/oHEcP6hILQlACkBV9Yhc
qtY9dRYFbnGBT/RtUWBBYFKQCwWxp84SXKmSRsyXRswXZfUJFhRKQE/7KkEvZZA0Yr40Yr40Yr40
Yr40Yr40Yr40Yr40Yr4oq3/rIZEpMCOXC0Gw9JipmR2wKmc1SlnhoGZ2oFEUHYrICGhT7w8WAdoi
Moqi6LB1cnJi3W73m5n9EJE7QFSDYAbMzOwd8HYymSx+ASOfrdnny/IjAAAAAElFTkSuQmCC
0
Emergency calling only
tel
voicemail
-1
false
true
15
分析其读取的过程,可以知道,mState的defaultOutgoingAccountHandles/accounts/versionNumber均在其中有所规定,那么接下来就按照这份xml文件中的内容分析其流程
private void addCall(Call call) {
......
call.addListener(this);
mCalls.add(call);
.....
for (CallsManagerListener listener : mListeners) {
......
listener.onCallAdded(call);
......
}
......
}
可以看到,主要是将刚刚初始化的Call对象加入到mCalls中进行管理,并且调用mListers中所有的Listener对象的onCallAdded方法,那么mListeners是什么?
mListeners.add(mInCallWakeLockController);
mListeners.add(statusBarNotifier);
mListeners.add(mCallLogManager);
mListeners.add(mPhoneStateBroadcaster);
mListeners.add(mInCallController);
mListeners.add(mCallAudioManager);
mListeners.add(missedCallNotifier);
mListeners.add(mHeadsetMediaButton);
mListeners.add(mProximitySensorManager);
因此,会分别调用添加到mListeners中的所有对象的onCallAdded方法
public NewOutgoingCallIntentBroadcaster(Context context, CallsManager callsManager, Call call,
Intent intent, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
boolean isDefaultPhoneApp) {
mContext = context;
mCallsManager = callsManager;
mCall = call;
mIntent = intent;
mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
mIsDefaultOrSystemPhoneApp = isDefaultPhoneApp;
mLock = mCallsManager.getLock();
}
初始化,没啥说的
public int processIntent() {
Intent intent = mIntent;
String action = intent.getAction();
final Uri handle = intent.getData();
......
String number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);
......
UserHandle targetUser = mCall.getInitiatingUser();
Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
broadcastIntent(intent, number, !callImmediately, targetUser);
return DisconnectCause.NOT_DISCONNECTED;
}
调用broadcastIntent方法
private void broadcastIntent(
Intent originalCallIntent,
String number,
boolean receiverRequired,
UserHandle targetUser) {
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
if (number != null) {
broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
}
// Force receivers of this broadcast intent to run at foreground priority because we
// want to finish processing the broadcast intent as soon as possible.
broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Log.v(this, "Broadcasting intent: %s.", broadcastIntent);
checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);
mContext.sendOrderedBroadcastAsUser(
broadcastIntent,
targetUser,
android.Manifest.permission.PROCESS_OUTGOING_CALLS,
AppOpsManager.OP_PROCESS_OUTGOING_CALLS,
receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
null, // scheduler
Activity.RESULT_OK, // initialCode
number, // initialData: initial value for the result data (number to be modified)
null); // initialExtras
}
发送广播,在NewOutgoingCallBroadcastIntentReceiver中进行处理
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
......
mCall.setNewOutgoingCallIntentBroadcastIsDone();
mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,
mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false),
mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY));
}
}
.....
}
}
回到CallsManager中,调用placeOutgoingCall方法
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
boolean speakerphoneOn, int videoState) {
......
call.startCreateConnection(mPhoneAccountRegistrar);
......
}
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
......
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}
public void process() {
......
attemptNextPhoneAccount();
}
private void attemptNextPhoneAccount() {
......
PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
mService = mRepository.getService(phoneAccount.getComponentName(), phoneAccount.getUserHandle());
......
mService.createConnection(mCall, this);
......
}
从上面的分析,知道,这边的PhoneAccountHandle对象是在phone-account-registrar-state.xml文件中读取出来的,那么分析一下ConnectionServiceRepository的getService方法,我们知道
private void createConnection(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
......
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
......
}
调用onCreateOutgoingConnection方法
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
......
placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);
......
}
调用placeOutgoingConnection方法
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) {
.....
originalConnection = phone.dial(number, null, videoState, extras);
......
}
调用Phone对象的dial方法
public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
throws CallStateException {
......
if (isPhoneTypeGsm()) {
return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
} else {
return dialInternal(dialString, null, videoState, intentExtras);
}
}
调用dialInternal方法
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras)
throws CallStateException {
return dialInternal(dialString, uusInfo, videoState, intentExtras, null);
}
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras, 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("dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
return mCT.dial(newDialString, uusInfo, intentExtras);
} else if (mmi.isTemporaryModeCLIR()) {
return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
} else {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
try {
mmi.processCode();
} catch (CallStateException e) {
//do nothing
}
// FIXME should this return null or something else?
return null;
}
} else {
return mCT.dial(newDialString);
}
}
可以看到,会调用GsmCdmaCallTracker的dial方法
public Connection dial(String dialString) throws CallStateException {
if (isPhoneTypeGsm()) {
return dial(dialString, CommandsInterface.CLIR_DEFAULT, null);
} else {
return dial(dialString, CommandsInterface.CLIR_DEFAULT);
}
}
以Gsm Phone来看
public Connection dial(String dialString, UUSInfo uusInfo, Bundle intentExtras)
throws CallStateException {
return dial(dialString, CommandsInterface.CLIR_DEFAULT, uusInfo, intentExtras);
}
public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,
Bundle intentExtras)
throws CallStateException {
......
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);
mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());
}
if (mNumberConverted) {
mPendingMO.setConverted(origNumber);
mNumberConverted = false;
}
updatePhoneState();
mPhone.notifyPreciseCallStateChanged();
return mPendingMO;
}
这边调用RIL的dial方法,最终会传入RIL层,进行处理