protected ServiceStateTracker(PhoneBase phoneBase, CommandsInterface ci, CellInfo cellInfo) {
    mPhoneBase = phoneBase;
    mCellInfo = cellInfo;
    mCi = ci;
    mVoiceCapable =
        mPhoneBase
            .getContext()
            .getResources()
            .getBoolean(com.android.internal.R.bool.config_voice_capable);
    mUiccController = UiccController.getInstance();
    mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
    mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
    mCi.registerForCellInfoList(this, EVENT_UNSOL_CELL_INFO_LIST, null);

    mSubscriptionController = SubscriptionController.getInstance();
    mSubscriptionManager = SubscriptionManager.from(phoneBase.getContext());
    mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);

    mPhoneBase.setSystemProperty(
        TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
        ServiceState.rilRadioTechnologyToString(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN));
    mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
  }
  /**
   * Replace oldAdn with newAdn in ADN-like record in EF
   *
   * <p>getAdnRecordsInEf must be called at least once before this function, otherwise an error will
   * be returned. Currently the email field if set in the ADN record is ignored. throws
   * SecurityException if no WRITE_CONTACTS permission
   *
   * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
   * @param oldTag adn tag to be replaced
   * @param oldPhoneNumber adn number to be replaced Set both oldTag and oldPhoneNubmer to "" means
   *     to replace an empty record, aka, insert new record
   * @param newTag adn tag to be stored
   * @param newPhoneNumber adn number ot be stored Set both newTag and newPhoneNubmer to "" means to
   *     replace the old record with empty one, aka, delete old record
   * @param pin2 required to update EF_FDN, otherwise must be null
   * @return true for success
   */
  public boolean updateAdnRecordsInEfBySearch(
      int efid,
      String oldTag,
      String oldPhoneNumber,
      String newTag,
      String newPhoneNumber,
      String pin2) {

    if (phone.getContext().checkCallingOrSelfPermission(android.Manifest.permission.WRITE_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
      throw new SecurityException("Requires android.permission.WRITE_CONTACTS permission");
    }

    if (DBG)
      logd(
          "updateAdnRecordsInEfBySearch: efid="
              + efid
              + " ("
              + oldTag
              + ","
              + oldPhoneNumber
              + ")"
              + "==>"
              + " ("
              + newTag
              + ","
              + newPhoneNumber
              + ")"
              + " pin2="
              + pin2);

    efid = updateEfForIccType(efid);

    synchronized (mLock) {
      checkThread();
      success = false;
      Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE);
      AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber);
      AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
      adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response);
      try {
        mLock.wait();
      } catch (InterruptedException e) {
        logd("interrupted while trying to update by search");
      }
    }
    return success;
  }
 protected void updatePhoneObject() {
   if (mPhoneBase
       .getContext()
       .getResources()
       .getBoolean(com.android.internal.R.bool.config_switch_phone_on_voice_reg_state_change)) {
     // If the phone is not registered on a network, no need to update.
     boolean isRegistered =
         mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
             || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY;
     if (!isRegistered) {
       Rlog.d(LOG_TAG, "updatePhoneObject: Ignore update");
       return;
     }
     mPhoneBase.updatePhoneObject(mSS.getRilVoiceRadioTechnology());
   }
 }
 /**
  * Clean up existing voice and data connection then turn off radio power.
  *
  * <p>Hang up the existing voice calls to decrease call drop rate.
  */
 public void powerOffRadioSafely(DcTrackerBase dcTracker) {
   synchronized (this) {
     if (!mPendingRadioPowerOffAfterDataOff) {
       // In some network, deactivate PDP connection cause releasing of RRC connection,
       // which MM/IMSI detaching request needs. Without this detaching, network can
       // not release the network resources previously attached.
       // So we are avoiding data detaching on these networks.
       String[] networkNotClearData =
           mPhoneBase
               .getContext()
               .getResources()
               .getStringArray(com.android.internal.R.array.networks_not_clear_data);
       String currentNetwork = mSS.getOperatorNumeric();
       if ((networkNotClearData != null) && (currentNetwork != null)) {
         for (int i = 0; i < networkNotClearData.length; i++) {
           if (currentNetwork.equals(networkNotClearData[i])) {
             // Don't clear data connection for this carrier
             if (DBG) log("Not disconnecting data for " + currentNetwork);
             hangupAndPowerOff();
             return;
           }
         }
       }
       // To minimize race conditions we call cleanUpAllConnections on
       // both if else paths instead of before this isDisconnected test.
       if (dcTracker.isDisconnected()) {
         // To minimize race conditions we do this after isDisconnected
         dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
         if (DBG) log("Data disconnected, turn off radio right away.");
         hangupAndPowerOff();
       } else {
         dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
         Message msg = Message.obtain(this);
         msg.what = EVENT_SET_RADIO_POWER_OFF;
         msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
         if (sendMessageDelayed(msg, 30000)) {
           if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
           mPendingRadioPowerOffAfterDataOff = true;
         } else {
           log("Cannot send delayed Msg, turn off radio right away.");
           hangupAndPowerOff();
         }
       }
     }
   }
 }
  /**
   * Loads the AdnRecords in efid and returns them as a List of AdnRecords
   *
   * <p>throws SecurityException if no READ_CONTACTS permission
   *
   * @param efid the EF id of a ADN-like ICC
   * @return List of AdnRecord
   */
  public List<AdnRecord> getAdnRecordsInEf(int efid) {

    if (phone.getContext().checkCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
      throw new SecurityException("Requires android.permission.READ_CONTACTS permission");
    }

    efid = updateEfForIccType(efid);
    if (DBG) logd("getAdnRecordsInEF: efid=" + efid);

    synchronized (mLock) {
      checkThread();
      Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
      adnCache.requestLoadAllAdnLike(efid, adnCache.extensionEfForEf(efid), response);
      try {
        mLock.wait();
      } catch (InterruptedException e) {
        logd("interrupted while trying to load from the SIM");
      }
    }
    return records;
  }
 protected String getHomeOperatorNumeric() {
   return ((TelephonyManager) mPhoneBase.getContext().getSystemService(Context.TELEPHONY_SERVICE))
       .getSimOperatorNumericForPhone(mPhoneBase.getPhoneId());
 }