Android Telephony Call分析

 

关于Call对象

一共4个

  1. ./packages/apps/Dialer/java/com/android/incallui/call/DialerCall.java
  2. ./frameworks/base/telecomm/java/android/telecom/Call.java
  3. ./packages/services/Telecomm/src/com/android/server/telecom/Call.java
  4. ./frameworks/opt/telephony/src/java/com/android/internal/telephony/Call.java

 

  • frameworks/opt/telephony/src/java/com/android/internal/telephony/Call.java没有使用,看样子google打算放弃使用,转用packages/services这个了。
  • Call状态最终都是通过CallsManager来广播出去的,CallsManager承上启下。通过不同Call的转换,最终在ui上体现出来。InCallService是UI和telecom的接口。InCallController绑定InCallService。
  • 从下往上,Call的传到是:
    com.android.server.telecom.call (系统进程)--> android.telecom.call(framgwork) --> com.android.incallui.DialerCall(Dialer进程)
  • com.android.server.telecom.call对象是拨打电话的时候(CallsManger.startOutgoingCall),或者收到来电intent的时候创建的(CallsManger.processIncomingCallIntent)。inCallController中的toParcelableCall函数会new ParcelableCall对象,参数是com.androidservice.telecom.call对象。toParcelableCall有两个地方可以调到,一个是onConnected的时候,就是inCallController绑定到incallService后,如果这个时候call不为空,就会走;还有一个地方是CallsManager回调onCallAdded的时候,也会调用。android.telecom.call就是通过这个ParcelableCall对象的相关信息来创建的。即完成了com.android.server.telecom.call到android.telecom.call的映射。
  • incallservice会在绑定的时候,把自己注册到phone的listener中。当incallservice的客户端(InCallController)调用addcall的时候,会传过来一个parcelableCall的对象,incallservice会调用phone.internalAddCall来处理,在internalAddCall中根据这个parcelableCall对象生成telecomCall对象,然后phone通过fireCallAdded把这个call对象通过回调传到incallservice中,incallservice调用onCallAdded,这个实现在incallui里面,即完成了android.telecom.call到 com.android.incallui.call的映射。
  • android.telecom.call作为构造参数创建com.android.incallui.DialerCall,同时incallui.DialerCall注册telecommCall的回调函数,这样有变化的时候,telecommCall会通知incallui.DialerCall来更新UI.

一,Diale里面的Call ,InCallUi  DialerCall.java

在以前没有吧InCallUi合进Dialer中的时InCallUi中只有一个Call.java,现在重新构建了一遍,吧InCallUi放入Dialer中(要看商场怎么分离)。

我们来看一下DialerCall的构造方法:

public DialerCall(
      Context context,DialerCallDelegate dialerCallDelegate,Call telecomCall,LatencyReport latencyReport,boolean registerCallback) {
    Assert.isNotNull(context);
   .....
}

这里的Call是framework telecomm  Call中传入的,调用逻辑图:

大致逻辑  Call先是从系统服务InCallContrller.java中通过AIDL传给framework中的InCallSerivce.java中在通过InCallSerive调用子类方法进行传入。

Dialer创建是在:CallList.java中onCallAdded初始化:

public void onCallAdded(
      final Context context, final android.telecom.Call telecomCall, LatencyReport latencyReport) {
    Trace.beginSection("onCallAdded");
    final DialerCall call =
        new DialerCall(context, this, telecomCall, latencyReport, true /* registerCallback */);
  
......
if (call.getState() == DialerCall.State.INCOMING
        || call.getState() == DialerCall.State.CALL_WAITING) {
      onIncoming(call);  //来电主核心
    } else {
      dialerCallListener.onDialerCallUpdate();
    }
}

这个onCallAdded是InCallServiceImpl中调用的,而InCallSerivceImpl中的onCallAdded方法是其父类直接调用,他的父类就是framewok里面的InCallSerivce.java其实他是一个服务,等待系统服务调用。

二,Serivce.Telecomm 中的Call 

Telecom Call  
framework/base/telecomm/src/java/android/telecomm/Phone.java

public final class Call {}

他是一个被定义成final类型的类,它是在Phone.java中被创建的internalAddCall()方法中被创建的.interanalAddCall()他是在InCallService中的Hanlder(MSG_ADD_CALL)调用,来电或去点都会被调用这个方法.

 final void internalAddCall(ParcelableCall parcelableCall) {//parcelabeCall是通过AIDL进行传输的,所有需要转换
        //从ParcelableCall中取出信息用于new Telecom Call
        Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
                parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
        mCallByTelecomCallId.put(parcelableCall.getId(), call);
        //添加调集合中
        mCalls.add(call);
        checkCallTree(parcelableCall);
        call.internalUpdate(parcelableCall, mCallByTelecomCallId);
        fireCallAdded(call);
     }

这里的ParcelableCall是一个中间者的角色,在InCallController.java中先将Telecom Service中的Call转换成ParcelableCall传入.

  ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
                        call,
                        videoProviderChanged /* includeVideoProvider */,
                        mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported(),
                        rttInfoChanged && info.equals(mInCallServiceConnection.getInfo()));
                ComponentName componentName = info.getComponentName();
                IInCallService inCallService = entry.getValue();
                componentsUpdated.add(componentName);

       inCallService.updateCall(parcelableCall);//通过AIDL调用Framework中的数据

总结:然后通过ParcelableCallUtils进行转换,转换成Telecom Call, 这样子就实现了serviceTelecomm传入给frameworkTelecomm

