Пример #1
0
        @Override
        public void onCallTerminated(ImsCall imsCall, ImsReasonInfo reasonInfo) {
          if (DBG) log("onCallTerminated reasonCode=" + reasonInfo.getCode());

          ImsPhoneCall.State oldState = mForegroundCall.getState();
          int cause = getDisconnectCauseFromReasonInfo(reasonInfo);
          ImsPhoneConnection conn = findConnection(imsCall);
          if (DBG) log("cause = " + cause + " conn = " + conn);

          if (conn != null && conn.isIncoming() && conn.getConnectTime() == 0) {
            // Missed
            if (cause == DisconnectCause.NORMAL) {
              cause = DisconnectCause.INCOMING_MISSED;
            }
            if (DBG)
              log("Incoming connection of 0 connect time detected - translated cause = " + cause);
          }

          if (cause == DisconnectCause.NORMAL && conn != null && conn.getImsCall().isMerged()) {
            // Call was terminated while it is merged instead of a remote disconnect.
            cause = DisconnectCause.IMS_MERGED_SUCCESSFULLY;
          }

          processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause);
        }
Пример #2
0
  private void processCallStateChange(ImsCall imsCall, ImsPhoneCall.State state, int cause) {
    if (DBG) log("processCallStateChange " + imsCall + " state=" + state + " cause=" + cause);

    if (imsCall == null) return;

    boolean changed = false;
    ImsPhoneConnection conn = findConnection(imsCall);

    if (conn == null) {
      // TODO : what should be done?
      return;
    }

    changed = conn.update(imsCall, state);

    if (state == ImsPhoneCall.State.DISCONNECTED) {
      changed = conn.onDisconnect(cause) || changed;
      // detach the disconnected connections
      conn.getCall().detach(conn);
      removeConnection(conn);
    }

    if (changed) {
      if (conn.getCall() == mHandoverCall) return;
      updatePhoneState();
      mPhone.notifyPreciseCallStateChanged();
    }
  }
Пример #3
0
 private void transferHandoverConnections(ImsPhoneCall call) {
   if (call.mConnections != null) {
     for (Connection c : call.mConnections) {
       c.mPreHandoverState = call.mState;
       log("Connection state before handover is " + c.getStateBeforeHandover());
     }
   }
   if (mHandoverCall.mConnections == null) {
     mHandoverCall.mConnections = call.mConnections;
   } else { // Multi-call SRVCC
     mHandoverCall.mConnections.addAll(call.mConnections);
   }
   if (mHandoverCall.mConnections != null) {
     if (call.getImsCall() != null) {
       call.getImsCall().close();
     }
     for (Connection c : mHandoverCall.mConnections) {
       ((ImsPhoneConnection) c).changeParent(mHandoverCall);
       ((ImsPhoneConnection) c).releaseWakeLock();
     }
   }
   if (call.getState().isAlive()) {
     log("Call is alive and state is " + call.mState);
     mHandoverCall.mState = call.mState;
   }
   call.mConnections.clear();
   call.mState = ImsPhoneCall.State.IDLE;
 }
Пример #4
0
  void conference() {
    if (DBG) log("conference");

    ImsCall fgImsCall = mForegroundCall.getImsCall();
    if (fgImsCall == null) {
      log("conference no foreground ims call");
      return;
    }

    ImsCall bgImsCall = mBackgroundCall.getImsCall();
    if (bgImsCall == null) {
      log("conference no background ims call");
      return;
    }

    // Keep track of the connect time of the earliest call so that it can be set on the
    // {@code ImsConference} when it is created.
    long conferenceConnectTime =
        Math.min(
            mForegroundCall.getEarliestConnectTime(), mBackgroundCall.getEarliestConnectTime());
    ImsPhoneConnection foregroundConnection = mForegroundCall.getFirstConnection();
    if (foregroundConnection != null) {
      foregroundConnection.setConferenceConnectTime(conferenceConnectTime);
    }

    try {
      fgImsCall.merge(bgImsCall);
    } catch (ImsException e) {
      log("conference " + e.getMessage());
    }
  }
Пример #5
0
 private synchronized ImsPhoneConnection findConnection(ImsCall imsCall) {
   for (ImsPhoneConnection conn : mConnections) {
     if (conn.getImsCall() == imsCall) {
       return conn;
     }
   }
   return null;
 }
Пример #6
0
  /*package*/ void hangup(ImsPhoneConnection conn) throws CallStateException {
    if (DBG) log("hangup connection");

    if (conn.getOwner() != this) {
      throw new CallStateException(
          "ImsPhoneConnection " + conn + "does not belong to ImsPhoneCallTracker " + this);
    }

    hangup(conn.getCall());
  }
