/**
   * Handles the call to get the subscription source
   *
   * @param ar AsyncResult object that contains the result of get CDMA subscription source call
   */
  private void handleGetCdmaSubscriptionSource(AsyncResult ar) {
    if ((ar.exception == null) && (ar.result != null)) {
      int newSubscriptionSource = ((int[]) ar.result)[0];

      if (newSubscriptionSource != mCdmaSubscriptionSource.get()) {
        log(
            "Subscription Source Changed : "
                + mCdmaSubscriptionSource
                + " >> "
                + newSubscriptionSource);
        mCdmaSubscriptionSource.set(newSubscriptionSource);

        // Save CDMA subscription source
        saveCdmaSubscriptionSource(newSubscriptionSource);

        // Notify registrants of the new CDMA subscription source
        mCdmaSubscriptionSourceChangedRegistrants.notifyRegistrants(
            new AsyncResult(null, null, null));
      }
    } else {
      // GET_CDMA_SUBSCRIPTION is returning Failure. Probably
      // because modem created GSM Phone. If modem created
      // GSMPhone, then PhoneProxy will trigger a change in
      // Phone objects and this object will be destroyed.
      logw(
          "Unable to get CDMA Subscription Source, Exception: "
              + ar.exception
              + ", result: "
              + ar.result);
    }
  }
  /**
   * Handles the call to get the subscription source
   *
   * @param ar AsyncResult object that contains the result of get CDMA subscription source call
   */
  private void handleCdmaSubscriptionSource(AsyncResult ar) {
    if ((ar.exception == null) && (ar.result != null)) {
      int newSubscriptionSource = ((int[]) ar.result)[0];
      boolean cdmaSubSourceChanged = false;

      if (newSubscriptionSource != mCdmaSubscriptionSource) {
        Log.v(
            LOG_TAG,
            "Subscription Source Changed : "
                + mCdmaSubscriptionSource
                + " >> "
                + newSubscriptionSource);
        mCdmaSubscriptionSource = newSubscriptionSource;
        cdmaSubSourceChanged = true;
      }

      if (cdmaSubSourceChanged || mNotifyCdmaSubSource) {
        // Notify registrants of the new CDMA subscription source
        mCdmaSubscriptionSourceChangedRegistrants.notifyRegistrants(
            new AsyncResult(null, null, null));
        if (mNotifyCdmaSubSource) mNotifyCdmaSubSource = false;
      }
    } else {
      // GET_CDMA_SUBSCRIPTION is returning Failure. Probably
      // because modem created GSM Phone. If modem created
      // GSMPhone, then PhoneProxy will trigger a change in
      // Phone objects and this object will be destroyed.
      Log.w(
          LOG_TAG,
          "Unable to get CDMA Subscription Source, Exception: "
              + ar.exception
              + ", result: "
              + ar.result);
    }
  }
  /**
   * Registration point for combined roaming on of mobile data combined roaming is true when roaming
   * is true and ONS differs SPN
   *
   * @param h handler to notify
   * @param what what code of message when delivered
   * @param obj placed in Message.obj
   */
  public void registerForDataRoamingOn(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mDataRoamingOnRegistrants.add(r);

    if (mSS.getDataRoaming()) {
      r.notifyRegistrant();
    }
  }
  /**
   * Registration point for combined roaming off combined roaming is true when roaming is true and
   * ONS differs SPN
   *
   * @param h handler to notify
   * @param what what code of message when delivered
   * @param obj placed in Message.obj
   */
  public void registerForRoamingOff(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mRoamingOffRegistrants.add(r);

    if (!ss.getRoaming()) {
      r.notifyRegistrant();
    }
  }
  /**
   * Registration point for transition into DataConnection detached.
   *
   * @param h handler to notify
   * @param what what code of message when delivered
   * @param obj placed in Message.obj
   */
  public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mDetachedRegistrants.add(r);

    if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
      r.notifyRegistrant();
    }
  }
  /**
   * Registration point for transition into network attached.
   *
   * @param h handler to notify
   * @param what what code of message when delivered
   * @param obj in Message.obj
   */
  public void registerForNetworkAttached(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);

    mNetworkAttachedRegistrants.add(r);
    if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
      r.notifyRegistrant();
    }
  }
  /**
   * Registration point for transition out of packet service restricted zone.
   *
   * @param h handler to notify
   * @param what what code of message when delivered
   * @param obj placed in Message.obj
   */
  public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mPsRestrictDisabledRegistrants.add(r);

    if (mRestrictedState.isPsRestricted()) {
      r.notifyRegistrant();
    }
  }
 /**
  * Notify all mDataConnectionRatChangeRegistrants using an AsyncResult in msg.obj where
  * AsyncResult#result contains the new RAT as an Integer Object.
  */
 protected void notifyDataRegStateRilRadioTechnologyChanged() {
   int rat = mSS.getRilDataRadioTechnology();
   int drs = mSS.getDataRegState();
   if (DBG) log("notifyDataRegStateRilRadioTechnologyChanged: drs=" + drs + " rat=" + rat);
   mPhoneBase.setSystemProperty(
       TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
       ServiceState.rilRadioTechnologyToString(rat));
   mDataRegStateOrRatChangedRegistrants.notifyResult(new Pair<Integer, Integer>(drs, rat));
 }
  private void updatePhoneState() {
    PhoneConstants.State oldState = state;

    if (ringingCall.isRinging()) {
      state = PhoneConstants.State.RINGING;
    } else if (pendingMO != null || !(foregroundCall.isIdle() && backgroundCall.isIdle())) {
      state = PhoneConstants.State.OFFHOOK;
    } else {
      state = PhoneConstants.State.IDLE;
    }

    if (state == PhoneConstants.State.IDLE && oldState != state) {
      voiceCallEndedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
    } else if (oldState == PhoneConstants.State.IDLE && oldState != state) {
      voiceCallStartedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
    }

    if (state != oldState) {
      phone.notifyPhoneStateChanged();
    }
  }
 /** Unregisters for the registered event with RIL */
 public void dispose(Handler h) {
   mCdmaSubscriptionSourceChangedRegistrants.remove(h);
   synchronized (sReferenceCountMonitor) {
     sReferenceCount--;
     if (sReferenceCount <= 0) {
       mCM.unregisterForCdmaSubscriptionChanged(this);
       mCM.unregisterForOn(this);
       mCM.unregisterForSubscriptionStatusChanged(this);
       sInstance = null;
     }
   }
 }
  /** Unregisters for the registered event with RIL */
  public void dispose(Handler handler) {
    if (null != handler) {
      mCdmaSubscriptionSourceChangedRegistrants.remove(handler);
    }

    mRef--;
    if (mRef <= 0) {
      mCM.unregisterForCdmaSubscriptionSourceChanged(this);
      mCM.unregisterForOn(this);
      mCM.unregisterForSubscriptionStatusChanged(this);
      mCdmaSSMInstances.remove(mCM);
    }
  }
  private void updatePhoneState() {
    PhoneConstants.State oldState = mState;

    if (mRingingCall.isRinging()) {
      mState = PhoneConstants.State.RINGING;
    } else if (mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {
      mState = PhoneConstants.State.OFFHOOK;
    } else {
      mState = PhoneConstants.State.IDLE;
    }

    if (mState == PhoneConstants.State.IDLE && oldState != mState) {
      mVoiceCallEndedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
    } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) {
      mVoiceCallStartedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
    }

    if (DBG) log("updatePhoneState oldState=" + oldState + ", newState=" + mState);

    if (mState != oldState) {
      mPhone.notifyPhoneStateChanged();
    }
  }
 void unregisterForModemProfileReady(Handler h) {
   mModemDataProfileRegistrants.remove(h);
 }
 public void unregisterForDataConnectionDetached(Handler h) {
   mDetachedRegistrants.remove(h);
 }
  /*
   * Process the response for the RIL request GET_DATA_CALL_PROFILE.
   * Save the profile details received.
   */
  private void onGetDataCallProfileDone(AsyncResult ar, int context) {
    if (ar.exception != null) {
      log("OMH: Exception in onGetDataCallProfileDone:" + ar.exception);
      return;
    }

    if (context != mOmhReadProfileContext) {
      // we have other onReadOmhDataprofiles() on the way.
      return;
    }

    // DataProfile list from the modem for a given SERVICE_TYPE. These may
    // be from RUIM in case of OMH
    ArrayList<DataProfile> dataProfileListModem = new ArrayList<DataProfile>();
    dataProfileListModem = (ArrayList<DataProfile>) ar.result;

    DataProfileTypeModem modemProfile = (DataProfileTypeModem) ar.userObj;

    mOmhReadProfileCount--;

    if (dataProfileListModem != null && dataProfileListModem.size() > 0) {
      String serviceType;

      /* For the modem service type, get the android DataServiceType */
      serviceType = modemProfile.getDataServiceType();

      log(
          "OMH: # profiles returned from modem:"
              + dataProfileListModem.size()
              + " for "
              + serviceType);

      mOmhServicePriorityMap.put(
          serviceType, omhListGetArbitratedPriority(dataProfileListModem, serviceType));

      for (DataProfile dp : dataProfileListModem) {

        /* Store the modem profile type in the data profile */
        ((DataProfileOmh) dp).setDataProfileTypeModem(modemProfile);

        /* Look through mTempOmhDataProfilesList for existing profile id's
         * before adding it. This implies that the (similar) profile with same
         * priority already exists.
         */
        DataProfileOmh omhDuplicatedp = getDuplicateProfile(dp);
        if (null == omhDuplicatedp) {
          mTempOmhDataProfilesList.add(dp);
          ((DataProfileOmh) dp)
              .addServiceType(DataProfileTypeModem.getDataProfileTypeModem(serviceType));
        } else {
          /*  To share the already established data connection
           * (say between SUPL and DUN) in cases such as below:
           *  Ex:- SUPL+DUN [profile id 201, priority 1]
           *  'dp' instance is found at this point. Add the non-provisioned
           *   service type to this 'dp' instance
           */
          log("OMH: Duplicate Profile " + omhDuplicatedp);
          ((DataProfileOmh) omhDuplicatedp)
              .addServiceType(DataProfileTypeModem.getDataProfileTypeModem(serviceType));
        }
      }
    }

    // (Re)Load APN List
    if (mOmhReadProfileCount == 0) {
      log("OMH: Modem omh profile read complete.");
      addServiceTypeToUnSpecified();
      mDataProfilesList.addAll(mTempOmhDataProfilesList);
      mModemDataProfileRegistrants.notifyRegistrants();
    }

    return;
  }
 public void unregisterForRoamingOff(Handler h) {
   mRoamingOffRegistrants.remove(h);
 }
 public void unregisterForDataRegStateOrRatChanged(Handler h) {
   mDataRegStateOrRatChangedRegistrants.remove(h);
 }
 public void unregisterForVoiceCallEnded(Handler h) {
   voiceCallEndedRegistrants.remove(h);
 }
 public void unregisterForPsRestrictedDisabled(Handler h) {
   mPsRestrictDisabledRegistrants.remove(h);
 }
 /**
  * Clients automatically register for CDMA subscription source changed event when they get an
  * instance of this object.
  */
 private void registerForCdmaSubscriptionSourceChanged(Handler h, int what, Object obj) {
   Registrant r = new Registrant(h, what, obj);
   mCdmaSubscriptionSourceChangedRegistrants.add(r);
 }
 public void unregisterForSuppServiceNotification(Handler h) {
   mSsnRegistrants.remove(h);
   if (mSsnRegistrants.size() == 0) mCM.setSuppServiceNotifications(false, null);
 }
 public void registerForSuppServiceNotification(Handler h, int what, Object obj) {
   mSsnRegistrants.addUnique(h, what, obj);
   if (mSsnRegistrants.size() == 1) mCM.setSuppServiceNotifications(true, null);
 }
  @Override
  public void handleMessage(Message msg) {
    AsyncResult ar;
    Message onComplete;

    switch (msg.what) {
      case EVENT_RADIO_AVAILABLE:
        {
          mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));

          mCM.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
          mCM.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
        }
        break;

      case EVENT_RADIO_ON:
        break;

      case EVENT_REGISTERED_TO_NETWORK:
        syncClirSetting();
        break;

      case EVENT_SIM_RECORDS_LOADED:
        updateCurrentCarrierInProvider();

        // Check if this is a different SIM than the previous one. If so unset the
        // voice mail number.
        String imsi = getVmSimImsi();
        String imsiFromSIM = getSubscriberId();
        if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
          storeVoiceMailNumber(null);
          setVmSimImsi(null);
        }

        break;

      case EVENT_GET_BASEBAND_VERSION_DONE:
        ar = (AsyncResult) msg.obj;

        if (ar.exception != null) {
          break;
        }

        if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
        setSystemProperty(PROPERTY_BASEBAND_VERSION, (String) ar.result);
        break;

      case EVENT_GET_IMEI_DONE:
        ar = (AsyncResult) msg.obj;

        if (ar.exception != null) {
          break;
        }

        mImei = (String) ar.result;
        break;

      case EVENT_GET_IMEISV_DONE:
        ar = (AsyncResult) msg.obj;

        if (ar.exception != null) {
          break;
        }

        mImeiSv = (String) ar.result;
        break;

      case EVENT_USSD:
        ar = (AsyncResult) msg.obj;

        String[] ussdResult = (String[]) ar.result;

        if (ussdResult.length > 1) {
          try {
            onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
          } catch (NumberFormatException e) {
            Log.w(LOG_TAG, "error parsing USSD");
          }
        }
        break;

      case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
        // Some MMI requests (eg USSD) are not completed
        // within the course of a CommandsInterface request
        // If the radio shuts off or resets while one of these
        // is pending, we need to clean up.

        for (int i = 0, s = mPendingMMIs.size(); i < s; i++) {
          if (mPendingMMIs.get(i).isPendingUSSD()) {
            mPendingMMIs.get(i).onUssdFinishedError();
          }
        }
        break;

      case EVENT_SSN:
        ar = (AsyncResult) msg.obj;
        SuppServiceNotification not = (SuppServiceNotification) ar.result;
        mSsnRegistrants.notifyRegistrants(ar);
        break;

      case EVENT_SET_CALL_FORWARD_DONE:
        ar = (AsyncResult) msg.obj;
        if (ar.exception == null) {
          mSIMRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
        }
        onComplete = (Message) ar.userObj;
        if (onComplete != null) {
          AsyncResult.forMessage(onComplete, ar.result, ar.exception);
          onComplete.sendToTarget();
        }
        break;

      case EVENT_SET_VM_NUMBER_DONE:
        ar = (AsyncResult) msg.obj;
        if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
          storeVoiceMailNumber(mVmNumber);
          ar.exception = null;
        }
        onComplete = (Message) ar.userObj;
        if (onComplete != null) {
          AsyncResult.forMessage(onComplete, ar.result, ar.exception);
          onComplete.sendToTarget();
        }
        break;

      case EVENT_GET_CALL_FORWARD_DONE:
        ar = (AsyncResult) msg.obj;
        if (ar.exception == null) {
          handleCfuQueryResult((CallForwardInfo[]) ar.result);
        }
        onComplete = (Message) ar.userObj;
        if (onComplete != null) {
          AsyncResult.forMessage(onComplete, ar.result, ar.exception);
          onComplete.sendToTarget();
        }
        break;

        // handle the select network completion callbacks.
      case EVENT_SET_NETWORK_MANUAL_COMPLETE:
      case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
        handleSetSelectNetwork((AsyncResult) msg.obj);
        break;

      case EVENT_SET_CLIR_COMPLETE:
        ar = (AsyncResult) msg.obj;
        if (ar.exception == null) {
          saveClirSetting(msg.arg1);
        }
        onComplete = (Message) ar.userObj;
        if (onComplete != null) {
          AsyncResult.forMessage(onComplete, ar.result, ar.exception);
          onComplete.sendToTarget();
        }
        break;

      default:
        super.handleMessage(msg);
    }
  }
 public void unregisterForNetworkAttached(Handler h) {
   mNetworkAttachedRegistrants.remove(h);
 }
 void registerForModemProfileReady(Handler h, int what, Object obj) {
   Registrant r = new Registrant(h, what, obj);
   mModemDataProfileRegistrants.add(r);
 }
 public void unregisterForDataRoamingOn(Handler h) {
   mDataRoamingOnRegistrants.remove(h);
 }
 public void registerForVoiceCallEnded(Handler h, int what, Object obj) {
   Registrant r = new Registrant(h, what, obj);
   voiceCallEndedRegistrants.add(r);
 }
 public void unregisterForVoiceRoamingOn(Handler h) {
   mVoiceRoamingOnRegistrants.remove(h);
 }
 @Override
 public void unregisterForVoiceCallStarted(Handler h) {
   mVoiceCallStartedRegistrants.remove(h);
 }
 /**
  * Registration for DataConnection RIL Data Radio Technology changing. The new radio technology
  * will be returned AsyncResult#result as an Integer Object. The AsyncResult will be in the
  * notification Message#obj.
  *
  * @param h handler to notify
  * @param what what code of message when delivered
  * @param obj placed in Message.obj
  */
 public void registerForDataRegStateOrRatChanged(Handler h, int what, Object obj) {
   Registrant r = new Registrant(h, what, obj);
   mDataRegStateOrRatChangedRegistrants.add(r);
   notifyDataRegStateRilRadioTechnologyChanged();
 }