@Override
 public void handleMessage(Message msg) {
   switch (msg.what) {
     case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
       if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
         if (VDBG) {
           mMdst.log("MdstHandler connected");
         }
         mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj;
       } else {
         if (VDBG) {
           mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1);
         }
       }
       break;
     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
       if (VDBG) mMdst.log("Disconnected from DataStateTracker");
       mMdst.mDataConnectionTrackerAc = null;
       break;
     default:
       {
         if (VDBG) mMdst.log("Ignorning unknown message=" + msg);
         break;
       }
   }
 }
  /**
   * enable or disable interface by apn type
   *
   * @param apnType the type of APN to be enabled or disabled (e.g., mms)
   * @param enable {@code true} to enable the specified APN type, {@code false} to disable it.
   * @param radioNum 0:sim1, 1:sim2
   * @return an integer value representing the outcome of the request.
   */
  private int setEnableApnGemini(String apnType, boolean enable, int radioNum) {
    getPhoneService(false);
    /*
     * If the phone process has crashed in the past, we'll get a
     * RemoteException and need to re-reference the service.
     */
    for (int retry = 0; retry < 2; retry++) {
      if (mPhoneService == null) {
        log("Ignoring feature request because could not acquire PhoneService");
        break;
      }

      try {
        if (enable) {
          log(
              "gemini before enableApnTypeGemini() and mApnType is "
                  + mApnType
                  + " ,radioNum is "
                  + radioNum);
          return mPhoneService.enableApnTypeGemini(apnType, radioNum);
        } else {
          return mPhoneService.disableApnTypeGemini(apnType, radioNum);
        }
      } catch (RemoteException e) {
        if (retry == 0) getPhoneService(true);
      }
    }

    log("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
    return PhoneConstants.APN_REQUEST_FAILED;
  }
 public void setInternalDataEnable(boolean enabled) {
   if (DBG) log("setInternalDataEnable: E enabled=" + enabled);
   final AsyncChannel channel = mDataConnectionTrackerAc;
   if (channel != null) {
     channel.sendMessage(
         DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE,
         enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
   }
   if (VDBG) log("setInternalDataEnable: X enabled=" + enabled);
 }
 @Override
 public void setUserDataEnable(boolean enabled) {
   if (DBG) log("setUserDataEnable: E enabled=" + enabled);
   final AsyncChannel channel = mDataConnectionTrackerAc;
   if (channel != null) {
     channel.sendMessage(CMD_SET_USER_DATA_ENABLE, enabled ? ENABLED : DISABLED);
     mUserDataEnabled = enabled;
   }
   if (VDBG) log("setUserDataEnable: X enabled=" + enabled);
 }
 /**
  * carrier dependency is met/unmet
  *
  * @param met
  */
 public void setDependencyMet(boolean met) {
   Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType);
   try {
     if (DBG) log("setDependencyMet: E met=" + met);
     Message msg = Message.obtain();
     msg.what = DctConstants.CMD_SET_DEPENDENCY_MET;
     msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED);
     msg.setData(bundle);
     mDataConnectionTrackerAc.sendMessage(msg);
     if (VDBG) log("setDependencyMet: X met=" + met);
   } catch (NullPointerException e) {
     loge("setDependencyMet: X mAc was null" + e);
   }
 }
 /**
  * Record the detailed state of a network, and if it is a change from the previous state, send a
  * notification to any listeners.
  *
  * @param state the new @{code DetailedState}
  * @param reason a {@code String} indicating a reason for the state change, if one was supplied.
  *     May be {@code null}.
  * @param extraInfo optional {@code String} providing extra information about the state change
  * @param simId 0 for sim1 and 1 for sim2
  */
 public void setDetailedStateGemini(
     NetworkInfo.DetailedState state, String reason, String extraInfo, int simId) {
   if (DBG)
     log(
         "setDetailed state, old ="
             + mNetworkInfo.getDetailedState()
             + " and new state="
             + state
             + " simId is "
             + simId);
   if (state != mNetworkInfo.getDetailedState()) {
     boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
     String lastReason = mNetworkInfo.getReason();
     /*
      * If a reason was supplied when the CONNECTING state was entered, and no
      * reason was supplied for entering the CONNECTED state, then retain the
      * reason that was supplied when going to CONNECTING.
      */
     if (wasConnecting
         && state == NetworkInfo.DetailedState.CONNECTED
         && reason == null
         && lastReason != null) reason = lastReason;
     mNetworkInfo.setDetailedStateGemini(state, reason, extraInfo, simId);
     Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
     msg.sendToTarget();
   } else if (reason != null
       && (reason.equals(PhoneConstants.REASON_NO_SUCH_PDP)
           || reason.equals(Phone.REASON_APN_FAILED))
       && state == DetailedState.DISCONNECTED) {
     mNetworkInfo.setDetailedStateGemini(state, reason, extraInfo, simId);
     Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
     msg.sendToTarget();
   }
 }
  public NetworkInfo getNetworkInfo() {
    if (FeatureOption.MTK_GEMINI_SUPPORT) {
      getPhoneService(true);
      /*
       * If the phone process has crashed in the past, we'll get a
       * RemoteException and need to re-reference the service.
       */
      for (int retry = 0; retry < 2; retry++) {
        if (mPhoneService == null) {
          loge("Ignoring feature request because could not acquire PhoneService");
          break;
        }

        try {
          /**
           * M: update availabe info due to it may not correct when we received from
           * ACTION_ANY_DATA_CONNECTION_STATE_CHANGED
           */
          mNetworkInfo.setIsAvailable(mPhoneService.isDataConnectivityPossible());
          log("getNetworkInfo: updated IsAvailable=" + mNetworkInfo.isAvailable());
        } catch (RemoteException e) {
          if (retry == 0) getPhoneService(true);
        }
      }
    }

    return mNetworkInfo;
  }
 /**
  * Eanble/disable FailFast
  *
  * @param enabled is DctConstants.ENABLED/DISABLED
  */
 public void setEnableFailFastMobileData(int enabled) {
   if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")");
   final AsyncChannel channel = mDataConnectionTrackerAc;
   if (channel != null) {
     channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled);
   }
 }
 @Override
 public void setPolicyDataEnable(boolean enabled) {
   if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")");
   final AsyncChannel channel = mDataConnectionTrackerAc;
   if (channel != null) {
     channel.sendMessage(CMD_SET_POLICY_DATA_ENABLE, enabled ? ENABLED : DISABLED);
     mPolicyDataEnabled = enabled;
   }
 }
 /** Inform DCT mobile provisioning has started, it ends when provisioning completes. */
 public void enableMobileProvisioning(String url) {
   if (DBG) log("enableMobileProvisioning(url=" + url + ")");
   final AsyncChannel channel = mDataConnectionTrackerAc;
   if (channel != null) {
     Message msg = Message.obtain();
     msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING;
     msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url));
     channel.sendMessage(msg);
   }
 }
 /**
  * Return if this network is the provisioning network. Valid only if connected.
  *
  * @param met
  */
 public boolean isProvisioningNetwork() {
   boolean retVal;
   try {
     Message msg = Message.obtain();
     msg.what = DctConstants.CMD_IS_PROVISIONING_APN;
     msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType));
     Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg);
     retVal = result.arg1 == DctConstants.ENABLED;
   } catch (NullPointerException e) {
     loge("isProvisioningNetwork: X " + e);
     retVal = false;
   }
   if (DBG) log("isProvisioningNetwork: retVal=" + retVal);
   return retVal;
 }
 /**
  * Record the detailed state of a network, and if it is a change from the previous state, send a
  * notification to any listeners.
  *
  * @param state the new @{code DetailedState}
  * @param reason a {@code String} indicating a reason for the state change, if one was supplied.
  *     May be {@code null}.
  * @param extraInfo optional {@code String} providing extra information about the state change
  */
 private void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) {
   if (DBG)
     log("setDetailed state, old =" + mNetworkInfo.getDetailedState() + " and new state=" + state);
   if (state != mNetworkInfo.getDetailedState()) {
     boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
     String lastReason = mNetworkInfo.getReason();
     /*
      * If a reason was supplied when the CONNECTING state was entered, and no
      * reason was supplied for entering the CONNECTED state, then retain the
      * reason that was supplied when going to CONNECTING.
      */
     if (wasConnecting
         && state == NetworkInfo.DetailedState.CONNECTED
         && reason == null
         && lastReason != null) reason = lastReason;
     mNetworkInfo.setDetailedState(state, reason, extraInfo);
     Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo));
     msg.sendToTarget();
   }
 }
    @Override
    public void onReceive(Context context, Intent intent) {
      if (intent
          .getAction()
          .equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE)) {
        String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
        MobileDataStateTracker tracker = mTrackerMap.get(apnType);
        if (tracker == null) {
          return;
        }

        int slot = 0;
        int curSlot = 0;
        if (FeatureOption.MTK_GEMINI_SUPPORT) {
          slot = intent.getIntExtra(PhoneConstants.GEMINI_SIM_ID_KEY, PhoneConstants.GEMINI_SIM_1);
          curSlot = tracker.mNetworkInfo.getSimId();
        }

        if (tracker.mMobileDataState == PhoneConstants.DataState.CONNECTED) {
          if (slot != curSlot) {
            tracker.log("Receive peer SIM data state.ignor!");
            return;
          }
        }

        if (VDBG)
          Slog.d(
              TAG,
              "MobileDataStateReceiver received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE ["
                  + apnType
                  + "]");
        tracker.log(
            "Intent from SIM "
                + slot
                + ", current SIM "
                + curSlot
                + ", current DataState "
                + tracker.mMobileDataState);

        int oldSubtype = tracker.mNetworkInfo.getSubtype();
        int newSubType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
        String subTypeName;
        if (FeatureOption.MTK_GEMINI_SUPPORT) {
          newSubType =
              TelephonyManager.getDefault().getNetworkTypeGemini(tracker.mNetworkInfo.getSimId());
          subTypeName =
              TelephonyManager.getDefault()
                  .getNetworkTypeNameGemini(tracker.mNetworkInfo.getSimId());
        } else {
          newSubType = TelephonyManager.getDefault().getNetworkType();
          subTypeName = TelephonyManager.getDefault().getNetworkTypeName();
        }

        tracker.mNetworkInfo.setSubtype(newSubType, subTypeName);
        if (newSubType != oldSubtype && tracker.mNetworkInfo.isConnected()) {
          Message msg =
              tracker.mTarget.obtainMessage(
                  EVENT_NETWORK_SUBTYPE_CHANGED, oldSubtype, 0, tracker.mNetworkInfo);
          msg.sendToTarget();
        }

        PhoneConstants.DataState state =
            Enum.valueOf(
                PhoneConstants.DataState.class, intent.getStringExtra(PhoneConstants.STATE_KEY));
        String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY);
        String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
        tracker.mNetworkInfo.setRoaming(
            intent.getBooleanExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, false));
        if (VDBG) {
          tracker.log(
              tracker.mApnType
                  + " setting isAvailable to "
                  + !intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, false));
        }
        tracker.mNetworkInfo.setIsAvailable(
            !intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, false));

        if (DBG) {
          tracker.log(
              "Received state="
                  + state
                  + ", old="
                  + tracker.mMobileDataState
                  + ", reason="
                  + (reason == null ? "(unspecified)" : reason));
        }
        if (tracker.mMobileDataState != state) {
          tracker.mMobileDataState = state;
          switch (state) {
            case DISCONNECTED:
              if (tracker.isTeardownRequested()) {
                tracker.setTeardownRequested(false);
              }
              if (FeatureOption.MTK_GEMINI_SUPPORT) {
                tracker.setDetailedStateGemini(DetailedState.DISCONNECTED, reason, apnName, slot);
              } else {
                tracker.setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
              }
              // can't do this here - ConnectivityService needs it to clear stuff
              // it's ok though - just leave it to be refreshed next time
              // we connect.
              // if (DBG) log("clearing mInterfaceName for "+ mApnType +
              //        " as it DISCONNECTED");
              // mInterfaceName = null;
              break;
            case CONNECTING:
              if (FeatureOption.MTK_GEMINI_SUPPORT) {
                tracker.setDetailedStateGemini(DetailedState.CONNECTING, reason, apnName, slot);
              } else {
                tracker.setDetailedState(DetailedState.CONNECTING, reason, apnName);
              }
              break;
            case SUSPENDED:
              if (FeatureOption.MTK_GEMINI_SUPPORT) {
                tracker.setDetailedStateGemini(DetailedState.SUSPENDED, reason, apnName, slot);
              } else {
                tracker.setDetailedState(DetailedState.SUSPENDED, reason, apnName);
              }
              break;
            case CONNECTED:
              tracker.mLinkProperties =
                  intent.getParcelableExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY);
              if (tracker.mLinkProperties == null) {
                tracker.loge("CONNECTED event did not supply link properties.");
                tracker.mLinkProperties = new LinkProperties();
              }
              tracker.mLinkCapabilities =
                  intent.getParcelableExtra(PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
              if (tracker.mLinkCapabilities == null) {
                tracker.loge("CONNECTED event did not supply link capabilities.");
                tracker.mLinkCapabilities = new LinkCapabilities();
              }
              if (FeatureOption.MTK_GEMINI_SUPPORT) {
                tracker.setDetailedStateGemini(DetailedState.CONNECTED, reason, apnName, slot);
              } else {
                tracker.setDetailedState(DetailedState.CONNECTED, reason, apnName);
              }

              break;
          }
        } else {
          // There was no state change. Check if LinkProperties has been updated.
          if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
            tracker.mLinkProperties =
                intent.getParcelableExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY);
            if (tracker.mLinkProperties == null) {
              tracker.loge("No link property in LINK_PROPERTIES change event.");
              tracker.mLinkProperties = new LinkProperties();
            }
            // Just update reason field in this NetworkInfo
            tracker.mNetworkInfo.setDetailedState(
                tracker.mNetworkInfo.getDetailedState(),
                reason,
                tracker.mNetworkInfo.getExtraInfo());
            Message msg =
                tracker.mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, tracker.mNetworkInfo);
            msg.sendToTarget();
          }

          if (reason != null
              && (reason.equals(Phone.REASON_APN_FAILED)
                  || reason.equals(PhoneConstants.REASON_NO_SUCH_PDP))
              && apnType != null
              && !apnType.equals(PhoneConstants.APN_TYPE_DEFAULT)) {
            tracker.log(
                "Handle PhoneConstants.REASON_APN_FAILED OR  PhoneConstants.REASON_NO_SUCH_PDP from GeminiDataSubUtil");
            if (state == PhoneConstants.DataState.DISCONNECTED) {
              if (tracker.isTeardownRequested()) {
                tracker.setTeardownRequested(false);
              }
              if (FeatureOption.MTK_GEMINI_SUPPORT) {
                tracker.setDetailedStateGemini(DetailedState.DISCONNECTED, reason, apnName, slot);
              } else {
                tracker.setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
              }
            }
          }
        }
      } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
        String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
        MobileDataStateTracker tracker = mTrackerMap.get(apnType);
        if (tracker == null) {
          return;
        }
        if (DBG)
          Slog.d(
              TAG,
              "MobileDataStateReceiver received: ACTION_ANY_DATA_CONNECTION_FAILED ignore ["
                  + apnType
                  + "]");

        int slot = 0;
        String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
        String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
        if (DBG) {
          tracker.log(
              "Received " + intent.getAction() + " broadcast" + reason == null
                  ? ""
                  : "(" + reason + ")");
        }
        if (FeatureOption.MTK_GEMINI_SUPPORT) {
          slot = intent.getIntExtra(PhoneConstants.GEMINI_SIM_ID_KEY, PhoneConstants.GEMINI_SIM_1);
          tracker.setDetailedStateGemini(DetailedState.FAILED, reason, apnName, slot);
        } else {
          tracker.setDetailedState(DetailedState.FAILED, reason, apnName);
        }
      } else if (intent.getAction().equals(DctConstants.ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
        if (VDBG)
          Slog.d(TAG, "MobileDataStateReceiver received: ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
        Messenger messenger = intent.getParcelableExtra(DctConstants.EXTRA_MESSENGER);
        Collection<MobileDataStateTracker> collection = mTrackerMap.values();
        Iterator<MobileDataStateTracker> iter = collection.iterator();
        while (iter.hasNext()) {
          MobileDataStateTracker tracker = iter.next();
          tracker.mMessenger = messenger;
          AsyncChannel ac = new AsyncChannel();
          ac.connect(tracker.mContext, tracker.mHandler, tracker.mMessenger);
        }
      } else {
        if (DBG) Slog.d(TAG, "MobileDataStateReceiver received: ignore " + intent.getAction());
      }
    }
 public void supplyMessenger(Messenger messenger) {
   if (VDBG) log(mApnType + " got supplyMessenger");
   AsyncChannel ac = new AsyncChannel();
   ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger);
 }