cdma拨号是没有alerting状态的,即接通基站后就是active状态。所以即使对方没有接通,手机也会开始通话计时。
通话时间重置问题
针对这种问题,运营商后续加入了接通的上报事件,这样接通后手机的计时会重置。
google原生是没有这个功能的,这就导致后续各个厂商各种不同的实现。
mtk的实现
packages/services/Telephony/src/com/android/services/telephony/TelephonyConnection.java
case EVENT_CDMA_CALL_ACCEPTED:EVENT_CDMA_CALL_ACCEPTED消息处理
Log.v(TelephonyConnection.this, "EVENT_CDMA_CALL_ACCEPTED");
updateConnectionCapabilities();
fireOnCdmaCallAccepted();
frameworks/base/telecomm/java/android/telecom/Connection.java
protected void fireOnCdmaCallAccepted() {中间的具体流程不再赘述,Telephony,Telecomm.InCallUI三个app之间的数据传递之前有文章讲过,见 短信拒接流程。
Log.d(this, "fireOnCdmaCallAccepted: %s", stateToString(mState));
for (Listener l : mListeners) {
l.onCdmaCallAccepted(this);
}
}
packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
void notifyCdmaCallAccepted(Call call) {这里是关键,call重新设置连接时间为当前。
/// M: ALPS02445100. Update addCall capapility when cdma call accepted. @{
updateCanAddCall();
/// @}
call.setConnectTimeMillis(System.currentTimeMillis());
Log.d(this, "notifyCdmaCallAccepted, call:%s", call);
for (CallsManagerListener listener : mListeners) {
listener.onCdmaCallAccepted(call);
}
}
packages/services/Telecomm/src/com/android/server/telecom/InCallController.java
public void onCdmaCallAccepted(Call call) {
Log.d(this, "onCdmaCallAccepted %s", call);
updateCall(call);
}
private void updateCall(Call call, boolean videoProviderChanged) { if (!mInCallServices.isEmpty()) { ParcelableCall parcelableCall = toParcelableCall(call, videoProviderChanged /* includeVideoProvider */); Log.i(this, "Sending updateCall %s ==> %s", call, parcelableCall); List<ComponentName> componentsUpdated = new ArrayList<>(); for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) { ComponentName componentName = entry.getKey(); IInCallService inCallService = entry.getValue(); componentsUpdated.add(componentName); try { inCallService.updateCall(parcelableCall); } catch (RemoteException ignored) { } } Log.i(this, "Components updated: %s", componentsUpdated); } }然后InCallService就会传递Call数据到InCallUI
高通的实现
app层面是从Telephony开始的
packages/service/Telephony/src/com/android/services/telephony/CdmaConnection.java
private void onCdmaLineControlInfoRec() {
if (mOriginalConnection != null && mOriginalConnection.getState() == Call.State.ACTIVE) {
if (mOriginalConnection.getDurationMillis() > 0 &&
!mOriginalConnection.isIncoming() && !mConnectionTimeReset) {
Bundle extras = getExtras();
if (extras != null && !extras.getBoolean("isNeedReset", false)) {
extras.putBoolean("isNeedReset", true);
putExtras(extras);
mOriginalConnection.resetConnectionTime();
}
}
}
}
接下来就会上报到Telecomm
packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
@Override
public void onExtrasChanged(Call c, int source, Bundle extras) {
if (source != Call.SOURCE_CONNECTION_SERVICE) {
return;
}
handleCallTechnologyChange(c);
handleChildAddressChange(c);
if (extras != null) {
boolean isNeedReset = extras.getBoolean("isNeedReset", false);
handleCdmaConnectionTimeReset(c, isNeedReset);
}
updateCanAddCall();
}
void handleCdmaConnectionTimeReset(Call call, boolean isNeedReset) {
if (isNeedReset && call != null) {
call.setConnectTimeMillis(System.currentTimeMillis());
if (mCalls.contains(call)) {
for (CallsManagerListener listener : mListeners) {
listener.onCallStateChanged(call, CallState.ACTIVE, CallState.ACTIVE);
}
}
call.removeExtras(Call.SOURCE_INCALL_SERVICE,
new ArrayList<String>(Arrays.asList("isNeedReset")));
}
updateCanAddCall();
}
重置了通话时间
这里也可看出高通的实现还是高明一点,利用了现有的借口,不用在framework中再加一堆方法。
接通振动问题
与重置时间类似的就是接通振动问题,同样有各种实现
mtk的实现
boolean onCdmaCallAccept() {mtk的实现是大多数产品想要实现的效果,真正接通后振动,但是有个特殊的问题,就是mtk只针对cdma特殊处理,gsm就不管了...
Rlog.d(LOG_TAG, "onCdmaCallAccept, mIsRealConnected:" + mIsRealConnected
+ ", state:" + getState());
if (getState() != CdmaCall.State.ACTIVE) {
mReceivedAccepted = true;
return false;
}
mConnectTimeReal = SystemClock.elapsedRealtime();
mDuration = 0;
mConnectTime = System.currentTimeMillis();
if (!mIsRealConnected) {
mIsRealConnected = true;
// send DTMF when the CDMA call is really accepted.
processNextPostDialChar();
vibrateForAccepted();
}
return true;
}
private void vibrateForAccepted() {
//if CDMA phone accepted, start a Vibrator
Vibrator vibrator = (Vibrator) mOwner.mPhone.getContext().getSystemService(
Context.VIBRATOR_SERVICE);
vibrator.vibrate(MO_CALL_VIBRATE_TIME);
}
高通的实现
protected void onPhoneStateChanged() {
Call.State state = CallManager.getInstance().getActiveFgCallState();
if (mLastFgCallState.isDialing() && state == Call.State.ACTIVE) {
vibrateAfterCallConnected();
}
mLastFgCallState = state;
}
private void vibrateAfterCallConnected() {
int defaultVibrateEnabled = getResources()
.getInteger(R.integer.config_default_vibrate_after_connected);
if (Settings.System.getInt(getContentResolver(), "vibrate_on_accepted",
defaultVibrateEnabled) == 1) {
Vibrator mSystemVibrator = new SystemVibrator();
int nVibratorLength = 100;
mSystemVibrator.vibrate(nVibratorLength);
SystemClock.sleep(nVibratorLength);
mSystemVibrator.cancel();
}
}