cdma拨号的细节记录

时间:2022-11-10 10:51:26

cdma拨号是没有alerting状态的,即接通基站后就是active状态。所以即使对方没有接通,手机也会开始通话计时。


通话时间重置问题

针对这种问题,运营商后续加入了接通的上报事件,这样接通后手机的计时会重置。

google原生是没有这个功能的,这就导致后续各个厂商各种不同的实现。

mtk的实现

packages/services/Telephony/src/com/android/services/telephony/TelephonyConnection.java

                case EVENT_CDMA_CALL_ACCEPTED:
Log.v(TelephonyConnection.this, "EVENT_CDMA_CALL_ACCEPTED");
updateConnectionCapabilities();
fireOnCdmaCallAccepted();
EVENT_CDMA_CALL_ACCEPTED消息处理

frameworks/base/telecomm/java/android/telecom/Connection.java

    protected void fireOnCdmaCallAccepted() {
Log.d(this, "fireOnCdmaCallAccepted: %s", stateToString(mState));
for (Listener l : mListeners) {
l.onCdmaCallAccepted(this);
}
}
中间的具体流程不再赘述,Telephony,Telecomm.InCallUI三个app之间的数据传递之前有文章讲过,见 短信拒接流程

packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

    void notifyCdmaCallAccepted(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);
}
}
这里是关键,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的实现

frameworks/opt/telephony/src/java/com/android/internal/telephony/cdma/CdmaConnection.java
    boolean onCdmaCallAccept() {
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);
}
mtk的实现是大多数产品想要实现的效果,真正接通后振动,但是有个特殊的问题,就是mtk只针对cdma特殊处理,gsm就不管了...

高通的实现

vendor/qcom/proprietary/qrdplus/Extension/apps/PhoneFeatures/src/com/qualcomm/qti/phonefeature/FeatureService.java
   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();
}
}
高通实现在app层次,但是也看出并没有针对cdma做特殊处理,会在active状态后就马上振动。

可见最终还是要自己写代码处理这个问题