通话状态 --- notifyPreciseCallStateChanged

3.3 notifyPreciseCallStateChanged

notifyPreciseCallStateChanged方法是这三个方法中最难分析的一个, GsmCallTracker的notifyPreciseCallStateChanged

方法调用流程图如下,


PhoneBase的notifyPreciseCallStateChangedP方法调用逻辑如下,

1,利用AsyncResult推动着状态往下继续更新,

AsyncResult ar = new AsyncResult(null, this, null);
mPreciseCallStateRegistrants.notifyRegistrants(ar);

2,调用DefaultPhoneNotifier的notifyPreciseCallState方法将状态发送出去,

mNotifier.notifyPreciseCallState(this);

到此,就需要分2路来论述了,首先论述简单的DefaultPhoneNotifier的notifyPreciseCallState方法的调用。

1,notifyPreciseCallState

和上小节的notifyPhoneState方法类似, DefaultPhoneNotifier的notifyPreciseCallState方法逻辑如下,

1,首先获取三路通话,

int subId = sender.getSubId();
Call ringingCall = sender.getRingingCall();
Call foregroundCall = sender.getForegroundCall();
Call backgroundCall = sender.getBackgroundCall();

2,然后将这三路通话的状态分别发送出去,

if (ringingCall != null && foregroundCall != null && backgroundCall != null) {
   try {
       mRegistry.notifyPreciseCallStateForSubscriber(subId,
            convertPreciseCallState(ringingCall.getState()),
            convertPreciseCallState(foregroundCall.getState()),
            convertPreciseCallState(backgroundCall.getState()));
    } catch (RemoteException ex) {
         // system process is dead
    }
}

在调用TelephonyRegistry的notifyPreciseCallStateForSubscriber方法之前,需要调用convertPreciseCallState方法将

Call.State的状态和PreciseCallState状态进行映射。convertPreciseCallState方法如下,

switch (state) {
            case ACTIVE:
                return PreciseCallState.PRECISE_CALL_STATE_ACTIVE;
            case HOLDING:
                return PreciseCallState.PRECISE_CALL_STATE_HOLDING;
            case DIALING:
                return PreciseCallState.PRECISE_CALL_STATE_DIALING;
            case ALERTING:
                return PreciseCallState.PRECISE_CALL_STATE_ALERTING;
            case INCOMING:
                return PreciseCallState.PRECISE_CALL_STATE_INCOMING;
            case WAITING:
                return PreciseCallState.PRECISE_CALL_STATE_WAITING;
            case DISCONNECTED:
                return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED;
            case DISCONNECTING:
                return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING;
            default:
                return PreciseCallState.PRECISE_CALL_STATE_IDLE;
        }

因此, Call.State与PreciseCallState的State对应关系如下,

Call.State

PreciseCallState以及对应数值

State.ACTIVE

PRECISE_CALL_STATE_ACTIVE

1

State. DIALING

PRECISE_CALL_STATE_DIALING

3

State. ALERTING

PRECISE_CALL_STATE_ALERTING

4

State. HOLDING

PRECISE_CALL_STATE_HOLDING

2

State. INCOMING

PRECISE_CALL_STATE_INCOMING

5

State. WAITING

PRECISE_CALL_STATE_WAITING

6

State. DISCONNECTED

PRECISE_CALL_STATE_DISCONNECTED

7

State. DISCONNECTING

PRECISE_CALL_STATE_DISCONNECTING

8

State. IDLE

PRECISE_CALL_STATE_IDLE

0

PreciseCallState定义如下,

public class PreciseCallState implements Parcelable {

说明是可以进行跨进程通信的。

TelephonyRegistry的notifyPreciseCallStateForSubscriber方法逻辑如下,

1,首先通过PhoneStateListener的跨进程回调将PreciseCallState发送出去,

mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
  backgroundCallState, DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID);
for (Record r : mRecords) {
  if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)
      && ((r.subId == subId) || (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) {
    try {
        r.callback.onPreciseCallStateChanged(mPreciseCallState);
     } catch (RemoteException ex) {
        mRemoveList.add(r.binder);
     }
  }
}

Record是TelephonyRegistry的内部类, callback是PhoneStateListener的binder对象,

