/** Factory method to start query with a number */
  public static CallerInfoAsyncQuery startQuery(
      int token, Context context, String number, OnQueryCompleteListener listener, Object cookie) {
    // contruct the URI object and start Query.
    Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

    CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
    c.allocate(context, contactRef);

    if (DBG) log("starting query for number: " + number + " handler: " + c.toString());

    // create cookieWrapper, start query
    CookieWrapper cw = new CookieWrapper();
    cw.listener = listener;
    cw.cookie = cookie;
    cw.number = number;

    // check to see if these are recognized numbers, and use shortcuts if we can.
    if (PhoneNumberUtils.isEmergencyNumber(number)) {
      cw.event = EVENT_EMERGENCY_NUMBER;
    } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
      cw.event = EVENT_VOICEMAIL_NUMBER;
    } else {
      cw.event = EVENT_NEW_QUERY;
    }

    c.mHandler.startQuery(token, cw, contactRef, null, null, null, null);

    return c;
  }
  @Override
  public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
    RILRequest rr;
    if (PhoneNumberUtils.isEmergencyNumber(address)) {
      Log.v(LOG_TAG, "Emergency dial: " + address);
      rr = RILRequest.obtain(RIL_REQUEST_DIAL_EMERGENCY, result);
      rr.mp.writeString(address + "/");
    } else {
      rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
      rr.mp.writeString(address);
    }

    rr.mp.writeInt(clirMode);
    rr.mp.writeInt(0); // UUS information is absent

    if (uusInfo == null) {
      rr.mp.writeInt(0); // UUS information is absent
    } else {
      rr.mp.writeInt(1); // UUS information is present
      rr.mp.writeInt(uusInfo.getType());
      rr.mp.writeInt(uusInfo.getDcs());
      rr.mp.writeByteArray(uusInfo.getUserData());
    }

    if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

    send(rr);
  }
  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) {
    }
  }
 /**
  * Helper function for newFromDialString. Returns true if dialString appears to be a short code
  * AND conditions are correct for it to be treated as such.
  */
 private static boolean isShortCode(String dialString, GSMPhone phone) {
   // check for any  Adapt change requirements.
   boolean shortCodeExclusionFlag = false;
   if (SystemProperties.getBoolean("persist.cust.tel.adapt", false)) {
     if (dialString.length() == 2) {
       Log.i(LOG_TAG, "Adapt, Number needs to be checked for short code exclusion list");
       shortCodeExclusionFlag = isExcludedShortCode(dialString);
     }
   }
   // Refer to TS 22.030 Figure 3.5.3.2:
   // A 1 or 2 digit "short code" is treated as USSD if it is entered while on a call or
   // does not satisfy the condition (exactly 2 digits && starts with '1').
   return ((dialString != null && dialString.length() <= 2)
       && !PhoneNumberUtils.isEmergencyNumber(dialString)
       && (phone.isInCall()
           || !((dialString.length() == 2 && dialString.charAt(0) == '1')
               || shortCodeExclusionFlag
               /*
                * While contrary to TS 22.030, there is strong precedence for
                * treating "0" and "00" as call setup strings.
                */
               || dialString.equals("0")
               || dialString.equals("00"))));
 }
  /** oirMode is one of the CLIR_ constants */
  synchronized Connection dial(String dialString, int clirMode, int videoState)
      throws CallStateException {
    boolean isPhoneInEcmMode =
        SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false);
    boolean isEmergencyNumber = PhoneNumberUtils.isEmergencyNumber(dialString);

    if (DBG) log("dial clirMode=" + clirMode);

    // note that this triggers call state changed notif
    clearDisconnected();

    if (mImsManager == null) {
      throw new CallStateException("service not available");
    }

    if (!canDial()) {
      throw new CallStateException("cannot dial in current state");
    }

    if (isPhoneInEcmMode && isEmergencyNumber) {
      handleEcmTimer(ImsPhone.CANCEL_ECM_TIMER);
    }

    boolean holdBeforeDial = false;

    // The new call must be assigned to the foreground call.
    // That call must be idle, so place anything that's
    // there on hold
    if (mForegroundCall.getState() == ImsPhoneCall.State.ACTIVE) {
      if (mBackgroundCall.getState() != ImsPhoneCall.State.IDLE) {
        // we should have failed in !canDial() above before we get here
        throw new CallStateException("cannot dial in current state");
      }
      // foreground call is empty for the newly dialed connection
      holdBeforeDial = true;
      switchWaitingOrHoldingAndActive();
    }

    ImsPhoneCall.State fgState = ImsPhoneCall.State.IDLE;
    ImsPhoneCall.State bgState = ImsPhoneCall.State.IDLE;

    mClirMode = clirMode;

    synchronized (mSyncHold) {
      if (holdBeforeDial) {
        fgState = mForegroundCall.getState();
        bgState = mBackgroundCall.getState();

        // holding foreground call failed
        if (fgState == ImsPhoneCall.State.ACTIVE) {
          throw new CallStateException("cannot dial in current state");
        }

        // holding foreground call succeeded
        if (bgState == ImsPhoneCall.State.HOLDING) {
          holdBeforeDial = false;
        }
      }

      mPendingMO =
          new ImsPhoneConnection(
              mPhone.getContext(), checkForTestEmergencyNumber(dialString), this, mForegroundCall);
    }
    addConnection(mPendingMO);

    if (!holdBeforeDial) {
      if ((!isPhoneInEcmMode) || (isPhoneInEcmMode && isEmergencyNumber)) {
        dialInternal(mPendingMO, clirMode, videoState);
      } else {
        try {
          getEcbmInterface().exitEmergencyCallbackMode();
        } catch (ImsException e) {
          e.printStackTrace();
          throw new CallStateException("service not available");
        }
        mPhone.setOnEcbModeExitResponse(this, EVENT_EXIT_ECM_RESPONSE_CDMA, null);
        pendingCallClirMode = clirMode;
        pendingCallVideoState = videoState;
        pendingCallInEcm = true;
      }
    }

    updatePhoneState();
    mPhone.notifyPreciseCallStateChanged();

    return mPendingMO;
  }