/* * 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.net.NetworkConfig; import android.telephony.Rlog; import com.android.internal.R; import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; 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 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 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 PendingIntent getReconnectIntent() { return mReconnectAlarmIntent; } public synchronized void setReconnectIntent(PendingIntent intent) { mReconnectAlarmIntent = intent; } public synchronized ApnSetting getApnSetting() { log("getApnSetting: apnSetting=" + mApnSetting); return mApnSetting; } public synchronized void setApnSetting(ApnSetting apnSetting) { log("setApnSetting: apnSetting=" + apnSetting); mApnSetting = apnSetting; } public synchronized void setWaitingApns(ArrayList waitingApns) { mWaitingApns = waitingApns; mOriginalWaitingApns = new ArrayList(waitingApns); mWaitingApnsPermanentFailureCountDown.set(mWaitingApns.size()); } public int getWaitingApnsPermFailCount() { return mWaitingApnsPermanentFailureCountDown.get(); } public void decWaitingApnsPermFailCount() { mWaitingApnsPermanentFailureCountDown.decrementAndGet(); } public synchronized ApnSetting getNextWaitingApn() { ArrayList 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 getOriginalWaitingApns() { return mOriginalWaitingApns; } public synchronized ArrayList 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) || (mState == DctConstants.State.FAILED)); } public boolean isConnectedOrConnecting() { return isReady() && ((mState == DctConstants.State.CONNECTED) || (mState == DctConstants.State.CONNECTING) || (mState == DctConstants.State.SCANNING) || (mState == DctConstants.State.RETRYING)); } public void setEnabled(boolean enabled) { if (DBG) { log("set enabled as " + enabled + ", current state is " + mDataEnabled.get()); } mDataEnabled.set(enabled); } public boolean isEnabled() { return mDataEnabled.get(); } public void setDependencyMet(boolean met) { if (DBG) { log("set mDependencyMet as " + met + " current state is " + mDependencyMet.get()); } mDependencyMet.set(met); } public boolean getDependencyMet() { return mDependencyMet.get(); } public boolean isProvisioningApn() { String provisioningApn = mContext.getResources() .getString(R.string.mobile_provisioning_apn); if ((mApnSetting != null) && (mApnSetting.apn != null)) { return (mApnSetting.apn.equals(provisioningApn)); } else { return false; } } public void incRefCount() { synchronized (mRefCountLock) { if (mRefCount++ == 0) { mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), true); } } } public void decRefCount() { synchronized (mRefCountLock) { if (mRefCount-- == 1) { mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), false); } } } @Override public synchronized String toString() { // We don't print mDataConnection because its recursive. return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" + mWaitingApns + "} mWaitingApnsPermanentFailureCountDown=" + mWaitingApnsPermanentFailureCountDown + " mApnSetting={" + mApnSetting + "} mReason=" + mReason + " mDataEnabled=" + mDataEnabled + " mDependencyMet=" + mDependencyMet + "}"; } protected void log(String s) { Rlog.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("ApnContext: " + this.toString()); } }