三,Service Telecomm 系统中Telecomm

路径:package/service/telecomm/src/com/android/service/telecomm/Call.java

public class Call implements CreateConnectionResponse, EventManager.Loggable,
        ConnectionServiceFocusManager.CallFocus {}

Call实现了CreateConnectionResponse接口,说明他负责与Connection创建之后处理一些事件,比如创建Connection之后需要UI界面的一些刷新以及更新。

Service Telecom Call是通话流程中最重要的Call对象,他拥有管理一通电话的能力,(answer,reject,hold,disconnect等等),他由CallsManager创建管理

在通过过程中,CallsManager是这样管理的:

CallsManager.java
来电创建Call对象processInComingCallIntent()
去电创建Call对象

startOutgoingCall()

发起拨号请求placeOutgoingCall()
设置状态setCallState()
主动挂断disconnectCall()

四,framework opt中的Call

framework/opt/telephony/src/android/internel/Call.java

public abstract class Call {
}

他是一个抽象类。

继承结构

我们这里关注一下GsmCdmaCall的关系:

GsmCdmaPhone初始化了GsmCdmaCallTracker,GsmCdmaCallTracker是负责管理GsmCdmaCall和GsmCdmaConnection的操作类,GsmCdmaCallTracker里面有一个GsmCdmaConnection的数组:

public GsmCdmaConnection[] mConnections;

并且有常量控制着mConnections数组数组的大小,一个GsmCdmaConnection代表着一通电话,说明GSM最大允许同时存在19通,CDMA最大同时存在8通。

    public static final int MAX_CONNECTIONS_GSM = 19;   //7 allowed in GSM + 12 from IMS for SRVCC
    private static final int MAX_CONNECTIONS_PER_CALL_GSM = 5; //only 5 connections allowed per call

    private static final int MAX_CONNECTIONS_CDMA = 8;
    private static final int MAX_CONNECTIONS_PER_CALL_CDMA = 1; //only 1 connection allowed per call

同时,GsmCdmaCallTracker的内部也会创建三个GsmCdmaCall(GsmCdmaCall仅仅会在GsmCdmaCallTracker中被创建,创建之后不会再被重新赋值):

    public GsmCdmaCall mRingingCall = new GsmCdmaCall(this);
    // A call that is ringing or (call) waiting
    public GsmCdmaCall mForegroundCall = new GsmCdmaCall(this);
    public GsmCdmaCall mBackgroundCall = new GsmCdmaCall(this);

Telephony Framework Call的状态有9种:

    public enum State {
        IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;

        public boolean isAlive() {
            return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
        }

        public boolean isRinging() {
            return this == INCOMING || this == WAITING;
        }

        public boolean isDialing() {
            return this == DIALING || this == ALERTING;
        }
    }

问题1:那么mRingingCall,mForegroundCall,mBackgroundCall分别对应Call的什么状态呢?

由于Telephony Framework Call的”ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING”这六种状态跟DriverCall.State是一一对应的
 

public static State
    stateFromDCState (DriverCall.State dcState) {
        switch (dcState) {
            case ACTIVE:        return State.ACTIVE;
            case HOLDING:       return State.HOLDING;
            case DIALING:       return State.DIALING;
            case ALERTING:      return State.ALERTING;
            case INCOMING:      return State.INCOMING;
            case WAITING:       return State.WAITING;
            default:            throw new RuntimeException ("illegal call state:" + dcState);
        }
    }

在GsmCdmaConnection中有依据DriverCall.State将GsmCdmaCall分类的方法,根据state来返回相应的对象

private GsmCdmaCall
    parentFromDCState (DriverCall.State state) {
        switch (state) {
            case ACTIVE:
            case DIALING:
            case ALERTING:
                return mOwner.mForegroundCall;
            //break;

            case HOLDING:
                return mOwner.mBackgroundCall;
            //break;

            case INCOMING:
            case WAITING:
                return mOwner.mRingingCall;
            //break;

            default:
                throw new RuntimeException("illegal call state: " + state);
        }
    }

所以mRingingCall,mForegroundCall,mBackgroundCall与GsmCdmaCall.mState的关系如下:

mRingingCallINCOMING,WAITING
mForegroundCallACTIVE,DIALING,ALERTING
mBackgroundCallHOLDING

GsmCdmaCallTracker在初始化的时候就注册监听了Call状态变化的消息,

    public GsmCdmaCallTracker (GsmCdmaPhone phone) {
        this.mPhone = phone;
        mCi = phone.mCi;
        mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);//注册EVENT_CALL_STATE_CHANGE 状态
        mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
        mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);

        // Register receiver for ECM exit
        IntentFilter filter = new IntentFilter();
        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
        mPhone.getContext().registerReceiver(mEcmExitReceiver, filter);

        updatePhoneType(true);
    }

所以当modem中Call状态发生变化后,便会通知到GsmCdmaCallTracker,GsmCdmaCallTracker通过调用RILJ的getCurrentCalls()方法发起查询modem当前的Call状态列表,modem返回来的结果是DriverCall 集合。
再由GsmCdmaCallTracker的handlePollCalls()方法来对比自身mConnections集合与DriverCall 集合的差异,进而依据DriverCall的信息跟新这对应GsmCdmaCall(mRingingCall,mForegroundCall,mBackgroundCall)的状态,同时将当前GsmCdmaConnection与对应的GsmCdmaCall绑定。
 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达帮主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值