这样就通过PreciseCallState 将三路通话的Call状态发送出去了。

2,调用broadcastPreciseCallStateChanged方法将三路通话的Call状态通过广播的形式发送出去,

broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
   DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID, subId);

broadcastPreciseCallStateChanged方法如下,

ntent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
   intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
}
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
 android.Manifest.permission.READ_PRECISE_PHONE_STATE);

因此, TelephonyRegistry类不仅通过回调发送phone的状态,而且还通过广播的形式将phone状态发送出去。

因此,第三方app可以注册并接收相应的广播。

2,状态更新

在GSMPhone 的notifyPreciseCallStateChangedP方法中,会通知phone状态的改变,

AsyncResult ar = new AsyncResult(null, this, null);
mPreciseCallStateRegistrants.notifyRegistrants(ar);

mPreciseCallStateRegistrants也是RegistrantList对象,定义如下,

protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList();

对于RegistrantList机制,就是一个观察者模式,谁注册就回调谁。

mPreciseCallStateRegistrants是在registerForPreciseCallStateChanged方法中完成注册的,

mPreciseCallStateRegistrants.addUnique(h, what, obj);

在unregisterForPreciseCallStateChanged方法中取消注册的,

mPreciseCallStateRegistrants.remove(h);

现在问题是哪个类会调用GSMPhone的registerForPreciseCallStateChanged方法进行注册,

TelephonyConnection.java中的setOriginalConnection方法会调用,如下,

getPhone().registerForPreciseCallStateChanged(
                mHandler, MSG_PRECISE_CALL_STATE_CHANGED, null);

当然,除此之外,还会注册一些很多其他的状态。

因此,一旦GSMPhone 的notifyPreciseCallStateChangedP方法得到调用,必然会向TelephonyConnection的内部

变量mHandler发送MSG_PRECISE_CALL_STATE_CHANGED方法,mHandler的handleMessage方法对该消息处理如下,

updateState();

在TelephonyConnection中, 有比较多的方法会调用updateState方法,例如,当远程挂断时, mHandler会收到MSG_DISCONNECT消息,

也会调用updateState方法。

updateState方法主要逻辑如下,

1,调用GsmConnection的方法获取电话的信息,例如号码,通话的Call状态等

final String number = mOriginalConnection.getAddress();
final Phone phone = mOriginalConnection.getCall().getPhone();
int cause = mOriginalConnection.getDisconnectCause();
final boolean isEmergencyNumber =
PhoneNumberUtils.isLocalEmergencyNumber(TelephonyGlobals. getApplicationContext(), number);
Call.State newState = mOriginalConnection.getState();

对于GMS制式的SIM卡来说,此处的mOriginalConnection就是GsmConnection对象。

getState方法就是获取Call.State的状态。

2,根据Call.State的状态调用不同的方法进行处理,对应的状态和方法如下,

Call.State

对应的处理方法

对应的Connection状态

对应的值

State.ACTIVE

setActiveInternal

STATE_ACTIVE

4

State. DIALING

setDialing

STATE_DIALING

3

State. ALERTING

State. HOLDING

setOnHold

STATE_HOLDING

5

State. INCOMING

setRinging

STATE_RINGING

2

State. WAITING

State. DISCONNECTED

setDisconnected

STATE_DISCONNECTED

6

State. DISCONNECTING

不处理

 

 

State. IDLE

例如,拨出电话---接听电话---挂断电话 对应的状态转换如下,


来电---接听电话---挂断电话 对应的状态转换如下,


3,最后更新信息

updateStatusHints();
updateConnectionCapabilities();
updateAddress();
updateMultiparty();

对于上表中的5个方法,现在分别一一论述。

TelephonyConnection的父类Connection的setDialing方法如下,

public final void setDialing() {
   checkImmutable();
   setState(STATE_DIALING); //调用setState将状态设置为STATE_DIALING
}

TelephonyConnection的父类Connection的setRinging方法如下,

setState(STATE_RINGING); //调用setState将状态设置为STATE_RINGING

setActiveInternal也会调用父类Connection的setActive方法, setActive方法如下,

setState(STATE_ACTIVE); //调用setState将状态设置为STATE_ACTIVE