Пример #7
0
        /**
         * Called when the state of IMS conference participant(s) has changed.
         *
         * @param call the call object that carries out the IMS call.
         * @param participants the participant(s) and their new state information.
         */
        @Override
        public void onConferenceParticipantsStateChanged(
            ImsCall call, List<ConferenceParticipant> participants) {
          if (DBG) log("onConferenceParticipantsStateChanged");

          ImsPhoneConnection conn = findConnection(call);
          if (conn != null) {
            conn.updateConferenceParticipants(participants);
          }
        }
Пример #8
0
  /* package */ void hangup(ImsPhoneCall call) throws CallStateException {
    if (DBG) log("hangup call");

    if (call.getConnections().size() == 0) {
      throw new CallStateException("no connections");
    }

    ImsCall imsCall = call.getImsCall();
    boolean rejectCall = false;

    if (call == mRingingCall) {
      if (Phone.DEBUG_PHONE) log("(ringing) hangup incoming");
      rejectCall = true;
    } else if (call == mForegroundCall) {
      if (call.isDialingOrAlerting()) {
        if (Phone.DEBUG_PHONE) {
          log("(foregnd) hangup dialing or alerting...");
        }
      } else {
        if (Phone.DEBUG_PHONE) {
          log("(foregnd) hangup foreground");
        }
        // held call will be resumed by onCallTerminated
      }
    } else if (call == mBackgroundCall) {
      if (Phone.DEBUG_PHONE) {
        log("(backgnd) hangup waiting or background");
      }
    } else {
      throw new CallStateException(
          "ImsPhoneCall " + call + "does not belong to ImsPhoneCallTracker " + this);
    }

    call.onHangupLocal();

    try {
      if (imsCall != null) {
        if (rejectCall) imsCall.reject(ImsReasonInfo.CODE_USER_DECLINE);
        else imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED);
      } else if (mPendingMO != null && call == mForegroundCall) {
        // is holding a foreground call
        mPendingMO.update(null, ImsPhoneCall.State.DISCONNECTED);
        mPendingMO.onDisconnect();
        removeConnection(mPendingMO);
        mPendingMO = null;
        updatePhoneState();
        removeMessages(EVENT_DIAL_PENDINGMO);
      }
    } catch (ImsException e) {
      throw new CallStateException(e.getMessage());
    }

    mPhone.notifyPreciseCallStateChanged();
  }
Пример #9
0
        @Override
        public void onCallHoldReceived(ImsCall imsCall) {
          if (DBG) log("onCallHoldReceived");

          ImsPhoneConnection conn = findConnection(imsCall);
          if (conn != null && conn.getState() == ImsPhoneCall.State.ACTIVE) {
            if (!mOnHoldToneStarted && ImsPhoneCall.isLocalTone(imsCall)) {
              mPhone.startOnHoldTone();
              mOnHoldToneStarted = true;
            }
          }
        }
Пример #10
0
        @Override
        public void onReceive(Context context, Intent intent) {
          if (intent.getAction().equals(ImsManager.ACTION_IMS_INCOMING_CALL)) {
            if (DBG) log("onReceive : incoming call intent");

            if (mImsManager == null) return;

            if (mServiceId < 0) return;

            try {
              // Network initiated USSD will be treated by mImsUssdListener
              boolean isUssd = intent.getBooleanExtra(ImsManager.EXTRA_USSD, false);
              if (isUssd) {
                if (DBG) log("onReceive : USSD");
                mUssdSession = mImsManager.takeCall(mServiceId, intent, mImsUssdListener);
                if (mUssdSession != null) {
                  mUssdSession.accept(ImsCallProfile.CALL_TYPE_VOICE);
                }
                return;
              }

              // Normal MT call
              ImsCall imsCall = mImsManager.takeCall(mServiceId, intent, mImsCallListener);
              ImsPhoneConnection conn =
                  new ImsPhoneConnection(
                      mPhone.getContext(), imsCall, ImsPhoneCallTracker.this, mRingingCall);
              addConnection(conn);

              IImsVideoCallProvider imsVideoCallProvider =
                  imsCall.getCallSession().getVideoCallProvider();
              if (imsVideoCallProvider != null) {
                ImsVideoCallProviderWrapper imsVideoCallProviderWrapper =
                    new ImsVideoCallProviderWrapper(imsVideoCallProvider);
                conn.setVideoProvider(imsVideoCallProviderWrapper);
              }

              if ((mForegroundCall.getState() != ImsPhoneCall.State.IDLE)
                  || (mBackgroundCall.getState() != ImsPhoneCall.State.IDLE)) {
                conn.update(imsCall, ImsPhoneCall.State.WAITING);
              }

              mPhone.notifyNewRingingConnection(conn);
              mPhone.notifyIncomingRing();

              updatePhoneState();
              mPhone.notifyPreciseCallStateChanged();
            } catch (ImsException e) {
              loge("onReceive : exception " + e);
            } catch (RemoteException e) {
            }
          }
        }
