gt:                                 || (mState == DctConstants.State.FAILED));
context: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.internal.telephony.dataconnection;
  
  import android.app.PendingIntent;
  import android.content.Context;
  import android.content.res.Resources;
  import android.net.NetworkConfig;
  import android.telephony.Rlog;
  import android.text.TextUtils;
  import android.util.LocalLog;
  import android.util.SparseIntArray;
  
  import com.android.internal.R;
  import com.android.internal.telephony.DctConstants;
  import com.android.internal.telephony.Phone;
  import com.android.internal.util.IndentingPrintWriter;
  
  import java.io.FileDescriptor;
  import java.io.PrintWriter;
  import java.util.ArrayList;
  import java.util.concurrent.atomic.AtomicBoolean;
  import java.util.concurrent.atomic.AtomicInteger;
  
  /**
   * Maintain the Apn context
   */
  public class ApnContext {
  
      public final String LOG_TAG;
  
      protected static final boolean DBG = false;
  
      private final Context mContext;
  
      private final String mApnType;
  
      private DctConstants.State mState;
  
      private ArrayList<ApnSetting> mWaitingApns = null;
  
      /**
       * Used to check if conditions (new RAT) are resulting in a new list which warrants a retry.
       * Set in the last trySetupData call.
       */
      private ArrayList<ApnSetting> mOriginalWaitingApns = null;
  
      public final int priority;
  
      /** A zero indicates that all waiting APNs had a permanent error */
      private AtomicInteger mWaitingApnsPermanentFailureCountDown;
  
      private ApnSetting mApnSetting;
  
      DcAsyncChannel mDcAc;
  
      String mReason;
  
      PendingIntent mReconnectAlarmIntent;
  
      /**
       * user/app requested connection on this APN
       */
      AtomicBoolean mDataEnabled;
  
      private final Object mRefCountLock = new Object();
      private int mRefCount = 0;
  
      /**
       * carrier requirements met
       */
      AtomicBoolean mDependencyMet;
  
      private final DcTrackerBase mDcTracker;
  
      /**
       * Remember this as a change in this value to a more permissive state
       * should cause us to retry even permanent failures
       */
      private boolean mConcurrentVoiceAndDataAllowed;
  
      public ApnContext(Context context, String apnType, String logTag, NetworkConfig config,
              DcTrackerBase tracker) {
          mContext = context;
          mApnType = apnType;
          mState = DctConstants.State.IDLE;
          setReason(Phone.REASON_DATA_ENABLED);
          mDataEnabled = new AtomicBoolean(false);
          mDependencyMet = new AtomicBoolean(config.dependencyMet);
          mWaitingApnsPermanentFailureCountDown = new AtomicInteger(0);
          priority = config.priority;
          LOG_TAG = logTag;
          mDcTracker = tracker;
      }
  
      public String getApnType() {
          return mApnType;
      }
  
      public synchronized DcAsyncChannel getDcAc() {
          return mDcAc;
      }
  
      public synchronized void setDataConnectionAc(DcAsyncChannel dcac) {
          if (DBG) {
              log("setDataConnectionAc: old dcac=" + mDcAc + " new dcac=" + dcac
                      + " this=" + this);
          }
          mDcAc = dcac;
      }
  
      public synchronized void releaseDataConnection(String reason) {
          if (mDcAc != null) {
              mDcAc.tearDown(this, reason, null);
              mDcAc = null;
          }
          setState(DctConstants.State.IDLE);
      }
  
      public synchronized PendingIntent getReconnectIntent() {
          return mReconnectAlarmIntent;
      }
  
      public synchronized void setReconnectIntent(PendingIntent intent) {
          mReconnectAlarmIntent = intent;
      }
  
      public synchronized ApnSetting getApnSetting() {
          if (DBG) log("getApnSetting: apnSetting=" + mApnSetting);
          return mApnSetting;
      }
  
      public synchronized void setApnSetting(ApnSetting apnSetting) {
          if (DBG) log("setApnSetting: apnSetting=" + apnSetting);
          mApnSetting = apnSetting;
      }
  
      public synchronized void setWaitingApns(ArrayList<ApnSetting> waitingApns) {
          mWaitingApns = waitingApns;
          mOriginalWaitingApns = new ArrayList<ApnSetting>(waitingApns);
          mWaitingApnsPermanentFailureCountDown.set(mWaitingApns.size());
      }
  
      public int getWaitingApnsPermFailCount() {
          return mWaitingApnsPermanentFailureCountDown.get();
      }
  
      public void decWaitingApnsPermFailCount() {
          mWaitingApnsPermanentFailureCountDown.decrementAndGet();
      }
  
      public synchronized ApnSetting getNextWaitingApn() {
          ArrayList<ApnSetting> list = mWaitingApns;
          ApnSetting apn = null;
  
          if (list != null) {
              if (!list.isEmpty()) {
                  apn = list.get(0);
              }
          }
          return apn;
      }
  
      public synchronized void removeWaitingApn(ApnSetting apn) {
          if (mWaitingApns != null) {
              mWaitingApns.remove(apn);
          }
      }
  
      public synchronized ArrayList<ApnSetting> getOriginalWaitingApns() {
          return mOriginalWaitingApns;
      }
  
      public synchronized ArrayList<ApnSetting> getWaitingApns() {
          return mWaitingApns;
      }
  
      public synchronized void setConcurrentVoiceAndDataAllowed(boolean allowed) {
          mConcurrentVoiceAndDataAllowed = allowed;
      }
  
      public synchronized boolean isConcurrentVoiceAndDataAllowed() {
          return mConcurrentVoiceAndDataAllowed;
      }
  
      public synchronized void setState(DctConstants.State s) {
          if (DBG) {
              log("setState: " + s + ", previous state:" + mState);
          }
  
          mState = s;
  
          if (mState == DctConstants.State.FAILED) {
              if (mWaitingApns != null) {
                  mWaitingApns.clear(); // when teardown the connection and set to IDLE
              }
          }
      }
  
      public synchronized DctConstants.State getState() {
          return mState;
      }
  
      public boolean isDisconnected() {
          DctConstants.State currentState = getState();
          return ((currentState == DctConstants.State.IDLE) ||
                      currentState == DctConstants.State.FAILED);
      }
  
      public synchronized void setReason(String reason) {
          if (DBG) {
              log("set reason as " + reason + ",current state " + mState);
          }
          mReason = reason;
      }
  
      public synchronized String getReason() {
          return mReason;
      }
  
      public boolean isReady() {
          return mDataEnabled.get() && mDependencyMet.get();
      }
  
      public boolean isConnectable() {
          return isReady() && ((mState == DctConstants.State.IDLE)
                                  || (mState == DctConstants.State.SCANNING)
                                  || (mState == DctConstants.State.RETRYING)
  