TelephonyConnection的父类Connection的setOnHold方法如下,

setState(STATE_HOLDING); //调用setState将状态设置为STATE_HOLDING

TelephonyConnection的父类Connection的setDisconnected方法如下,

setState(STATE_DISCONNECTED); //调用setState将状态设置为STATE_DISCONNECTED
•••
for (Listener l : mListeners) {
    l.onDisconnected(this, disconnectCause); //调用监听器的onDisconnected方法。
}

由此可知,这5个方法都会调用setState方法设置状态, Connection的setState方法主要逻辑如下,

for (Listener l : mListeners) {
   l.onStateChanged(this, state);
}

调用监听器的onStateChanged方法。

根据 远程挂断电话流程分析 这一章节的论述逻辑,Connection的setState方法调用流程图如下,


ConnectionService的内部匿名类的onStateChanged如下,

switch (state) {
                case Connection.STATE_ACTIVE:
                    mAdapter.setActive(id);
                    break;
                case Connection.STATE_DIALING:
                    mAdapter.setDialing(id);
                    break;
                case Connection.STATE_DISCONNECTED:
                    // Handled in onDisconnected()
                    break;
                case Connection.STATE_HOLDING:
                    mAdapter.setOnHold(id);
                    break;
                case Connection.STATE_NEW:
                    // Nothing to tell Telecom
                    break;
                case Connection.STATE_RINGING:
                    mAdapter.setRinging(id);
                    break;
            }

就是根据不同的phone状态调用ConnectionServiceAdapter的4个不同方法。STATE_DISCONNECTED 没有在这个地方进行处理,

因为在其他流程中单独处理了。

ConnectionServiceAdapter的4个方法调用流程完全相同, setActive方法调用如下,

for (IConnectionServiceAdapter adapter : mAdapters) {
    try {
        adapter.setActive(callId);
    } catch (RemoteException e) {
    }
}

这是一个跨进程的调用,当前在phone进程中, IconnectionServiceAdapter 是Telecom进程的ConnectionServiceWrapper的内部类

Adapter在phone进程中的binder对象。因此,会跨进程调用到Telecom进程当中,入口就是ConnectionServiceWrapper的内部类Adapter。

3,Telecom状态更新

ConnectionServiceWrapper的内部类Adapter的setActive, setDialing, setOnHold, setRinging, setDisconnected等其他跨进程的方法

调用流程图完全相同,


CallsManager的4个方法都会调用setCallState方法设置Call的状态, markCallAsRinging方法如下,

void markCallAsRinging(Call call) {
    setCallState(call, CallState.RINGING, "ringing set explicitly");
}

setCallState主要逻辑如下,如果状态有变化,则调用监听器的onCallStateChanged方法,

for (CallsManagerListener listener : mListeners) {
   if (Log.SYSTRACE_DEBUG) {
        Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
   }
   listener.onCallStateChanged(call, oldState, newState);
   •••
}

最后的InCallController的updateCall方法逻辑如下,

1,调用toParcelableCall方法将 Call和CallState的状态进行映射,

ParcelableCall parcelableCall = toParcelableCall(call,
 videoProviderChanged /* includeVideoProvider */);

2,进行跨进程调用

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);

当前进程在Telecom中, IInCallService  是Dialer进程的InCallService内部类InCallServiceBinder在Telecom进程中的binder对象。

InCallController的toParcelableCall方法首先调用getParcelableState方法将状态进行映射,

int state = getParcelableState(call);

然后构造ParcelableCall对象并将状态保存在其中。

CallState 和telecom.Call映射的关系如下表,

CallState

telecom.Call

ABORTED

STATE_DISCONNECTED

DISCONNECTED

ACTIVE

STATE_ACTIVE

CONNECTING

STATE_CONNECTING

DIALING

STATE_DIALING

DISCONNECTING

STATE_DISCONNECTING

NEW

STATE_NEW

ON_HOLD

STATE_HOLDING

RINGING

STATE_RINGING

SELECT_PHONE_ACCOUNT

STATE_SELECT_PHONE_ACCOUNT

最后phone状态一路调用,终于进入了Dialer进程,入口方法为InCallService内部类InCallServiceBinder的updateCall方法。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值