how a call be dailed out(Android Telephony basing on M)
来源:互联网 发布:淘宝同行恶意投诉售假 编辑:程序博客网 时间:2024/06/05 19:23
A call from UI to the real module that handle it on Android is not that simple,
Dialer--->Telecom--->Telephony--->RILD--->modem
and above path, there are 3 process simply from Android framework!
even these three are not all directly function call.
Dialer focus on Human–Machine Interaction close part. Telecom concentrates on call management. And Telephony is the core of all telephony related functions on Android framework layer.
Call Define
the calls are all transferred from UI to the call manager through broadcast. all call types are defined
frameworks/base/core/java/android/content/Intent.java
public static final String ACTION_DIAL = "android.intent.action.DIAL";public static final String ACTION_CALL = "android.intent.action.CALL";public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";...public static final String ACTION_ANSWER = "android.intent.action.ANSWER";...
so when you type some numbers from Dialer and click the call button, an broadcast will be send out.
Telecom
Telecom just waiting for this!packages/services/Telecomm/AndroidManifest.xml
<activity android:name="CallActivity" android:theme="@style/Theme.Telecomm.Transparent" android:configChanges="orientation|screenSize|keyboardHidden" android:permission="android.permission.CALL_PHONE" android:excludeFromRecents="true" android:process=":ui"> <!-- 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> <!-- Specify an icon for SIP calls so that quick contacts widget shows a special SIP icon for calls to SIP addresses. --> <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> <!-- Omit default category below so that all Intents sent to this filter must be explicit. --> <intent-filter> <action android:name="android.intent.action.CALL" /> <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> <activity-alias android:name="PrivilegedCallActivity" android:targetActivity="CallActivity" android:permission="android.permission.CALL_PRIVILEGED" android:process=":ui">... <activity-alias android:name="EmergencyCallActivity" android:targetActivity="CallActivity" android:permission="android.permission.CALL_PRIVILEGED" android:process=":ui">...we see that different call types is handled by associated Activities.
let's focus on the first one here.
packages/services/Telecomm/src/com/android/server/telecom/CallActivity.java
public class CallActivity extends Activity {... @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle);... Log.d(this, "onCreate: begin"); processIntent(getIntent()); // This activity does not have associated UI, so close. finish(); Log.d(this, "onCreate: end"); }that's simple, pure activity and finished just after process intent.
and the processIntent() just works as an capability and permission verifier, then pass the Intent to the next one:
private boolean sendBroadcastToReceiver(Intent intent) { intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, false); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); intent.setClass(this, CallReceiver.class); Log.d(this, "Sending broadcast as user to CallReceiver"); sendBroadcastAsUser(intent, UserHandle.OWNER); return true; }
packages/services/Telecomm/src/com/android/server/telecom/CallReceiver.java
public class CallReceiver extends BroadcastReceiver {public void onReceive(Context context, Intent intent) { if (isUnknownCall) { processUnknownCallIntent(intent); } else { processOutgoingCallIntent(context, intent); }...}static void processOutgoingCallIntent(Context context, Intent intent) PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra( TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); Call call = getCallsManager().startOutgoingCall(handle, phoneAccountHandle, clientExtras); NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster( context, getCallsManager(), call, intent, isDefaultDialer); final int result = broadcaster.processIntent();it is really a BroadcastReceiver for handling both incoming(unknow) and outgoing call.
for out going call, it initialize an Call object by CallsManager and then process Intent again by another new class NewOutgoingCallIntentBroadcaster.
packages/services/Telecomm/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
int processIntent()if (Intent.ACTION_CALL.equals(action)) {launchSystemDialer(intent.getData()); callImmediately = true;}if (callImmediately) {mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,speakerphoneOn, videoState);}broadcastIntent(intent, number, !callImmediately);it verifies if the call needs be handled immediately and call CallsManager function. the broadcastIntent() is for special handle logic, so we can ignore here firstly.
packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn, int videoState)if (neededForceSpeakerOn()) { call.setStartWithSpeakerphoneOn(true);} else { call.setStartWithSpeakerphoneOn(speakerphoneOn || mDockManager.isDocked());}boolean isEmergencyCall = TelephonyUtil.shouldProcessAsEmergency(mContext, call.getHandle());call.startCreateConnection(mPhoneAccountRegistrar);here it checks speaker status and verify if it should be an emergency call, then call startCreateConnection() of the Call.
packages/services/Telecomm/src/com/android/server/telecom/Call.java
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar)mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext);mCreateConnectionProcessor.process();here it again create an new class object to process the connection create logic.
packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java
void process()clearTimeout();mAttemptRecords.add(new CallAttemptRecord( mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));mAttemptRecordIterator = mAttemptRecords.iterator();attemptNextPhoneAccount();private void attemptNextPhoneAccount()attempt = mAttemptRecordIterator.next();PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;ConnectionServiceWrapper service = mRepository.getService( phoneAccount.getComponentName(), phoneAccount.getUserHandle());mCall.setConnectionService(service);setTimeoutIfNeeded(service, attempt);service.createConnection(mCall, new Response(service));it firstly creates and CallAttemptRecord and collects into its list, then process it by a new class' function ConnectionServiceWrapper.createConnection() as previous logic do.
before go ahead, let's explain how this ConnectionServiceWrapper is created first.
ConnectionServiceWrapper
it is got directly from mRepository. and this object comes from the param of CreateConnectionProcessor class constructor
private final ConnectionServiceRepository mRepository;... CreateConnectionProcessor( Call call, ConnectionServiceRepository repository, CreateConnectionResponse response, PhoneAccountRegistrar phoneAccountRegistrar, Context context) { mCall = call; mRepository = repository; mResponse = response; mPhoneAccountRegistrar = phoneAccountRegistrar; mContext = context; }and we've got that the CreateConnectionProcessor is constructed by Call object as previous code shows. this mRepository is also the member of Call class, which is also be initialized by its constructor:
Call( Context context, ConnectionServiceRepository repository, Uri handle, GatewayInfo gatewayInfo, PhoneAccountHandle connectionManagerPhoneAccountHandle, PhoneAccountHandle targetPhoneAccountHandle, boolean isIncoming, boolean isConference) { mState = isConference ? CallState.ACTIVE : CallState.NEW; mContext = context; mRepository = repository; setHandle(handle); setHandle(handle, TelecomManager.PRESENTATION_ALLOWED); mGatewayInfo = gatewayInfo; setConnectionManagerPhoneAccount(connectionManagerPhoneAccountHandle); setTargetPhoneAccount(targetPhoneAccountHandle); mIsIncoming = isIncoming; mIsConference = isConference; maybeLoadCannedSmsResponses(); }from our earlier analysis, the Call object comes from CallsManager.startOutgoingCall() in CallReceiver class. and the function just looks:
packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras) Call call = getNewOutgoingCall(handle); call.setTargetPhoneAccount(phoneAccountHandle);if (needsAccountSelection) { call.setState(CallState.PRE_DIAL_WAIT);} else {call.setState(CallState.CONNECTING);}if (!mCalls.contains(call)) addCall(call);private Call getNewOutgoingCall(Uri handle) return new Call( mContext, mConnectionServiceRepository, handle, null /* gatewayInfo */, null /* connectionManagerPhoneAccount */, null /* phoneAccountHandle */, false /* isIncoming */, false /* isConference */);so the mRepository comes from CallsManager! then how it is initialized, still from others?
private final ConnectionServiceRepository mConnectionServiceRepository;CallsManager(Context context, MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) { mContext = context; mPhoneAccountRegistrar = phoneAccountRegistrar; mConnectionServiceRepository = new ConnectionServiceRepository(mPhoneAccountRegistrar, context);luckly it is created here directly!
packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceRepository.java
final class ConnectionServiceRepository implements ServiceBinder.Listener<ConnectionServiceWrapper> { private final HashMap<Pair<ComponentName, UserHandle>, ConnectionServiceWrapper> mServiceCache = new HashMap<>(); private final PhoneAccountRegistrar mPhoneAccountRegistrar; private final Context mContext; ConnectionServiceRepository(PhoneAccountRegistrar phoneAccountRegistrar, Context context) { mPhoneAccountRegistrar = phoneAccountRegistrar; mContext = context; } ConnectionServiceWrapper getService(ComponentName componentName, UserHandle userHandle) { Pair<ComponentName, UserHandle> cacheKey = Pair.create(componentName, userHandle); ConnectionServiceWrapper service = mServiceCache.get(cacheKey); if (service == null) { service = new ConnectionServiceWrapper( componentName, this, mPhoneAccountRegistrar, mContext, userHandle); service.addListener(this); mServiceCache.put(cacheKey, service); } return service; }so it is! and the ConnectionServiceWrapper is firstly created and be cached here.
let's back and continue our previous topic.
Cont.
int CreateConnectionProcessor it calls ConnectionServiceWrapper's createconnection()
packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java
final class ConnectionServiceWrapper extends ServiceBinder {void createConnection(final Call call, final CreateConnectionResponse response) BindCallback callback = new BindCallback() { public void onSuccess() { String callId = mCallIdMapper.getCallId(call); mPendingResponses.put(callId, response); mServiceInterface.createConnection( call.getConnectionManagerPhoneAccount(), callId, new ConnectionRequest( call.getTargetPhoneAccount(), call.getHandle(), extras, call.getVideoState()), call.isIncoming(), call.isUnknown()); } public void onFailure() { response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); } }; mBinder.bind(callback, call);private Binder2 mBinder = new Binder2();private IConnectionService mServiceInterface;protected void setServiceInterface(IBinder binder) { if (binder == null) { handleConnectionServiceDeath(); CallsManager.getInstance().handleConnectionServiceDeath(this); mServiceInterface = null; } else { mServiceInterface = IConnectionService.Stub.asInterface(binder); addConnectionServiceAdapter(mAdapter); }it also create another new class object to do the further handle logic.
firstly new an BinderCallback object and put the logic into its onSucess callback function. then call mBinder's bind() to associate the callback object with the call.
let's see how the Binder2 looks like and how the callback works.
as no code details found in ConnectionServiceWrapper and its parent class is ServiceBinder, we'd go there and have a look
packages/services/Telecomm/src/com/android/server/telecom/ServiceBinder.java
abstract class ServiceBinder { interface BindCallback { void onSuccess(); void onFailure(); }...private final Set<BindCallback> mCallbacks = new ArraySet<>();... private void setBinder(IBinder binder) mBinder = binder; setServiceInterface(binder);...protected abstract void setServiceInterface(IBinder binder);... protected ServiceBinder(String serviceAction, ComponentName componentName, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle) { Preconditions.checkState(!TextUtils.isEmpty(serviceAction)); Preconditions.checkNotNull(componentName); mContext = context; mLock = lock; mServiceAction = serviceAction; mComponentName = componentName; mUserHandle = userHandle; } final class Binder2 { void bind(BindCallback callback, Call call) mCallbacks.add(callback); if (mServiceConnection == null) { Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName); ServiceConnection connection = new ServiceBinderConnection(call); mContext.bindService(serviceIntent, connection, bindingFlags); } else { handleSuccessfulConnection(); } }it is an abstract class and the bind() function in the internal BInder2 class performs an remote service call after add the callback into its list.
the callback must be triggered while the remote service be binded. have a look.
private final class ServiceBinderConnection implements ServiceConnection {public void onServiceConnected(ComponentName componentName, IBinder binder)if (mIsBindingAborted) {handleFailedConnection();return;}setBinder(binder);handleSuccessfulConnection();public void onServiceDisconnected(ComponentName componentName)mServiceConnection = null;handleServiceDisconnected();}... private void handleSuccessfulConnection() { for (BindCallback callback : mCallbacks) { callback.onSuccess(); } mCallbacks.clear(); }so we get it.
and back to ConnectionServiceWrapper, mServiceInterface is calling the real and remote createConnection() now.
wait, where this mServiceInterface is initialized?
find the setBinder() in above onServiceConnected()? remember that abstract function "setServiceInterface()"
packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java
protected void setServiceInterface(IBinder binder) {if (binder == null) {handleConnectionServiceDeath();CallsManager.getInstance().handleConnectionServiceDeath(this);mServiceInterface = null;} else {mServiceInterface = IConnectionService.Stub.asInterface(binder);addConnectionServiceAdapter(mAdapter);}the call is transferred out of Telecom, but we do not find where the remote service now.
let's find out.
The real ConnectionService
as previous remote service bind from Binder2, it is named by mServiceAction and it is initialized by ServiceBinder constructor.
protected ServiceBinder(String serviceAction, ComponentName componentName, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle) { Preconditions.checkState(!TextUtils.isEmpty(serviceAction)); Preconditions.checkNotNull(componentName); mContext = context; mLock = lock; mServiceAction = serviceAction; mComponentName = componentName; mUserHandle = userHandle; } final class Binder2 { void bind(BindCallback callback, Call call) mCallbacks.add(callback); if (mServiceConnection == null) { Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName); ServiceConnection connection = new ServiceBinderConnection(call); mContext.bindService(serviceIntent, connection, bindingFlags); } else { handleSuccessfulConnection(); } }and as ServiceBinder is inherented by ConnectionServiceWrapper, we just check its functions.
ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, Context context, UserHandle userHandle) { super(ConnectionService.SERVICE_INTERFACE, componentName, context, userHandle); mConnectionServiceRepository = connectionServiceRepository; phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections // To do this, we must proxy remote ConnectionService objects }); mPhoneAccountRegistrar = phoneAccountRegistrar; }the value should be ConnectionService.SERVICE_INTERFACE as it shows.
frameworks/base/telecomm/java/android/telecom/ConnectionService.java
public abstract class ConnectionService extends Service { public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";...by comment of the source code, we learn that AndroidManifest needs to be searched to find the real service:
An abstract service that should be implemented by any apps which can make phone calls (VoIP or otherwise) and want those calls to be integrated into the built-in phone app. Once implemented, the ConnectionService needs two additional steps before it will be integrated into the phone app:
1. Registration in AndroidManifest.xml
<service android:name="com.example.package.MyConnectionService"
android:label="@string/some_label_for_my_connection_service"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>
</service>
and here we go to Telephony directly.
packages/services/Telephony/AndroidManifest.xml
<service android:singleUser="true" android:name="com.android.services.telephony.TelephonyConnectionService" android:label="@string/pstn_connection_service_label" android:permission="android.permission.BIND_CONNECTION_SERVICE" > <intent-filter> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service>packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java
public class TelephonyConnectionService extends ConnectionService {... @Override public void onCreate() { super.onCreate(); mExpectedComponentName = new ComponentName(this, this.getClass()); mEmergencyTonePlayer = new EmergencyTonePlayer(this); TelecomAccountRegistry.getInstance(this).setTelephonyConnectionService(this); }but we do not find the createConnection() method, so we have to back to ConnectionService:
/** * This can be used by telecom to either create a new outgoing call or attach to an existing * incoming call. In either case, telecom will cycle through a set of services and call * createConnection util a connection service cancels the process or completes it successfully. */ 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);... if (connection.getState() != Connection.STATE_DISCONNECTED) { addConnection(callId, connection); }... mAdapter.handleCreateConnectionComplete( callId, request, new ParcelableConnection( connection.getState(), connection.getConnectionCapabilities(), connection.getAddress(), connection.getAddressPresentation(), connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation(), connection.getVideoProvider() == null ? null : connection.getVideoProvider().getInterface(), connection.getVideoState(), connection.isRingbackRequested(), connection.getAudioModeIsVoip(), connection.getStatusHints(), connection.getDisconnectCause(), createIdList(connection.getConferenceables())));...create connection object, add to record list, then complete by mAdapter.
and the create connection is implemented in the TelephonyConnectionService
@Override public Connection onCreateOutgoingConnection( PhoneAccountHandle connectionManagerPhoneAccount, final ConnectionRequest request) {... // Get the right phone object from the account data passed in. if (phone == null) { phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber); }... final TelephonyConnection connection = createConnectionFor(phone, null, true /* isOutgoing */);... connection.setAddress(handle, PhoneConstants.PRESENTATION_ALLOWED); connection.setInitializing(); connection.setVideoState(request.getVideoState());... if (useEmergencyCallHelper) {... } else { placeOutgoingConnection(connection, phone, request); } return connection; } private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency) { if (Objects.equals(mExpectedComponentName, accountHandle.getComponentName())) { if (accountHandle.getId() != null) { try { int phoneId = SubscriptionController.getInstance().getPhoneId( Integer.parseInt(accountHandle.getId())); return PhoneFactory.getPhone(phoneId); } catch (NumberFormatException e) { Log.w(this, "Could not get subId from account: " + accountHandle.getId()); } } } if (isEmergency) {... } return null; } private TelephonyConnection createConnectionFor( Phone phone, com.android.internal.telephony.Connection originalConnection, boolean isOutgoing) { TelephonyConnection returnConnection = null; int phoneType = phone.getPhoneType(); if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { returnConnection = new GsmConnection(originalConnection); } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { boolean allowMute = allowMute(phone); returnConnection = new CdmaConnection( originalConnection, mEmergencyTonePlayer, allowMute, isOutgoing); } if (returnConnection != null) { // Listen to Telephony specific callbacks from the connection returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener); } return returnConnection; }and the method placeOutgoingConnection() would transfer the dial task on the target Phone object now(just one notice, the phone object got from PhoneFactory is a PhoneProxy instance):
private void placeOutgoingConnection( TelephonyConnection connection, Phone phone, ConnectionRequest request) { String number = connection.getAddress().getSchemeSpecificPart(); com.android.internal.telephony.Connection originalConnection; try { originalConnection = phone.dial(number, request.getVideoState()); } catch (CallStateException 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) {... startActivity(intent); } connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause( telephonyDisconnectCause, "Connection is null")); } else { connection.setOriginalConnection(originalConnection); }frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneProxy.java
@Override public Connection dial(String dialString, int videoState) throws CallStateException { return mActivePhone.dial(dialString, videoState); } @Override public Connection dial(String dialString, UUSInfo uusInfo, int videoState) throws CallStateException { return mActivePhone.dial(dialString, uusInfo, videoState); }
The Real Call of Phone
take Gsm phone as example.
frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java
@Override public Connection dial(String dialString, int videoState) throws CallStateException { return dial(dialString, null, videoState); } @Override public Connection dial (String dialString, UUSInfo uusInfo, int videoState) throws CallStateException {... return dialInternal(dialString, null, VideoProfile.VideoState.AUDIO_ONLY); } @Override protected Connection dialInternal (String dialString, UUSInfo uusInfo, int videoState) throws CallStateException {... if (mmi == null) { return mCT.dial(newDialString, uusInfo); } else if (mmi.isTemporaryModeCLIR()) { return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo); ... GsmCallTracker mCT; public GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { super("GSM", notifier, context, ci, unitTestMode); ... mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM); mCT = new GsmCallTracker(this);frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GsmCallTracker.java
GsmCallTracker (GSMPhone phone) { this.mPhone = phone; mCi = phone.mCi; mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null); mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);... synchronized Connection dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException {... String origNumber = dialString; dialString = convertNumberIfNecessary(mPhone, dialString);... mPendingMO = new GsmConnection(mPhone.getContext(), checkForTestEmergencyNumber(dialString), this, mForegroundCall);... // Always unmute when initiating a new call setMute(false);... if (!mWaitingForHoldRequest.isWaiting()) { mCi.dial(PhoneNumberUtils.parseGlobalPrefix(mPendingMO.getAddress()), clirMode, uusInfo, obtainCompleteMessage(EVENT_DIAL_CALL_RESULT)); } else { mWaitingForHoldRequest.set(mPendingMO.getAddress(), clirMode, uusInfo, mPhone); }... updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); return mPendingMO; }it convert dial string if needed, then unmute to make sure there there audio works as expected, send command to the rild and notify the whole system about the call state change.
waiting for the response
case EVENT_DIAL_CALL_RESULT: ar = (AsyncResult) msg.obj; if (ar.exception != null) { log("dial call failed!!"); mHelper.PendingHangupRequestUpdate(); } operationComplete();... private void operationComplete() { mPendingOperations--; if (mPendingOperations == 0 && mNeedsPoll) { mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); mCi.getCurrentCalls(mLastRelevantPoll);... switch (msg.what) { case EVENT_POLL_CALLS_RESULT: ar = (AsyncResult)msg.obj; if (msg == mLastRelevantPoll) { if (DBG_POLL) log( "handle EVENT_POLL_CALLS_RESULT: set needsPoll=F"); mNeedsPoll = false; mLastRelevantPoll = null; handlePollCalls((AsyncResult)msg.obj); } break;
reference:
1.Android M6.0 source code
2.http://developer.android.com/
- how a call be dailed out(Android Telephony basing on M)
- Telephony Call
- import android.provider.Telephony cannot be resolved
- android - How to make a phone call from webview
- android Out of memory on a xxx-byte allocation问题
- Android Out of memory on a 5200288-byte allocation.解决方法
- Telephony MO CALL/IMS CALL
- Telephony Call状态图解
- Set QListWidgetItem height basing on contents
- Fatal error: Call to a member function fetch_row() on a non-object in C:\wamp\www\baicaotang\admin\m
- How to call a android/native service from a native/android (java) code
- Android(M) Telephony Framework SIM card recognization flow
- how to be a man
- HOW TO BE A HECKER !
- How-to create a Calculator on Google Android: Part I
- How to add a new key on android
- How to create a custom notification on Android
- Based on or Basing on, 为何写作多用 Based on?
- 解决RHEL6 vncserver 启动 could not open default font 'fixed'错误.
- iOS开发遍历集合(NSArray,NSDictionary、NSSet)方法总结
- iOS、mac开源项目及库汇总
- 同一类型标识符(Uniform Type Identifier,UTI)
- Fragment中startActivityForResult与onActivityResult详细解决方案
- how a call be dailed out(Android Telephony basing on M)
- Android四大组件之Service
- Retrofit的使用与深入学习(下)
- Java中int转String 和 String转int 各方法效率对比
- Linux-16、17、18-服务器操作系统CentOS6.5安装实战(L003-30,31,32)
- Swift学习笔记二:常用类型的注意事项
- Android http操作
- INT BYTE4
- Block的使用