Пример #11
0
  private void dialInternal(ImsPhoneConnection conn, int clirMode, int videoState) {
    if (conn == null) {
      return;
    }

    if (conn.getAddress() == null
        || conn.getAddress().length() == 0
        || conn.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {
      // Phone number is invalid
      conn.setDisconnectCause(DisconnectCause.INVALID_NUMBER);
      sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO);
      return;
    }

    // Always unmute when initiating a new call
    setMute(false);
    int serviceType =
        PhoneNumberUtils.isEmergencyNumber(conn.getAddress())
            ? ImsCallProfile.SERVICE_TYPE_EMERGENCY
            : ImsCallProfile.SERVICE_TYPE_NORMAL;
    int callType = ImsCallProfile.getCallTypeFromVideoState(videoState);
    // TODO(vt): Is this sufficient?  At what point do we know the video state of the call?
    conn.setVideoState(videoState);

    try {
      String[] callees = new String[] {conn.getAddress()};
      ImsCallProfile profile = mImsManager.createCallProfile(mServiceId, serviceType, callType);
      profile.setCallExtraInt(ImsCallProfile.EXTRA_OIR, clirMode);

      ImsCall imsCall = mImsManager.makeCall(mServiceId, profile, callees, mImsCallListener);
      conn.setImsCall(imsCall);

      IImsVideoCallProvider imsVideoCallProvider = imsCall.getCallSession().getVideoCallProvider();
      if (imsVideoCallProvider != null) {
        ImsVideoCallProviderWrapper imsVideoCallProviderWrapper =
            new ImsVideoCallProviderWrapper(imsVideoCallProvider);
        conn.setVideoProvider(imsVideoCallProviderWrapper);
      }
    } catch (ImsException e) {
      loge("dialInternal : " + e);
      conn.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED);
      sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO);
    } catch (RemoteException e) {
    }
  }
Пример #12
0
        @Override
        public void onCallHoldFailed(ImsCall imsCall, ImsReasonInfo reasonInfo) {
          if (DBG) log("onCallHoldFailed reasonCode=" + reasonInfo.getCode());

          synchronized (mSyncHold) {
            ImsPhoneCall.State bgState = mBackgroundCall.getState();
            if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED) {
              // disconnected while processing hold
              if (mPendingMO != null) {
                sendEmptyMessage(EVENT_DIAL_PENDINGMO);
              }
            } else if (bgState == ImsPhoneCall.State.ACTIVE) {
              mForegroundCall.switchWith(mBackgroundCall);

              if (mPendingMO != null) {
                mPendingMO.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED);
                sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO);
              }
            }
          }
        }
Пример #13
0
        /**
         * onCallStartFailed will be invoked when: case 1) Dialing fails case 2) Ringing call is
         * disconnected by local or remote user
         */
        @Override
        public void onCallStartFailed(ImsCall imsCall, ImsReasonInfo reasonInfo) {
          if (DBG) log("onCallStartFailed reasonCode=" + reasonInfo.getCode());

          if (mPendingMO != null) {
            // To initiate dialing circuit-switched call
            if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED
                && mBackgroundCall.getState() == ImsPhoneCall.State.IDLE
                && mRingingCall.getState() == ImsPhoneCall.State.IDLE) {
              mForegroundCall.detach(mPendingMO);
              removeConnection(mPendingMO);
              mPendingMO.finalize();
              mPendingMO = null;
              mPhone.initiateSilentRedial();
              return;
            } else {
              int cause = getDisconnectCauseFromReasonInfo(reasonInfo);
              processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause);
            }
            mPendingMO = null;
          }
        }
Пример #14
0
  @Override
  public void handleMessage(Message msg) {
    AsyncResult ar;
    if (DBG) log("handleMessage what=" + msg.what);

    switch (msg.what) {
      case EVENT_HANGUP_PENDINGMO:
        if (mPendingMO != null) {
          mPendingMO.onDisconnect();
          removeConnection(mPendingMO);
          mPendingMO = null;
        }

        updatePhoneState();
        mPhone.notifyPreciseCallStateChanged();
        break;
      case EVENT_RESUME_BACKGROUND:
        try {
          resumeWaitingOrHolding();
        } catch (CallStateException e) {
          if (Phone.DEBUG_PHONE) {
            loge("handleMessage EVENT_RESUME_BACKGROUND exception=" + e);
          }
        }
        break;
      case EVENT_DIAL_PENDINGMO:
        dialInternal(mPendingMO, mClirMode, VideoProfile.VideoState.AUDIO_ONLY);
        break;

      case EVENT_EXIT_ECM_RESPONSE_CDMA:
        // no matter the result, we still do the same here
        if (pendingCallInEcm) {
          dialInternal(mPendingMO, pendingCallClirMode, pendingCallVideoState);
          pendingCallInEcm = false;
        }
        mPhone.unsetOnEcbModeExitResponse(this);
        break;
    }
  }