Revert "Revert "add apn setting parameters, and set apn parameters to bp""
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / dataconnection / DcTracker.java
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.internal.telephony.dataconnection;
18
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.ActivityNotFoundException;
22 import android.content.ContentResolver;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.res.Resources;
28 import android.database.ContentObserver;
29 import android.database.Cursor;
30 import android.net.ConnectivityManager;
31 import android.net.LinkProperties;
32 import android.net.NetworkCapabilities;
33 import android.net.NetworkConfig;
34 import android.net.NetworkFactory;
35 import android.net.NetworkRequest;
36 import android.net.NetworkUtils;
37 import android.net.ProxyInfo;
38 import android.net.Uri;
39 import android.os.AsyncResult;
40 import android.os.Build;
41 import android.os.Handler;
42 import android.os.Looper;
43 import android.os.Message;
44 import android.os.Messenger;
45 import android.os.RegistrantList;
46 import android.os.SystemClock;
47 import android.os.SystemProperties;
48 import android.os.UserHandle;
49 import android.provider.Settings;
50 import android.provider.Telephony;
51 import android.telephony.CellLocation;
52 import android.telephony.ServiceState;
53 import android.telephony.TelephonyManager;
54 import android.telephony.SubscriptionManager;
55 import android.telephony.cdma.CdmaCellLocation;
56 import android.telephony.gsm.GsmCellLocation;
57 import android.text.TextUtils;
58 import android.util.EventLog;
59 import android.telephony.Rlog;
60
61 import com.android.internal.telephony.cdma.CDMALTEPhone;
62 import com.android.internal.telephony.Phone;
63 import com.android.internal.telephony.PhoneBase;
64 import com.android.internal.telephony.DctConstants;
65 import com.android.internal.telephony.EventLogTags;
66 import com.android.internal.telephony.TelephonyIntents;
67 import com.android.internal.telephony.gsm.GSMPhone;
68 import com.android.internal.telephony.PhoneConstants;
69 import com.android.internal.telephony.RILConstants;
70 import com.android.internal.telephony.uicc.IccRecords;
71 import com.android.internal.telephony.uicc.UiccController;
72 import com.android.internal.util.AsyncChannel;
73 import com.android.internal.util.ArrayUtils;
74
75 import java.io.FileDescriptor;
76 import java.io.PrintWriter;
77 import java.util.ArrayList;
78 import java.util.concurrent.atomic.AtomicBoolean;
79 import java.util.HashMap;
80
81 import android.provider.Settings;
82
83 import com.android.internal.telephony.ServiceStateTracker;
84 /**
85  * {@hide}
86  */
87 public final class DcTracker extends DcTrackerBase {
88     protected final String LOG_TAG = "DCT";
89
90     /**
91      * List of messages that are waiting to be posted, when data call disconnect
92      * is complete
93      */
94     private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>();
95
96     private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
97
98     protected int mDisconnectPendingCount = 0;
99
100     /**
101      * Handles changes to the APN db.
102      */
103     private class ApnChangeObserver extends ContentObserver {
104         public ApnChangeObserver () {
105             super(mDataConnectionTracker);
106         }
107
108         @Override
109         public void onChange(boolean selfChange) {
110             sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED));
111         }
112     }
113
114     //***** Instance Variables
115
116     private boolean mReregisterOnReconnectFailure = false;
117
118
119     //***** Constants
120
121     // Used by puppetmaster/*/radio_stress.py
122     private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active";
123
124     private static final int POLL_PDP_MILLIS = 5 * 1000;
125
126     static final Uri PREFERAPN_NO_UPDATE_URI =
127                         Uri.parse("content://telephony/carriers/preferapn_no_update");
128     static final String APN_ID = "apn_id";
129
130     private boolean mCanSetPreferApn = false;
131
132     private AtomicBoolean mAttached = new AtomicBoolean(false);
133
134     /** Watches for changes to the APN db. */
135     private ApnChangeObserver mApnObserver;
136
137     /** Used to send us NetworkRequests from ConnectivityService.  Remeber it so we can
138      * unregister on dispose. */
139     private Messenger mNetworkFactoryMessenger;
140     private NetworkFactory mNetworkFactory;
141     private NetworkCapabilities mNetworkFilter;
142
143     public boolean mImsRegistrationState = false;
144     private ApnContext mWaitCleanUpApnContext = null;
145     private boolean mDeregistrationAlarmState = false;
146     private PendingIntent mImsDeregistrationDelayIntent = null;
147
148     //***** Constructor
149     public DcTracker(PhoneBase p) {
150         super(p);
151         if (DBG) log("GsmDCT.constructor");
152
153         mDataConnectionTracker = this;
154         update();
155         mApnObserver = new ApnChangeObserver();
156         p.getContext().getContentResolver().registerContentObserver(
157                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
158
159         initApnContexts();
160
161         for (ApnContext apnContext : mApnContexts.values()) {
162             // Register the reconnect and restart actions.
163             IntentFilter filter = new IntentFilter();
164             filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType());
165             filter.addAction(INTENT_RESTART_TRYSETUP_ALARM + '.' + apnContext.getApnType());
166             mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
167         }
168
169         ConnectivityManager cm = (ConnectivityManager)p.getContext().getSystemService(
170                 Context.CONNECTIVITY_SERVICE);
171
172         mNetworkFilter = new NetworkCapabilities();
173         mNetworkFilter.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
174         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
175         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
176         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
177         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
178         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
179         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
180         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
181         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
182         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
183         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
184         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
185         mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
186
187         mNetworkFactory = new TelephonyNetworkFactory(this.getLooper(), p.getContext(),
188                 "TelephonyNetworkFactory", mNetworkFilter);
189         mNetworkFactory.setScoreFilter(50);
190         mNetworkFactoryMessenger = new Messenger(mNetworkFactory);
191         cm.registerNetworkFactory(mNetworkFactoryMessenger, "Telephony");
192
193         // Add Emergency APN to APN setting list by default to support EPDN in sim absent cases
194         initEmergencyApnSetting();
195         addEmergencyApnSetting();
196     }
197
198     protected void registerForAllEvents() {
199         mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null);
200         mPhone.mCi.registerForOffOrNotAvailable(this,
201                DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
202         mPhone.mCi.registerForDataNetworkStateChanged(this,
203                DctConstants.EVENT_DATA_STATE_CHANGED, null);
204         mPhone.getCallTracker().registerForVoiceCallEnded (this,
205                DctConstants.EVENT_VOICE_CALL_ENDED, null);
206         mPhone.getCallTracker().registerForVoiceCallStarted (this,
207                DctConstants.EVENT_VOICE_CALL_STARTED, null);
208         mPhone.getServiceStateTracker().registerForDataConnectionAttached(this,
209                DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
210         mPhone.getServiceStateTracker().registerForDataConnectionDetached(this,
211                DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
212         mPhone.getServiceStateTracker().registerForRoamingOn(this,
213                DctConstants.EVENT_ROAMING_ON, null);
214         mPhone.getServiceStateTracker().registerForRoamingOff(this,
215                DctConstants.EVENT_ROAMING_OFF, null);
216         mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
217                 DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
218         mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
219                 DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
220      //   SubscriptionManager.registerForDdsSwitch(this,
221      //          DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null);
222         mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this,
223                 DctConstants.EVENT_DATA_RAT_CHANGED, null);
224     }
225     @Override
226     public void dispose() {
227         if (DBG) log("GsmDCT.dispose");
228
229         ConnectivityManager cm = (ConnectivityManager)mPhone.getContext().getSystemService(
230                 Context.CONNECTIVITY_SERVICE);
231         cm.unregisterNetworkFactory(mNetworkFactoryMessenger);
232         mNetworkFactoryMessenger = null;
233
234         cleanUpAllConnections(true, null);
235
236         super.dispose();
237
238         mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver);
239         mApnContexts.clear();
240         mPrioritySortedApnContexts.clear();
241
242         destroyDataConnections();
243     }
244     protected void unregisterForAllEvents() {
245          //Unregister for all events
246         mPhone.mCi.unregisterForAvailable(this);
247         mPhone.mCi.unregisterForOffOrNotAvailable(this);
248         IccRecords r = mIccRecords.get();
249         if (r != null) {
250             r.unregisterForRecordsLoaded(this);
251             mIccRecords.set(null);
252         }
253         mPhone.mCi.unregisterForDataNetworkStateChanged(this);
254         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
255         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
256         mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
257         mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
258         mPhone.getServiceStateTracker().unregisterForRoamingOn(this);
259         mPhone.getServiceStateTracker().unregisterForRoamingOff(this);
260         mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
261         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
262         //SubscriptionManager.unregisterForDdsSwitch(this);
263     }
264
265     private class TelephonyNetworkFactory extends NetworkFactory {
266         public TelephonyNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities nc) {
267             super(l, c, TAG, nc);
268         }
269
270         @Override
271         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
272             // figure out the apn type and enable it
273             if (DBG) log("Cellular needs Network for " + networkRequest);
274             ApnContext apnContext = apnContextForNetworkRequest(networkRequest);
275             if (apnContext != null) apnContext.incRefCount();
276         }
277
278         @Override
279         protected void releaseNetworkFor(NetworkRequest networkRequest) {
280             if (DBG) log("Cellular releasing Network for " + networkRequest);
281             ApnContext apnContext = apnContextForNetworkRequest(networkRequest);
282             if (apnContext != null) apnContext.decRefCount();
283         }
284     }
285
286     private ApnContext apnContextForNetworkRequest(NetworkRequest nr) {
287         NetworkCapabilities nc = nr.networkCapabilities;
288         // for now, ignore the bandwidth stuff
289         if (nc.getTransportTypes().length > 0 &&
290                 nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == false) {
291             return null;
292         }
293
294         // in the near term just do 1-1 matches.
295         // TODO - actually try to match the set of capabilities
296         int type = -1;
297         String name = null;
298
299         boolean error = false;
300         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
301             if (name != null) error = true;
302             name = PhoneConstants.APN_TYPE_DEFAULT;
303             type = ConnectivityManager.TYPE_MOBILE;
304         }
305         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
306             if (name != null) error = true;
307             name = PhoneConstants.APN_TYPE_MMS;
308             type = ConnectivityManager.TYPE_MOBILE_MMS;
309         }
310         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
311             if (name != null) error = true;
312             name = PhoneConstants.APN_TYPE_SUPL;
313             type = ConnectivityManager.TYPE_MOBILE_SUPL;
314         }
315         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
316             if (name != null) error = true;
317             name = PhoneConstants.APN_TYPE_DUN;
318             type = ConnectivityManager.TYPE_MOBILE_DUN;
319         }
320         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
321             if (name != null) error = true;
322             name = PhoneConstants.APN_TYPE_FOTA;
323             type = ConnectivityManager.TYPE_MOBILE_FOTA;
324         }
325         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
326             if (name != null) error = true;
327             name = PhoneConstants.APN_TYPE_IMS;
328             type = ConnectivityManager.TYPE_MOBILE_IMS;
329         }
330         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
331             if (name != null) error = true;
332             name = PhoneConstants.APN_TYPE_CBS;
333             type = ConnectivityManager.TYPE_MOBILE_CBS;
334         }
335         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) {
336             if (name != null) error = true;
337             name = PhoneConstants.APN_TYPE_IA;
338             type = ConnectivityManager.TYPE_MOBILE_IA;
339         }
340         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_RCS)) {
341             if (name != null) error = true;
342             name = null;
343             loge("RCS APN type not yet supported");
344         }
345         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
346             if (name != null) error = true;
347             name = null;
348             loge("XCAP APN type not yet supported");
349         }
350         if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
351             if (name != null) error = true;
352             name = null;
353             loge("EIMS APN type not yet supported");
354         }
355         if (error) {
356             loge("Multiple apn types specified in request - result is unspecified!");
357         }
358         if (type == -1 || name == null) {
359             loge("Unsupported NetworkRequest in Telephony: " + nr);
360             return null;
361         }
362         ApnContext apnContext = mApnContexts.get(name);
363         if (apnContext == null) {
364             loge("Request for unsupported mobile type: " + type);
365         }
366         return apnContext;
367     }
368
369     @Override
370     public boolean isApnTypeActive(String type) {
371         ApnContext apnContext = mApnContexts.get(type);
372         if (apnContext == null) return false;
373
374         return (apnContext.getDcAc() != null);
375     }
376
377     @Override
378     public boolean isDataPossible(String apnType) {
379         ApnContext apnContext = mApnContexts.get(apnType);
380         if (apnContext == null) {
381             return false;
382         }
383         boolean apnContextIsEnabled = apnContext.isEnabled();
384         DctConstants.State apnContextState = apnContext.getState();
385         boolean apnTypePossible = !(apnContextIsEnabled &&
386                 (apnContextState == DctConstants.State.FAILED));
387         boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
388         // Set the emergency APN availability status as TRUE irrespective of conditions checked in
389         // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc.
390         boolean dataAllowed = isEmergencyApn || isDataAllowed();
391         boolean possible = dataAllowed && apnTypePossible;
392
393         if (VDBG) {
394             log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
395                     "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
396                     apnType, possible, dataAllowed, apnTypePossible,
397                     apnContextIsEnabled, apnContextState));
398         }
399         return possible;
400     }
401
402     @Override
403     protected void finalize() {
404         if(DBG) log("finalize");
405     }
406
407     protected void supplyMessenger() {
408        // Supply the data connection tracker messenger only if
409        // this is corresponding to the current DDS.
410        if (!isActiveDataSubscription()) {
411            return;
412        }
413
414         ConnectivityManager cm = (ConnectivityManager)mPhone.getContext().getSystemService(
415                 Context.CONNECTIVITY_SERVICE);
416         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE, new Messenger(this));
417         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_MMS, new Messenger(this));
418         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_SUPL, new Messenger(this));
419         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_DUN, new Messenger(this));
420         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_HIPRI, new Messenger(this));
421         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_FOTA, new Messenger(this));
422         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_IMS, new Messenger(this));
423         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_CBS, new Messenger(this));
424         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_EMERGENCY, new Messenger(this));
425     }
426
427     private ApnContext addApnContext(String type, NetworkConfig networkConfig) {
428         ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG, networkConfig,
429                 this);
430         mApnContexts.put(type, apnContext);
431         mPrioritySortedApnContexts.add(apnContext);
432         return apnContext;
433     }
434
435     protected void initApnContexts() {
436         log("initApnContexts: E");
437         // Load device network attributes from resources
438         String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
439                 com.android.internal.R.array.networkAttributes);
440         for (String networkConfigString : networkConfigStrings) {
441             NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
442             ApnContext apnContext = null;
443
444             switch (networkConfig.type) {
445             case ConnectivityManager.TYPE_MOBILE:
446                 apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
447                 break;
448             case ConnectivityManager.TYPE_MOBILE_MMS:
449                 apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
450                 break;
451             case ConnectivityManager.TYPE_MOBILE_SUPL:
452                 apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig);
453                 break;
454             case ConnectivityManager.TYPE_MOBILE_DUN:
455                 apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig);
456                 break;
457             case ConnectivityManager.TYPE_MOBILE_HIPRI:
458                 apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig);
459                 break;
460             case ConnectivityManager.TYPE_MOBILE_FOTA:
461                 apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig);
462                 break;
463             case ConnectivityManager.TYPE_MOBILE_IMS:
464                 apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig);
465                 break;
466             case ConnectivityManager.TYPE_MOBILE_CBS:
467                 apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig);
468                 break;
469             case ConnectivityManager.TYPE_MOBILE_IA:
470                 apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig);
471                 break;
472             case ConnectivityManager.TYPE_MOBILE_EMERGENCY:
473                 apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig);
474                 break;
475             default:
476                 log("initApnContexts: skipping unknown type=" + networkConfig.type);
477                 continue;
478             }
479             log("initApnContexts: apnContext=" + apnContext);
480         }
481         log("initApnContexts: X mApnContexts=" + mApnContexts);
482     }
483
484     @Override
485     public LinkProperties getLinkProperties(String apnType) {
486         ApnContext apnContext = mApnContexts.get(apnType);
487         if (apnContext != null) {
488             DcAsyncChannel dcac = apnContext.getDcAc();
489             if (dcac != null) {
490                 if (DBG) log("return link properites for " + apnType);
491                 return dcac.getLinkPropertiesSync();
492             }
493         }
494         if (DBG) log("return new LinkProperties");
495         return new LinkProperties();
496     }
497
498     @Override
499     public NetworkCapabilities getNetworkCapabilities(String apnType) {
500         ApnContext apnContext = mApnContexts.get(apnType);
501         if (apnContext!=null) {
502             DcAsyncChannel dataConnectionAc = apnContext.getDcAc();
503             if (dataConnectionAc != null) {
504                 if (DBG) {
505                     log("get active pdp is not null, return NetworkCapabilities for " + apnType);
506                 }
507                 return dataConnectionAc.getNetworkCapabilitiesSync();
508             }
509         }
510         if (DBG) log("return new NetworkCapabilities");
511         return new NetworkCapabilities();
512     }
513
514     @Override
515     // Return all active apn types
516     public String[] getActiveApnTypes() {
517         if (DBG) log("get all active apn types");
518         ArrayList<String> result = new ArrayList<String>();
519
520         for (ApnContext apnContext : mApnContexts.values()) {
521             if (mAttached.get() && apnContext.isReady()) {
522                 result.add(apnContext.getApnType());
523             }
524         }
525
526         return result.toArray(new String[0]);
527     }
528
529     @Override
530     // Return active apn of specific apn type
531     public String getActiveApnString(String apnType) {
532         if (VDBG) log( "get active apn string for type:" + apnType);
533         ApnContext apnContext = mApnContexts.get(apnType);
534         if (apnContext != null) {
535             ApnSetting apnSetting = apnContext.getApnSetting();
536             if (apnSetting != null) {
537                 return apnSetting.apn;
538             }
539         }
540         return null;
541     }
542
543     @Override
544     public boolean isApnTypeEnabled(String apnType) {
545         ApnContext apnContext = mApnContexts.get(apnType);
546         if (apnContext == null) {
547             return false;
548         }
549         return apnContext.isEnabled();
550     }
551
552     @Override
553     protected void setState(DctConstants.State s) {
554         if (DBG) log("setState should not be used in GSM" + s);
555     }
556
557     // Return state of specific apn type
558     @Override
559     public DctConstants.State getState(String apnType) {
560         ApnContext apnContext = mApnContexts.get(apnType);
561         if (apnContext != null) {
562             return apnContext.getState();
563         }
564         return DctConstants.State.FAILED;
565     }
566
567     // Return if apn type is a provisioning apn.
568     @Override
569     protected boolean isProvisioningApn(String apnType) {
570         ApnContext apnContext = mApnContexts.get(apnType);
571         if (apnContext != null) {
572             return apnContext.isProvisioningApn();
573         }
574         return false;
575     }
576
577     // Return state of overall
578     @Override
579     public DctConstants.State getOverallState() {
580         boolean isConnecting = false;
581         boolean isFailed = true; // All enabled Apns should be FAILED.
582         boolean isAnyEnabled = false;
583
584         for (ApnContext apnContext : mApnContexts.values()) {
585             if (apnContext.isEnabled()) {
586                 isAnyEnabled = true;
587                 switch (apnContext.getState()) {
588                 case CONNECTED:
589                 case DISCONNECTING:
590                     if (DBG) log("overall state is CONNECTED");
591                     return DctConstants.State.CONNECTED;
592                 case RETRYING:
593                 case CONNECTING:
594                     isConnecting = true;
595                     isFailed = false;
596                     break;
597                 case IDLE:
598                 case SCANNING:
599                     isFailed = false;
600                     break;
601                 default:
602                     isAnyEnabled = true;
603                     break;
604                 }
605             }
606         }
607
608         if (!isAnyEnabled) { // Nothing enabled. return IDLE.
609             if (DBG) log( "overall state is IDLE");
610             return DctConstants.State.IDLE;
611         }
612
613         if (isConnecting) {
614             if (DBG) log( "overall state is CONNECTING");
615             return DctConstants.State.CONNECTING;
616         } else if (!isFailed) {
617             if (DBG) log( "overall state is IDLE");
618             return DctConstants.State.IDLE;
619         } else {
620             if (DBG) log( "overall state is FAILED");
621             return DctConstants.State.FAILED;
622         }
623     }
624
625     @Override
626     protected boolean isApnTypeAvailable(String type) {
627         if (type.equals(PhoneConstants.APN_TYPE_DUN) && fetchDunApn() != null) {
628             return true;
629         }
630
631         if (mAllApnSettings != null) {
632             for (ApnSetting apn : mAllApnSettings) {
633                 if (apn.canHandleType(type)) {
634                     return true;
635                 }
636             }
637         }
638         return false;
639     }
640
641     /**
642      * Report on whether data connectivity is enabled for any APN.
643      * @return {@code false} if data connectivity has been explicitly disabled,
644      * {@code true} otherwise.
645      */
646     @Override
647     public boolean getAnyDataEnabled() {
648         synchronized (mDataEnabledLock) {
649             if (!(mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled)) return false;
650             for (ApnContext apnContext : mApnContexts.values()) {
651                 // Make sure we don't have a context that is going down
652                 // and is explicitly disabled.
653                 if (isDataAllowed(apnContext)) {
654                     return true;
655                 }
656             }
657             return false;
658         }
659     }
660
661     public boolean getAnyDataEnabled(boolean checkUserDataEnabled) {
662         synchronized (mDataEnabledLock) {
663             if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled)
664                         && (!checkUserDataEnabled || sPolicyDataEnabled)))
665                 return false;
666
667             for (ApnContext apnContext : mApnContexts.values()) {
668                 // Make sure we dont have a context that going down
669                 // and is explicitly disabled.
670                 if (isDataAllowed(apnContext)) {
671                     return true;
672                 }
673             }
674             return false;
675         }
676     }
677
678     private boolean isDataAllowed(ApnContext apnContext) {
679         return apnContext.isReady() && isDataAllowed();
680     }
681
682     //****** Called from ServiceStateTracker
683     /**
684      * Invoked when ServiceStateTracker observes a transition from GPRS
685      * attach to detach.
686      */
687     protected void onDataConnectionDetached() {
688         /*
689          * We presently believe it is unnecessary to tear down the PDP context
690          * when GPRS detaches, but we should stop the network polling.
691          */
692         if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
693         stopNetStatPoll();
694         stopDataStallAlarm();
695         notifyDataConnection(Phone.REASON_DATA_DETACHED);
696         mAttached.set(false);
697     }
698
699     private void onDataConnectionAttached() {
700         if (DBG) log("onDataConnectionAttached");
701         mAttached.set(true);
702         if (getOverallState() == DctConstants.State.CONNECTED) {
703             if (DBG) log("onDataConnectionAttached: start polling notify attached");
704             startNetStatPoll();
705             startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
706             notifyDataConnection(Phone.REASON_DATA_ATTACHED);
707         } else {
708             // update APN availability so that APN can be enabled.
709             notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED);
710         }
711         mAutoAttachOnCreation = true;
712         setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
713     }
714
715     @Override
716     protected boolean isDataAllowed() {
717         final boolean internalDataEnabled;
718         synchronized (mDataEnabledLock) {
719             internalDataEnabled = mInternalDataEnabled;
720         }
721
722         boolean attachedState = mAttached.get();
723         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
724         IccRecords r = mIccRecords.get();
725         boolean recordsLoaded = (r != null) ? r.getRecordsLoaded() : false;
726
727         //FIXME always attach
728         boolean psRestricted = mIsPsRestricted;
729         int phoneNum = TelephonyManager.getDefault().getPhoneCount();
730         if (phoneNum > 1) {
731             attachedState = true;
732             psRestricted = false;
733         }
734
735         boolean allowed =
736                     (attachedState || mAutoAttachOnCreation) &&
737                     recordsLoaded &&
738                     (mPhone.getState() == PhoneConstants.State.IDLE ||
739                      mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) &&
740                     internalDataEnabled &&
741                     (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
742                     //!mIsPsRestricted &&
743                     !psRestricted &&
744                     desiredPowerState;
745         if (!allowed && DBG) {
746             String reason = "";
747             if (!(attachedState || mAutoAttachOnCreation)) {
748                 reason += " - Attached= " + attachedState;
749             }
750             if (!recordsLoaded) reason += " - SIM not loaded";
751             if (mPhone.getState() != PhoneConstants.State.IDLE &&
752                     !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
753                 reason += " - PhoneState= " + mPhone.getState();
754                 reason += " - Concurrent voice and data not allowed";
755             }
756             if (!internalDataEnabled) reason += " - mInternalDataEnabled= false";
757             if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) {
758                 reason += " - Roaming and data roaming not enabled";
759             }
760             if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
761             if (!desiredPowerState) reason += " - desiredPowerState= false";
762             if (DBG) log("isDataAllowed: not allowed due to" + reason);
763         }
764         return allowed;
765     }
766
767     private void setupDataOnConnectableApns(String reason) {
768         if (DBG) log("setupDataOnConnectableApns: " + reason);
769
770         for (ApnContext apnContext : mPrioritySortedApnContexts) {
771             if (DBG) log("setupDataOnConnectableApns: apnContext " + apnContext);
772             if (apnContext.getState() == DctConstants.State.FAILED) {
773                 apnContext.setState(DctConstants.State.IDLE);
774             }
775             if (apnContext.isConnectable()) {
776                 log("setupDataOnConnectableApns: isConnectable() call trySetupData");
777                 apnContext.setReason(reason);
778                 trySetupData(apnContext);
779             }
780         }
781     }
782
783     private boolean trySetupData(ApnContext apnContext) {
784         if (DBG) {
785             log("trySetupData for type:" + apnContext.getApnType() +
786                     " due to " + apnContext.getReason() + " apnContext=" + apnContext);
787             log("trySetupData with mIsPsRestricted=" + mIsPsRestricted);
788         }
789
790         if (mPhone.getSimulatedRadioControl() != null) {
791             // Assume data is connected on the simulator
792             // FIXME  this can be improved
793             apnContext.setState(DctConstants.State.CONNECTED);
794             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
795
796             log("trySetupData: X We're on the simulator; assuming connected retValue=true");
797             return true;
798         }
799
800         // Allow SETUP_DATA request for E-APN to be completed during emergency call
801         // and MOBILE DATA On/Off cases as well.
802         boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
803         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
804         boolean checkUserDataEnabled =
805                     !(apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS));
806
807         if (apnContext.isConnectable() && (isEmergencyApn ||
808                 (isDataAllowed(apnContext) &&
809                 getAnyDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
810             if (apnContext.getState() == DctConstants.State.FAILED) {
811                 if (DBG) log("trySetupData: make a FAILED ApnContext IDLE so its reusable");
812                 apnContext.setState(DctConstants.State.IDLE);
813             }
814             int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
815             if (apnContext.getState() == DctConstants.State.IDLE) {
816
817                 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType(),
818                         radioTech);
819                 if (waitingApns.isEmpty()) {
820                     notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
821                     notifyOffApnsOfAvailability(apnContext.getReason());
822                     if (DBG) log("trySetupData: X No APN found retValue=false");
823                     return false;
824                 } else {
825                     apnContext.setWaitingApns(waitingApns);
826                     if (DBG) {
827                         log ("trySetupData: Create from mAllApnSettings : "
828                                     + apnListToString(mAllApnSettings));
829                     }
830                 }
831             }
832
833             if (DBG) {
834                 log("trySetupData: call setupData, waitingApns : "
835                         + apnListToString(apnContext.getWaitingApns()));
836             }
837             boolean retValue = setupData(apnContext, radioTech);
838             notifyOffApnsOfAvailability(apnContext.getReason());
839
840             if (DBG) log("trySetupData: X retValue=" + retValue);
841             return retValue;
842         } else {
843             if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
844                     && apnContext.isConnectable()) {
845                 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
846             }
847             notifyOffApnsOfAvailability(apnContext.getReason());
848             if (DBG) log ("trySetupData: X apnContext not 'ready' retValue=false");
849             return false;
850         }
851     }
852
853     @Override
854     // Disabled apn's still need avail/unavail notificiations - send them out
855     protected void notifyOffApnsOfAvailability(String reason) {
856         for (ApnContext apnContext : mApnContexts.values()) {
857             if (!mAttached.get() || !apnContext.isReady()) {
858                 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
859                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
860                                             apnContext.getApnType(),
861                                             PhoneConstants.DataState.DISCONNECTED);
862             } else {
863                 if (VDBG) {
864                     log("notifyOffApnsOfAvailability skipped apn due to attached && isReady " +
865                             apnContext.toString());
866                 }
867             }
868         }
869     }
870
871     /**
872      * If tearDown is true, this only tears down a CONNECTED session. Presently,
873      * there is no mechanism for abandoning an CONNECTING session,
874      * but would likely involve cancelling pending async requests or
875      * setting a flag or new state to ignore them when they came in
876      * @param tearDown true if the underlying DataConnection should be
877      * disconnected.
878      * @param reason reason for the clean up.
879      * @return boolean - true if we did cleanup any connections, false if they
880      *                   were already all disconnected.
881      */
882     protected boolean cleanUpAllConnections(boolean tearDown, String reason) {
883         if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
884         boolean didDisconnect = false;
885         boolean specificdisable = false;
886
887         if (!TextUtils.isEmpty(reason)) {
888             specificdisable = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED);
889         }
890
891         for (ApnContext apnContext : mApnContexts.values()) {
892             if (apnContext.isDisconnected() == false) didDisconnect = true;
893             if (specificdisable) {
894                 if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)) {
895                     if (DBG) log("ApnConextType: " + apnContext.getApnType());
896                     apnContext.setReason(reason);
897                     cleanUpConnection(tearDown, apnContext);
898                 }
899             } else {
900                 // TODO - only do cleanup if not disconnected
901                 apnContext.setReason(reason);
902                 cleanUpConnection(tearDown, apnContext);
903             }
904         }
905
906         stopNetStatPoll();
907         stopDataStallAlarm();
908
909         // TODO: Do we need mRequestedApnType?
910         mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
911
912         log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount);
913         if (tearDown && mDisconnectPendingCount == 0) {
914             notifyDataDisconnectComplete();
915             notifyAllDataDisconnected();
916         }
917
918         return didDisconnect;
919     }
920
921     /**
922      * Cleanup all connections.
923      *
924      * TODO: Cleanup only a specified connection passed as a parameter.
925      *       Also, make sure when you clean up a conn, if it is last apply
926      *       logic as though it is cleanupAllConnections
927      *
928      * @param cause for the clean up.
929      */
930
931     @Override
932     protected void onCleanUpAllConnections(String cause) {
933         cleanUpAllConnections(true, cause);
934     }
935
936     protected void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
937
938         if (apnContext == null) {
939             if (DBG) log("cleanUpConnection: apn context is null");
940             return;
941         }
942
943         DcAsyncChannel dcac = apnContext.getDcAc();
944         if (DBG) {
945             log("cleanUpConnection: E tearDown=" + tearDown + " reason=" + apnContext.getReason() +
946                     " apnContext=" + apnContext);
947         }
948         if (tearDown) {
949             if (apnContext.isDisconnected()) {
950                 // The request is tearDown and but ApnContext is not connected.
951                 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC.
952                 apnContext.setState(DctConstants.State.IDLE);
953                 if (!apnContext.isReady()) {
954                     if (dcac != null) {
955                         dcac.tearDown(apnContext, "", null);
956                     }
957                     apnContext.setDataConnectionAc(null);
958                 }
959             } else {
960                 // Connection is still there. Try to clean up.
961                 if (dcac != null) {
962                     if (apnContext.getState() != DctConstants.State.DISCONNECTING) {
963                         boolean disconnectAll = false;
964                         if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) {
965                             // CAF_MSIM is this below condition required.
966                             // if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) {
967                             ApnSetting dunSetting = fetchDunApn();
968                             if (dunSetting != null &&
969                                     dunSetting.equals(apnContext.getApnSetting())) {
970                                 if (DBG) log("tearing down dedicated DUN connection");
971                                 // we need to tear it down - we brought it up just for dun and
972                                 // other people are camped on it and now dun is done.  We need
973                                 // to stop using it and let the normal apn list get used to find
974                                 // connections for the remaining desired connections
975                                 disconnectAll = true;
976                             }
977                         }
978                         if (DBG) {
979                             log("cleanUpConnection: tearing down" + (disconnectAll ? " all" :""));
980                         }
981                         Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);
982                         if (disconnectAll) {
983                             apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg);
984                         } else {
985                             apnContext.getDcAc()
986                                 .tearDown(apnContext, apnContext.getReason(), msg);
987                         }
988                         apnContext.setState(DctConstants.State.DISCONNECTING);
989                         mDisconnectPendingCount++;
990                     }
991                 } else {
992                     // apn is connected but no reference to dcac.
993                     // Should not be happen, but reset the state in case.
994                     apnContext.setState(DctConstants.State.IDLE);
995                     mPhone.notifyDataConnection(apnContext.getReason(),
996                                                 apnContext.getApnType());
997                 }
998             }
999         } else {
1000             // force clean up the data connection.
1001             if (dcac != null) dcac.reqReset();
1002             apnContext.setState(DctConstants.State.IDLE);
1003             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1004             apnContext.setDataConnectionAc(null);
1005         }
1006
1007         // Make sure reconnection alarm is cleaned up if there is no ApnContext
1008         // associated to the connection.
1009         if (dcac != null) {
1010             cancelReconnectAlarm(apnContext);
1011         }
1012         if (DBG) {
1013             log("cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason() +
1014                     " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc());
1015         }
1016     }
1017
1018     /**
1019      * Cancels the alarm associated with apnContext.
1020      *
1021      * @param apnContext on which the alarm should be stopped.
1022      */
1023     private void cancelReconnectAlarm(ApnContext apnContext) {
1024         if (apnContext == null) return;
1025
1026         PendingIntent intent = apnContext.getReconnectIntent();
1027
1028         if (intent != null) {
1029                 AlarmManager am =
1030                     (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
1031                 am.cancel(intent);
1032                 apnContext.setReconnectIntent(null);
1033         }
1034     }
1035
1036     /**
1037      * @param types comma delimited list of APN types
1038      * @return array of APN types
1039      */
1040     private String[] parseTypes(String types) {
1041         String[] result;
1042         // If unset, set to DEFAULT.
1043         if (types == null || types.equals("")) {
1044             result = new String[1];
1045             result[0] = PhoneConstants.APN_TYPE_ALL;
1046         } else {
1047             result = types.split(",");
1048         }
1049         return result;
1050     }
1051
1052    private boolean imsiMatches(String imsiDB, String imsiSIM) {
1053         // Note: imsiDB value has digit number or 'x' character for seperating USIM information
1054         // for MVNO operator. And then digit number is matched at same order and 'x' character
1055         // could replace by any digit number.
1056         // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator,
1057         //     that means first 6 digits, 8th and 9th digit
1058         //     should be set in USIM for GG Operator.
1059         int len = imsiDB.length();
1060         int idxCompare = 0;
1061
1062         if (len <= 0) return false;
1063         if (len > imsiSIM.length()) return false;
1064
1065         for (int idx=0; idx<len; idx++) {
1066             char c = imsiDB.charAt(idx);
1067             if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) {
1068                 continue;
1069             } else {
1070                 return false;
1071             }
1072         }
1073         return true;
1074     }
1075
1076     private boolean mvnoMatches(IccRecords r, String mvno_type, String mvno_match_data) {
1077         if (mvno_type.equalsIgnoreCase("spn")) {
1078             if ((r.getServiceProviderName() != null) &&
1079                     r.getServiceProviderName().equalsIgnoreCase(mvno_match_data)) {
1080                 return true;
1081             }
1082         } else if (mvno_type.equalsIgnoreCase("imsi")) {
1083             String imsiSIM = r.getIMSI();
1084             if ((imsiSIM != null) && imsiMatches(mvno_match_data, imsiSIM)) {
1085                 return true;
1086             }
1087         } else if (mvno_type.equalsIgnoreCase("gid")) {
1088             String gid1 = r.getGid1();
1089             int mvno_match_data_length = mvno_match_data.length();
1090             if ((gid1 != null) && (gid1.length() >= mvno_match_data_length) &&
1091                     gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvno_match_data)) {
1092                 return true;
1093             }
1094         }
1095         return false;
1096     }
1097
1098     private ApnSetting makeApnSetting(Cursor cursor) {
1099         String[] types = parseTypes(
1100                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
1101         ApnSetting apn = new ApnSetting(
1102                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
1103                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
1104                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
1105                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
1106                 NetworkUtils.trimV4AddrZeros(
1107                         cursor.getString(
1108                         cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
1109                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
1110                 NetworkUtils.trimV4AddrZeros(
1111                         cursor.getString(
1112                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
1113                 NetworkUtils.trimV4AddrZeros(
1114                         cursor.getString(
1115                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
1116                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
1117                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
1118                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
1119                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
1120                 types,
1121                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
1122                 cursor.getString(cursor.getColumnIndexOrThrow(
1123                         Telephony.Carriers.ROAMING_PROTOCOL)),
1124                 cursor.getInt(cursor.getColumnIndexOrThrow(
1125                         Telephony.Carriers.CARRIER_ENABLED)) == 1,
1126                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)),
1127                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
1128                 cursor.getInt(cursor.getColumnIndexOrThrow(
1129                         Telephony.Carriers.MODEM_COGNITIVE)) == 1,
1130                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
1131                 cursor.getInt(cursor.getColumnIndexOrThrow(
1132                         Telephony.Carriers.WAIT_TIME)),
1133                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS_TIME)));
1134         return apn;
1135     }
1136
1137     private ArrayList<ApnSetting> createApnList(Cursor cursor) {
1138         ArrayList<ApnSetting> result = new ArrayList<ApnSetting>();
1139         IccRecords r = mIccRecords.get();
1140
1141         if (cursor.moveToFirst()) {
1142             String mvnoType = null;
1143             String mvnoMatchData = null;
1144             do {
1145                 String cursorMvnoType = cursor.getString(
1146                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE));
1147                 String cursorMvnoMatchData = cursor.getString(
1148                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA));
1149                 if (mvnoType != null) {
1150                     if (mvnoType.equals(cursorMvnoType) &&
1151                             mvnoMatchData.equals(cursorMvnoMatchData)) {
1152                         result.add(makeApnSetting(cursor));
1153                     }
1154                 } else {
1155                     // no mvno match yet
1156                     if (mvnoMatches(r, cursorMvnoType, cursorMvnoMatchData)) {
1157                         // first match - toss out non-mvno data
1158                         result.clear();
1159                         mvnoType = cursorMvnoType;
1160                         mvnoMatchData = cursorMvnoMatchData;
1161                         result.add(makeApnSetting(cursor));
1162                     } else {
1163                         // add only non-mvno data
1164                         if (cursorMvnoType.equals("")) {
1165                             result.add(makeApnSetting(cursor));
1166                         }
1167                     }
1168                 }
1169             } while (cursor.moveToNext());
1170         }
1171         if (DBG) log("createApnList: X result=" + result);
1172         return result;
1173     }
1174
1175     private boolean dataConnectionNotInUse(DcAsyncChannel dcac) {
1176         if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac);
1177         for (ApnContext apnContext : mApnContexts.values()) {
1178             if (apnContext.getDcAc() == dcac) {
1179                 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext);
1180                 return false;
1181             }
1182         }
1183         // TODO: Fix retry handling so free DataConnections have empty apnlists.
1184         // Probably move retry handling into DataConnections and reduce complexity
1185         // of DCT.
1186         if (DBG) log("dataConnectionNotInUse: tearDownAll");
1187         dcac.tearDownAll("No connection", null);
1188         if (DBG) log("dataConnectionNotInUse: not in use return true");
1189         return true;
1190     }
1191
1192     private DcAsyncChannel findFreeDataConnection() {
1193         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
1194             if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) {
1195                 if (DBG) {
1196                     log("findFreeDataConnection: found free DataConnection=" +
1197                         " dcac=" + dcac);
1198                 }
1199                 return dcac;
1200             }
1201         }
1202         log("findFreeDataConnection: NO free DataConnection");
1203         return null;
1204     }
1205
1206     private boolean setupData(ApnContext apnContext, int radioTech) {
1207         if (DBG) log("setupData: apnContext=" + apnContext);
1208         ApnSetting apnSetting;
1209         DcAsyncChannel dcac;
1210
1211         apnSetting = apnContext.getNextWaitingApn();
1212         int profileId = apnSetting.profileId;
1213         if (profileId == 0) {
1214             profileId = getApnProfileID(apnContext.getApnType());
1215         }
1216
1217         if (apnSetting == null) {
1218             if (DBG) log("setupData: return for no apn found!");
1219             return false;
1220         }
1221
1222         dcac = checkForCompatibleConnectedApnContext(apnContext);
1223         if (dcac != null) {
1224             // Get the dcacApnSetting for the connection we want to share.
1225             ApnSetting dcacApnSetting = dcac.getApnSettingSync();
1226             if (dcacApnSetting != null) {
1227                 // Setting is good, so use it.
1228                 apnSetting = dcacApnSetting;
1229             }
1230         }
1231         if (dcac == null) {
1232             if (isOnlySingleDcAllowed(radioTech)) {
1233                 if (isHigherPriorityApnContextActive(apnContext)) {
1234                     if (DBG) {
1235                         log("setupData: Higher priority ApnContext active.  Ignoring call");
1236                     }
1237                     return false;
1238                 }
1239
1240                 // Only lower priority calls left.  Disconnect them all in this single PDP case
1241                 // so that we can bring up the requested higher priority call (once we receive
1242                 // repsonse for deactivate request for the calls we are about to disconnect
1243                 if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
1244                     // If any call actually requested to be disconnected, means we can't
1245                     // bring up this connection yet as we need to wait for those data calls
1246                     // to be disconnected.
1247                     if (DBG) log("setupData: Some calls are disconnecting first.  Wait and retry");
1248                     return false;
1249                 }
1250
1251                 // No other calls are active, so proceed
1252                 if (DBG) log("setupData: Single pdp. Continue setting up data call.");
1253             }
1254
1255             dcac = findFreeDataConnection();
1256
1257             if (dcac == null) {
1258                 dcac = createDataConnection();
1259             }
1260
1261             if (dcac == null) {
1262                 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
1263                 return false;
1264             }
1265         }
1266         if (DBG) log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting);
1267
1268         apnContext.setDataConnectionAc(dcac);
1269         apnContext.setApnSetting(apnSetting);
1270         apnContext.setState(DctConstants.State.CONNECTING);
1271         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1272
1273         Message msg = obtainMessage();
1274         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
1275         msg.obj = apnContext;
1276         dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, msg);
1277
1278         if (DBG) log("setupData: initing!");
1279         return true;
1280     }
1281
1282     /**
1283      * Handles changes to the APN database.
1284      */
1285     private void onApnChanged() {
1286         DctConstants.State overallState = getOverallState();
1287         boolean isDisconnected = (overallState == DctConstants.State.IDLE ||
1288                 overallState == DctConstants.State.FAILED);
1289
1290         if (mPhone instanceof GSMPhone) {
1291             // The "current" may no longer be valid.  MMS depends on this to send properly. TBD
1292             ((GSMPhone)mPhone).updateCurrentCarrierInProvider();
1293         }
1294
1295         // TODO: It'd be nice to only do this if the changed entrie(s)
1296         // match the current operator.
1297         if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
1298         createAllApnList();
1299         setInitialAttachApn();
1300         cleanUpAllConnections(!isDisconnected, Phone.REASON_APN_CHANGED);
1301         if (isDisconnected) {
1302             setupDataOnConnectableApns(Phone.REASON_APN_CHANGED);
1303         }
1304     }
1305
1306     /**
1307      * @param cid Connection id provided from RIL.
1308      * @return DataConnectionAc associated with specified cid.
1309      */
1310     private DcAsyncChannel findDataConnectionAcByCid(int cid) {
1311         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
1312             if (dcac.getCidSync() == cid) {
1313                 return dcac;
1314             }
1315         }
1316         return null;
1317     }
1318
1319     // TODO: For multiple Active APNs not exactly sure how to do this.
1320     @Override
1321     protected void gotoIdleAndNotifyDataConnection(String reason) {
1322         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
1323         notifyDataConnection(reason);
1324         mActiveApn = null;
1325     }
1326
1327     /**
1328      * "Active" here means ApnContext isEnabled() and not in FAILED state
1329      * @param apnContext to compare with
1330      * @return true if higher priority active apn found
1331      */
1332     private boolean isHigherPriorityApnContextActive(ApnContext apnContext) {
1333         for (ApnContext otherContext : mPrioritySortedApnContexts) {
1334             if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false;
1335             if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) {
1336                 return true;
1337             }
1338         }
1339         return false;
1340     }
1341
1342     /**
1343      * Reports if we support multiple connections or not.
1344      * This is a combination of factors, based on carrier and RAT.
1345      * @param rilRadioTech the RIL Radio Tech currently in use
1346      * @return true if only single DataConnection is allowed
1347      */
1348     private boolean isOnlySingleDcAllowed(int rilRadioTech) {
1349         int[] singleDcRats = mPhone.getContext().getResources().getIntArray(
1350                 com.android.internal.R.array.config_onlySingleDcAllowed);
1351         boolean onlySingleDcAllowed = false;
1352         if (Build.IS_DEBUGGABLE &&
1353                 SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) {
1354             onlySingleDcAllowed = true;
1355         }
1356         if (singleDcRats != null) {
1357             for (int i=0; i < singleDcRats.length && onlySingleDcAllowed == false; i++) {
1358                 if (rilRadioTech == singleDcRats[i]) onlySingleDcAllowed = true;
1359             }
1360         }
1361
1362         if (DBG) log("isOnlySingleDcAllowed(" + rilRadioTech + "): " + onlySingleDcAllowed);
1363         return onlySingleDcAllowed;
1364     }
1365
1366     @Override
1367     protected void restartRadio() {
1368         if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
1369         cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
1370         mPhone.getServiceStateTracker().powerOffRadioSafely(this);
1371         /* Note: no need to call setRadioPower(true).  Assuming the desired
1372          * radio power state is still ON (as tracked by ServiceStateTracker),
1373          * ServiceStateTracker will call setRadioPower when it receives the
1374          * RADIO_STATE_CHANGED notification for the power off.  And if the
1375          * desired power state has changed in the interim, we don't want to
1376          * override it with an unconditional power on.
1377          */
1378
1379         int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
1380         SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1));
1381     }
1382
1383     /**
1384      * Return true if data connection need to be setup after disconnected due to
1385      * reason.
1386      *
1387      * @param reason the reason why data is disconnected
1388      * @return true if try setup data connection is need for this reason
1389      */
1390     private boolean retryAfterDisconnected(ApnContext apnContext) {
1391         boolean retry = true;
1392         String reason = apnContext.getReason();
1393
1394         if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
1395                 (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())
1396                  && isHigherPriorityApnContextActive(apnContext))) {
1397             retry = false;
1398         }
1399         return retry;
1400     }
1401
1402     private void startAlarmForReconnect(int delay, ApnContext apnContext) {
1403         String apnType = apnContext.getApnType();
1404
1405         Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType);
1406         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
1407         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType);
1408
1409         // Get current sub id.
1410         long subId = SubscriptionManager.getDefaultDataSubId();
1411         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1412
1413         if (DBG) {
1414             log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction()
1415                     + " apn=" + apnContext);
1416         }
1417
1418         PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
1419                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
1420         apnContext.setReconnectIntent(alarmIntent);
1421         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1422                 SystemClock.elapsedRealtime() + delay, alarmIntent);
1423     }
1424
1425     private void startAlarmForRestartTrySetup(int delay, ApnContext apnContext) {
1426         String apnType = apnContext.getApnType();
1427         Intent intent = new Intent(INTENT_RESTART_TRYSETUP_ALARM + "." + apnType);
1428         intent.putExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE, apnType);
1429
1430         if (DBG) {
1431             log("startAlarmForRestartTrySetup: delay=" + delay + " action=" + intent.getAction()
1432                     + " apn=" + apnContext);
1433         }
1434         PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
1435                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
1436         apnContext.setReconnectIntent(alarmIntent);
1437         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1438                 SystemClock.elapsedRealtime() + delay, alarmIntent);
1439     }
1440
1441     private void notifyNoData(DcFailCause lastFailCauseCode,
1442                               ApnContext apnContext) {
1443         if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
1444         if (lastFailCauseCode.isPermanentFail()
1445             && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) {
1446             mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
1447         }
1448     }
1449
1450     private void onRecordsLoaded() {
1451         if (DBG) log("onRecordsLoaded: createAllApnList");
1452         createAllApnList();
1453         setInitialAttachApn();
1454         if (mPhone.mCi.getRadioState().isOn()) {
1455             if (DBG) log("onRecordsLoaded: notifying data availability");
1456             notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
1457         }
1458         setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
1459     }
1460
1461     @Override
1462     protected void onSetDependencyMet(String apnType, boolean met) {
1463         // don't allow users to tweak hipri to work around default dependency not met
1464         if (PhoneConstants.APN_TYPE_HIPRI.equals(apnType)) return;
1465
1466         ApnContext apnContext = mApnContexts.get(apnType);
1467         if (apnContext == null) {
1468             loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
1469                     apnType + ", " + met + ")");
1470             return;
1471         }
1472         applyNewState(apnContext, apnContext.isEnabled(), met);
1473         if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) {
1474             // tie actions on default to similar actions on HIPRI regarding dependencyMet
1475             apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_HIPRI);
1476             if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met);
1477         }
1478     }
1479
1480     private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
1481         boolean cleanup = false;
1482         boolean trySetup = false;
1483         if (DBG) {
1484             log("applyNewState(" + apnContext.getApnType() + ", " + enabled +
1485                     "(" + apnContext.isEnabled() + "), " + met + "(" +
1486                     apnContext.getDependencyMet() +"))");
1487         }
1488         if (apnContext.isReady()) {
1489             cleanup = true;
1490             if (enabled && met) {
1491                 DctConstants.State state = apnContext.getState();
1492                 switch(state) {
1493                     case CONNECTING:
1494                     case SCANNING:
1495                     case CONNECTED:
1496                     case DISCONNECTING:
1497                         // We're "READY" and active so just return
1498                         if (DBG) log("applyNewState: 'ready' so return");
1499                         return;
1500                     case IDLE:
1501                         // fall through: this is unexpected but if it happens cleanup and try setup
1502                     case FAILED:
1503                     case RETRYING: {
1504                         // We're "READY" but not active so disconnect (cleanup = true) and
1505                         // connect (trySetup = true) to be sure we retry the connection.
1506                         trySetup = true;
1507                         apnContext.setReason(Phone.REASON_DATA_ENABLED);
1508                         break;
1509                     }
1510                 }
1511             } else if (met) {
1512                 apnContext.setReason(Phone.REASON_DATA_DISABLED);
1513                 // If ConnectivityService has disabled this network, stop trying to bring
1514                 // it up, but do not tear it down - ConnectivityService will do that
1515                 // directly by talking with the DataConnection.
1516                 cleanup = false;
1517             } else {
1518                 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
1519             }
1520         } else {
1521             if (enabled && met) {
1522                 if (apnContext.isEnabled()) {
1523                     apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
1524                 } else {
1525                     apnContext.setReason(Phone.REASON_DATA_ENABLED);
1526                 }
1527                 if (apnContext.getState() == DctConstants.State.FAILED) {
1528                     apnContext.setState(DctConstants.State.IDLE);
1529                 }
1530                 trySetup = true;
1531             }
1532         }
1533         apnContext.setEnabled(enabled);
1534         apnContext.setDependencyMet(met);
1535         if (cleanup) cleanUpConnection(true, apnContext);
1536         if (trySetup) trySetupData(apnContext);
1537     }
1538
1539     private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) {
1540         String apnType = apnContext.getApnType();
1541         ApnSetting dunSetting = null;
1542
1543         if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) {
1544             dunSetting = fetchDunApn();
1545         }
1546         if (DBG) {
1547             log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext );
1548         }
1549
1550         DcAsyncChannel potentialDcac = null;
1551         ApnContext potentialApnCtx = null;
1552         for (ApnContext curApnCtx : mApnContexts.values()) {
1553             DcAsyncChannel curDcac = curApnCtx.getDcAc();
1554             log("curDcac: " + curDcac);
1555             if (curDcac != null) {
1556                 ApnSetting apnSetting = curApnCtx.getApnSetting();
1557                 log("apnSetting: " + apnSetting);
1558                 if (dunSetting != null) {
1559                     if (dunSetting.equals(apnSetting)) {
1560                         switch (curApnCtx.getState()) {
1561                             case CONNECTED:
1562                                 if (DBG) {
1563                                     log("checkForCompatibleConnectedApnContext:"
1564                                             + " found dun conn=" + curDcac
1565                                             + " curApnCtx=" + curApnCtx);
1566                                 }
1567                                 return curDcac;
1568                             case RETRYING:
1569                             case CONNECTING:
1570                                 potentialDcac = curDcac;
1571                                 potentialApnCtx = curApnCtx;
1572                             default:
1573                                 // Not connected, potential unchanged
1574                                 break;
1575                         }
1576                     }
1577                 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) {
1578                     switch (curApnCtx.getState()) {
1579                         case CONNECTED:
1580                             if (DBG) {
1581                                 log("checkForCompatibleConnectedApnContext:"
1582                                         + " found canHandle conn=" + curDcac
1583                                         + " curApnCtx=" + curApnCtx);
1584                             }
1585                             return curDcac;
1586                         case RETRYING:
1587                         case CONNECTING:
1588                             potentialDcac = curDcac;
1589                             potentialApnCtx = curApnCtx;
1590                         default:
1591                             // Not connected, potential unchanged
1592                             break;
1593                     }
1594                 }
1595             } else {
1596                 if (VDBG) {
1597                     log("checkForCompatibleConnectedApnContext: not conn curApnCtx=" + curApnCtx);
1598                 }
1599             }
1600         }
1601         if (potentialDcac != null) {
1602             if (DBG) {
1603                 log("checkForCompatibleConnectedApnContext: found potential conn=" + potentialDcac
1604                         + " curApnCtx=" + potentialApnCtx);
1605             }
1606             return potentialDcac;
1607         }
1608
1609         if (DBG) log("checkForCompatibleConnectedApnContext: NO conn apnContext=" + apnContext);
1610         return null;
1611     }
1612
1613     @Override
1614     protected void onEnableApn(int apnId, int enabled) {
1615         ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
1616         if (apnContext == null) {
1617             loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
1618             return;
1619         }
1620         // TODO change our retry manager to use the appropriate numbers for the new APN
1621         if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
1622         applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
1623     }
1624
1625     @Override
1626     // TODO: We shouldnt need this.
1627     protected boolean onTrySetupData(String reason) {
1628         if (DBG) log("onTrySetupData: reason=" + reason);
1629         setupDataOnConnectableApns(reason);
1630         return true;
1631     }
1632
1633     protected boolean onTrySetupData(ApnContext apnContext) {
1634         if (DBG) log("onTrySetupData: apnContext=" + apnContext);
1635         return trySetupData(apnContext);
1636     }
1637
1638     @Override
1639     protected void onRoamingOff() {
1640         if (DBG) log("onRoamingOff");
1641
1642         if (mUserDataEnabled == false) return;
1643
1644         if (getDataOnRoamingEnabled() == false) {
1645             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
1646             setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF);
1647         } else {
1648             notifyDataConnection(Phone.REASON_ROAMING_OFF);
1649         }
1650     }
1651
1652     @Override
1653     protected void onRoamingOn() {
1654         if (mUserDataEnabled == false) return;
1655
1656         if (getDataOnRoamingEnabled()) {
1657             if (DBG) log("onRoamingOn: setup data on roaming");
1658             setupDataOnConnectableApns(Phone.REASON_ROAMING_ON);
1659             notifyDataConnection(Phone.REASON_ROAMING_ON);
1660         } else {
1661             if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
1662             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
1663             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
1664         }
1665     }
1666
1667     @Override
1668     protected void onRadioAvailable() {
1669         if (DBG) log("onRadioAvailable");
1670         if (mPhone.getSimulatedRadioControl() != null) {
1671             // Assume data is connected on the simulator
1672             // FIXME  this can be improved
1673             // setState(DctConstants.State.CONNECTED);
1674             notifyDataConnection(null);
1675
1676             log("onRadioAvailable: We're on the simulator; assuming data is connected");
1677         }
1678
1679         IccRecords r = mIccRecords.get();
1680         if (r != null && r.getRecordsLoaded()) {
1681             notifyOffApnsOfAvailability(null);
1682         }
1683
1684         if (getOverallState() != DctConstants.State.IDLE) {
1685             cleanUpConnection(true, null);
1686         }
1687     }
1688
1689     @Override
1690     protected void onRadioOffOrNotAvailable() {
1691         // Make sure our reconnect delay starts at the initial value
1692         // next time the radio comes on
1693
1694         mReregisterOnReconnectFailure = false;
1695
1696         if (mPhone.getSimulatedRadioControl() != null) {
1697             // Assume data is connected on the simulator
1698             // FIXME  this can be improved
1699             log("We're on the simulator; assuming radio off is meaningless");
1700         } else {
1701             if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
1702             cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
1703         }
1704         notifyOffApnsOfAvailability(null);
1705     }
1706
1707     @Override
1708     protected void completeConnection(ApnContext apnContext) {
1709         boolean isProvApn = apnContext.isProvisioningApn();
1710
1711         if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext);
1712
1713         if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) {
1714             if (DBG) {
1715                 log("completeConnection: MOBILE_PROVISIONING_ACTION url="
1716                         + mProvisioningUrl);
1717             }
1718             Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
1719                     Intent.CATEGORY_APP_BROWSER);
1720             newIntent.setData(Uri.parse(mProvisioningUrl));
1721             newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
1722                     Intent.FLAG_ACTIVITY_NEW_TASK);
1723             try {
1724                 mPhone.getContext().startActivity(newIntent);
1725             } catch (ActivityNotFoundException e) {
1726                 loge("completeConnection: startActivityAsUser failed" + e);
1727             }
1728         }
1729         mIsProvisioning = false;
1730         mProvisioningUrl = null;
1731
1732         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1733         startNetStatPoll();
1734         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1735     }
1736
1737     /**
1738      * A SETUP (aka bringUp) has completed, possibly with an error. If
1739      * there is an error this method will call {@link #onDataSetupCompleteError}.
1740      */
1741     @Override
1742     protected void onDataSetupComplete(AsyncResult ar) {
1743
1744         DcFailCause cause = DcFailCause.UNKNOWN;
1745         boolean handleError = false;
1746         ApnContext apnContext = null;
1747
1748         if(ar.userObj instanceof ApnContext){
1749             apnContext = (ApnContext)ar.userObj;
1750         } else {
1751             throw new RuntimeException("onDataSetupComplete: No apnContext");
1752         }
1753
1754         if (ar.exception == null) {
1755             DcAsyncChannel dcac = apnContext.getDcAc();
1756
1757             if (RADIO_TESTS) {
1758                 // Note: To change radio.test.onDSC.null.dcac from command line you need to
1759                 // adb root and adb remount and from the command line you can only change the
1760                 // value to 1 once. To change it a second time you can reboot or execute
1761                 // adb shell stop and then adb shell start. The command line to set the value is:
1762                 // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"
1763                 ContentResolver cr = mPhone.getContext().getContentResolver();
1764                 String radioTestProperty = "radio.test.onDSC.null.dcac";
1765                 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) {
1766                     log("onDataSetupComplete: " + radioTestProperty +
1767                             " is true, set dcac to null and reset property to false");
1768                     dcac = null;
1769                     Settings.System.putInt(cr, radioTestProperty, 0);
1770                     log("onDataSetupComplete: " + radioTestProperty + "=" +
1771                             Settings.System.getInt(mPhone.getContext().getContentResolver(),
1772                                     radioTestProperty, -1));
1773                 }
1774             }
1775             if (dcac == null) {
1776                 log("onDataSetupComplete: no connection to DC, handle as error");
1777                 cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
1778                 handleError = true;
1779             } else {
1780                 ApnSetting apn = apnContext.getApnSetting();
1781                 if (DBG) {
1782                     log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn));
1783                 }
1784                 if (apn != null && apn.proxy != null && apn.proxy.length() != 0) {
1785                     try {
1786                         String port = apn.port;
1787                         if (TextUtils.isEmpty(port)) port = "8080";
1788                         ProxyInfo proxy = new ProxyInfo(apn.proxy,
1789                                 Integer.parseInt(port), null);
1790                         dcac.setLinkPropertiesHttpProxySync(proxy);
1791                     } catch (NumberFormatException e) {
1792                         loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
1793                                 apn.port + "): " + e);
1794                     }
1795                 }
1796
1797                 // everything is setup
1798                 if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {
1799                     SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true");
1800                     if (mCanSetPreferApn && mPreferredApn == null) {
1801                         if (DBG) log("onDataSetupComplete: PREFERED APN is null");
1802                         mPreferredApn = apn;
1803                         if (mPreferredApn != null) {
1804                             setPreferredApn(mPreferredApn.id);
1805                         }
1806                     }
1807                 } else {
1808                     SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
1809                 }
1810
1811                 // A connection is setup
1812                 apnContext.setState(DctConstants.State.CONNECTED);
1813                 boolean isProvApn = apnContext.isProvisioningApn();
1814                 if ((!isProvApn) || mIsProvisioning) {
1815                     // Complete the connection normally notifying the world we're connected.
1816                     // We do this if this isn't a special provisioning apn or if we've been
1817                     // told its time to provision.
1818                     completeConnection(apnContext);
1819                 } else {
1820                     // This is a provisioning APN that we're reporting as connected. Later
1821                     // when the user desires to upgrade this to a "default" connection,
1822                     // mIsProvisioning == true, we'll go through the code path above.
1823                     // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING
1824                     // is sent to the DCT.
1825                     if (DBG) {
1826                         log("onDataSetupComplete: successful, BUT send connected to prov apn as"
1827                                 + " mIsProvisioning:" + mIsProvisioning + " == false"
1828                                 + " && (isProvisioningApn:" + isProvApn + " == true");
1829                     }
1830
1831                     Intent intent = new Intent(
1832                             TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
1833                     intent.putExtra(PhoneConstants.DATA_APN_KEY, apnContext.getApnSetting().apn);
1834                     intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnContext.getApnType());
1835
1836                     String apnType = apnContext.getApnType();
1837                     LinkProperties linkProperties = getLinkProperties(apnType);
1838                     if (linkProperties != null) {
1839                         intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
1840                         String iface = linkProperties.getInterfaceName();
1841                         if (iface != null) {
1842                             intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
1843                         }
1844                     }
1845                     NetworkCapabilities networkCapabilities = getNetworkCapabilities(apnType);
1846                     if (networkCapabilities != null) {
1847                         intent.putExtra(PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY,
1848                                 networkCapabilities);
1849                     }
1850
1851                     mPhone.getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1852                 }
1853                 if (DBG) {
1854                     log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()
1855                         + ", reason:" + apnContext.getReason());
1856                 }
1857             }
1858         } else {
1859             cause = (DcFailCause) (ar.result);
1860             if (DBG) {
1861                 ApnSetting apn = apnContext.getApnSetting();
1862                 log(String.format("onDataSetupComplete: error apn=%s cause=%s",
1863                         (apn == null ? "unknown" : apn.apn), cause));
1864             }
1865             if (cause.isEventLoggable()) {
1866                 // Log this failure to the Event Logs.
1867                 int cid = getCellLocationId();
1868                 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
1869                         cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType());
1870             }
1871             ApnSetting apn = apnContext.getApnSetting();
1872             mPhone.notifyPreciseDataConnectionFailed(apnContext.getReason(),
1873                     apnContext.getApnType(), apn != null ? apn.apn : "unknown", cause.toString());
1874
1875             // Count permanent failures and remove the APN we just tried
1876             if (cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();
1877
1878             apnContext.removeWaitingApn(apnContext.getApnSetting());
1879             if (DBG) {
1880                 log(String.format("onDataSetupComplete: WaitingApns.size=%d" +
1881                         " WaitingApnsPermFailureCountDown=%d",
1882                         apnContext.getWaitingApns().size(),
1883                         apnContext.getWaitingApnsPermFailCount()));
1884             }
1885             handleError = true;
1886         }
1887
1888         if (handleError) {
1889             onDataSetupCompleteError(ar);
1890         }
1891
1892         /* If flag is set to false after SETUP_DATA_CALL is invoked, we need
1893          * to clean data connections.
1894          */
1895         if (!mInternalDataEnabled) {
1896             cleanUpAllConnections(null);
1897         }
1898
1899     }
1900
1901     /**
1902      * @return number of milli-seconds to delay between trying apns'
1903      */
1904     private int getApnDelay() {
1905         if (mFailFast) {
1906             return SystemProperties.getInt("persist.radio.apn_ff_delay",
1907                     APN_FAIL_FAST_DELAY_DEFAULT_MILLIS);
1908         } else {
1909             return SystemProperties.getInt("persist.radio.apn_delay", APN_DELAY_DEFAULT_MILLIS);
1910         }
1911     }
1912
1913     /**
1914      * Error has occurred during the SETUP {aka bringUP} request and the DCT
1915      * should either try the next waiting APN or start over from the
1916      * beginning if the list is empty. Between each SETUP request there will
1917      * be a delay defined by {@link #getApnDelay()}.
1918      */
1919     @Override
1920     protected void onDataSetupCompleteError(AsyncResult ar) {
1921         String reason = "";
1922         ApnContext apnContext = null;
1923
1924         if(ar.userObj instanceof ApnContext){
1925             apnContext = (ApnContext)ar.userObj;
1926         } else {
1927             throw new RuntimeException("onDataSetupCompleteError: No apnContext");
1928         }
1929
1930         // See if there are more APN's to try
1931         if (apnContext.getWaitingApns().isEmpty()) {
1932             apnContext.setState(DctConstants.State.FAILED);
1933             mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
1934
1935             apnContext.setDataConnectionAc(null);
1936
1937             if (apnContext.getWaitingApnsPermFailCount() == 0) {
1938                 if (DBG) {
1939                     log("onDataSetupCompleteError: All APN's had permanent failures, stop retrying");
1940                 }
1941             } else {
1942                 int delay = getApnDelay();
1943                 if (DBG) {
1944                     log("onDataSetupCompleteError: Not all APN's had permanent failures delay="
1945                             + delay);
1946                 }
1947                 startAlarmForRestartTrySetup(delay, apnContext);
1948             }
1949         } else {
1950             if (DBG) log("onDataSetupCompleteError: Try next APN");
1951             apnContext.setState(DctConstants.State.SCANNING);
1952             // Wait a bit before trying the next APN, so that
1953             // we're not tying up the RIL command channel
1954             startAlarmForReconnect(getApnDelay(), apnContext);
1955         }
1956     }
1957
1958     /**
1959      * Called when EVENT_DISCONNECT_DONE is received.
1960      */
1961     @Override
1962     protected void onDisconnectDone(int connId, AsyncResult ar) {
1963         ApnContext apnContext = null;
1964
1965         if (ar.userObj instanceof ApnContext) {
1966             apnContext = (ApnContext) ar.userObj;
1967         } else {
1968             loge("onDisconnectDone: Invalid ar in onDisconnectDone, ignore");
1969             return;
1970         }
1971
1972         if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
1973         apnContext.setState(DctConstants.State.IDLE);
1974
1975         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1976
1977         // if all data connection are gone, check whether Airplane mode request was
1978         // pending.
1979         if (isDisconnected()) {
1980             if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
1981                 if(DBG) log("onDisconnectDone: radio will be turned off, no retries");
1982                 // Radio will be turned off. No need to retry data setup
1983                 apnContext.setApnSetting(null);
1984                 apnContext.setDataConnectionAc(null);
1985
1986                 // Need to notify disconnect as well, in the case of switching Airplane mode.
1987                 // Otherwise, it would cause 30s delayed to turn on Airplane mode.
1988                 if (mDisconnectPendingCount > 0)
1989                     mDisconnectPendingCount--;
1990
1991                 if (mDisconnectPendingCount == 0) {
1992                     notifyDataDisconnectComplete();
1993                     notifyAllDataDisconnected();
1994                 }
1995                 return;
1996             }
1997         }
1998
1999         // If APN is still enabled, try to bring it back up automatically
2000         if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) {
2001             SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
2002             // Wait a bit before trying the next APN, so that
2003             // we're not tying up the RIL command channel.
2004             // This also helps in any external dependency to turn off the context.
2005             if(DBG) log("onDisconnectDone: attached, ready and retry after disconnect");
2006             startAlarmForReconnect(getApnDelay(), apnContext);
2007         } else {
2008             boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean(
2009                     com.android.internal.R.bool.config_restartRadioAfterProvisioning);
2010
2011             if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) {
2012                 log("onDisconnectDone: restartRadio after provisioning");
2013                 restartRadio();
2014             }
2015             apnContext.setApnSetting(null);
2016             apnContext.setDataConnectionAc(null);
2017             if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) {
2018                 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn");
2019                 setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION);
2020             } else {
2021                 if(DBG) log("onDisconnectDone: not retrying");
2022             }
2023         }
2024
2025         if (mDisconnectPendingCount > 0)
2026             mDisconnectPendingCount--;
2027
2028         if (mDisconnectPendingCount == 0) {
2029             notifyDataDisconnectComplete();
2030             notifyAllDataDisconnected();
2031         }
2032
2033     }
2034
2035     /**
2036      * Called when EVENT_DISCONNECT_DC_RETRYING is received.
2037      */
2038     @Override
2039     protected void onDisconnectDcRetrying(int connId, AsyncResult ar) {
2040         // We could just do this in DC!!!
2041         ApnContext apnContext = null;
2042
2043         if (ar.userObj instanceof ApnContext) {
2044             apnContext = (ApnContext) ar.userObj;
2045         } else {
2046             loge("onDisconnectDcRetrying: Invalid ar in onDisconnectDone, ignore");
2047             return;
2048         }
2049
2050         apnContext.setState(DctConstants.State.RETRYING);
2051         if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext);
2052
2053         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
2054     }
2055
2056
2057     @Override
2058     protected void onVoiceCallStarted() {
2059         if (DBG) log("onVoiceCallStarted");
2060         mInVoiceCall = true;
2061         if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
2062             if (DBG) log("onVoiceCallStarted stop polling");
2063             stopNetStatPoll();
2064             stopDataStallAlarm();
2065             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
2066         }
2067     }
2068
2069     @Override
2070     protected void onVoiceCallEnded() {
2071         if (DBG) log("onVoiceCallEnded");
2072         mInVoiceCall = false;
2073         if (isConnected()) {
2074             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
2075                 startNetStatPoll();
2076                 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
2077                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
2078             } else {
2079                 // clean slate after call end.
2080                 resetPollStats();
2081             }
2082         }
2083         // reset reconnect timer
2084         setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED);
2085     }
2086
2087     @Override
2088     protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
2089         if (DBG) log("onCleanUpConnection");
2090         ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
2091         if (apnContext != null) {
2092             apnContext.setReason(reason);
2093             cleanUpConnection(tearDown, apnContext);
2094         }
2095     }
2096
2097     @Override
2098     protected boolean isConnected() {
2099         for (ApnContext apnContext : mApnContexts.values()) {
2100             if (apnContext.getState() == DctConstants.State.CONNECTED) {
2101                 // At least one context is connected, return true
2102                 return true;
2103             }
2104         }
2105         // There are not any contexts connected, return false
2106         return false;
2107     }
2108
2109     @Override
2110     public boolean isDisconnected() {
2111         for (ApnContext apnContext : mApnContexts.values()) {
2112             if (!apnContext.isDisconnected()) {
2113                 // At least one context was not disconnected return false
2114                 return false;
2115             }
2116         }
2117         // All contexts were disconnected so return true
2118         return true;
2119     }
2120
2121     @Override
2122     protected void notifyDataConnection(String reason) {
2123         if (DBG) log("notifyDataConnection: reason=" + reason);
2124         for (ApnContext apnContext : mApnContexts.values()) {
2125             if (mAttached.get() && apnContext.isReady()) {
2126                 if (DBG) log("notifyDataConnection: type:" + apnContext.getApnType());
2127                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
2128                         apnContext.getApnType());
2129             }
2130         }
2131         notifyOffApnsOfAvailability(reason);
2132     }
2133
2134     /**
2135      * Based on the sim operator numeric, create a list for all possible
2136      * Data Connections and setup the preferredApn.
2137      */
2138     private void createAllApnList() {
2139         mAllApnSettings = new ArrayList<ApnSetting>();
2140         IccRecords r = mIccRecords.get();
2141         String operator = (r != null) ? r.getOperatorNumeric() : "";
2142         if (operator != null) {
2143             String selection = "numeric = '" + operator + "'";
2144             // query only enabled apn.
2145             // carrier_enabled : 1 means enabled apn, 0 disabled apn.
2146             // selection += " and carrier_enabled = 1";
2147             if (DBG) log("createAllApnList: selection=" + selection);
2148
2149             Cursor cursor = mPhone.getContext().getContentResolver().query(
2150                     Telephony.Carriers.CONTENT_URI, null, selection, null, null);
2151
2152             if (cursor != null) {
2153                 if (cursor.getCount() > 0) {
2154                     mAllApnSettings = createApnList(cursor);
2155                 }
2156                 cursor.close();
2157             }
2158         }
2159
2160         addEmergencyApnSetting();
2161
2162         if (mAllApnSettings.isEmpty()) {
2163             if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
2164             mPreferredApn = null;
2165             // TODO: What is the right behavior?
2166             //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
2167         } else {
2168             mPreferredApn = getPreferredApn();
2169             if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
2170                 mPreferredApn = null;
2171                 setPreferredApn(-1);
2172             }
2173             if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
2174         }
2175         if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);
2176
2177         setDataProfilesAsNeeded();
2178     }
2179
2180     /** Return the DC AsyncChannel for the new data connection */
2181     private DcAsyncChannel createDataConnection() {
2182         if (DBG) log("createDataConnection E");
2183
2184         int id = mUniqueIdGenerator.getAndIncrement();
2185         DataConnection conn = DataConnection.makeDataConnection(mPhone, id,
2186                                                 this, mDcTesterFailBringUpAll, mDcc);
2187         mDataConnections.put(id, conn);
2188         DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);
2189         int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
2190         if (status == AsyncChannel.STATUS_SUCCESSFUL) {
2191             mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac);
2192         } else {
2193             loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status);
2194         }
2195
2196         if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
2197         return dcac;
2198     }
2199
2200     private void destroyDataConnections() {
2201         if(mDataConnections != null) {
2202             if (DBG) log("destroyDataConnections: clear mDataConnectionList");
2203             mDataConnections.clear();
2204         } else {
2205             if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore");
2206         }
2207     }
2208
2209     /**
2210      * Build a list of APNs to be used to create PDP's.
2211      *
2212      * @param requestedApnType
2213      * @return waitingApns list to be used to create PDP
2214      *          error when waitingApns.isEmpty()
2215      */
2216     private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) {
2217         if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType);
2218         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
2219
2220         if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) {
2221             ApnSetting dun = fetchDunApn();
2222             if (dun != null) {
2223                 apnList.add(dun);
2224                 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
2225                 return apnList;
2226             }
2227         }
2228
2229         IccRecords r = mIccRecords.get();
2230         String operator = (r != null) ? r.getOperatorNumeric() : "";
2231
2232         // This is a workaround for a bug (7305641) where we don't failover to other
2233         // suitable APNs if our preferred APN fails.  On prepaid ATT sims we need to
2234         // failover to a provisioning APN, but once we've used their default data
2235         // connection we are locked to it for life.  This change allows ATT devices
2236         // to say they don't want to use preferred at all.
2237         boolean usePreferred = true;
2238         try {
2239             usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android.
2240                     internal.R.bool.config_dontPreferApn);
2241         } catch (Resources.NotFoundException e) {
2242             if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true");
2243             usePreferred = true;
2244         }
2245         if (DBG) {
2246             log("buildWaitingApns: usePreferred=" + usePreferred
2247                     + " canSetPreferApn=" + mCanSetPreferApn
2248                     + " mPreferredApn=" + mPreferredApn
2249                     + " operator=" + operator + " radioTech=" + radioTech
2250                     + " IccRecords r=" + r);
2251         }
2252
2253         if (usePreferred && mCanSetPreferApn && mPreferredApn != null &&
2254                 mPreferredApn.canHandleType(requestedApnType)) {
2255             if (DBG) {
2256                 log("buildWaitingApns: Preferred APN:" + operator + ":"
2257                         + mPreferredApn.numeric + ":" + mPreferredApn);
2258             }
2259             if (mPreferredApn.numeric.equals(operator)) {
2260                 if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) {
2261                     apnList.add(mPreferredApn);
2262                     if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
2263                     return apnList;
2264                 } else {
2265                     if (DBG) log("buildWaitingApns: no preferred APN");
2266                     setPreferredApn(-1);
2267                     mPreferredApn = null;
2268                 }
2269             } else {
2270                 if (DBG) log("buildWaitingApns: no preferred APN");
2271                 setPreferredApn(-1);
2272                 mPreferredApn = null;
2273             }
2274         }
2275         if (mAllApnSettings != null) {
2276             if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
2277             for (ApnSetting apn : mAllApnSettings) {
2278                 if (DBG) log("buildWaitingApns: apn=" + apn);
2279                 if (apn.canHandleType(requestedApnType)) {
2280                     if (apn.bearer == 0 || apn.bearer == radioTech) {
2281                         if (DBG) log("buildWaitingApns: adding apn=" + apn.toString());
2282                         apnList.add(apn);
2283                     } else {
2284                         if (DBG) {
2285                             log("buildWaitingApns: bearer:" + apn.bearer + " != "
2286                                     + "radioTech:" + radioTech);
2287                         }
2288                     }
2289                 } else {
2290                 if (DBG) {
2291                     log("buildWaitingApns: couldn't handle requesedApnType="
2292                             + requestedApnType);
2293                 }
2294             }
2295             }
2296         } else {
2297             loge("mAllApnSettings is empty!");
2298         }
2299         if (DBG) log("buildWaitingApns: X apnList=" + apnList);
2300         return apnList;
2301     }
2302
2303     private String apnListToString (ArrayList<ApnSetting> apns) {
2304         StringBuilder result = new StringBuilder();
2305         for (int i = 0, size = apns.size(); i < size; i++) {
2306             result.append('[')
2307                   .append(apns.get(i).toString())
2308                   .append(']');
2309         }
2310         return result.toString();
2311     }
2312
2313     private void setPreferredApn(int pos) {
2314         if (!mCanSetPreferApn) {
2315             log("setPreferredApn: X !canSEtPreferApn");
2316             return;
2317         }
2318
2319         log("setPreferredApn: delete");
2320         ContentResolver resolver = mPhone.getContext().getContentResolver();
2321         resolver.delete(PREFERAPN_NO_UPDATE_URI, null, null);
2322
2323         if (pos >= 0) {
2324             log("setPreferredApn: insert");
2325             ContentValues values = new ContentValues();
2326             values.put(APN_ID, pos);
2327             resolver.insert(PREFERAPN_NO_UPDATE_URI, values);
2328         }
2329     }
2330
2331     private ApnSetting getPreferredApn() {
2332         if (mAllApnSettings.isEmpty()) {
2333             log("getPreferredApn: X not found mAllApnSettings.isEmpty");
2334             return null;
2335         }
2336
2337         Cursor cursor = mPhone.getContext().getContentResolver().query(
2338                 PREFERAPN_NO_UPDATE_URI, new String[] { "_id", "name", "apn" },
2339                 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
2340
2341         if (cursor != null) {
2342             mCanSetPreferApn = true;
2343         } else {
2344             mCanSetPreferApn = false;
2345         }
2346         log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor
2347                 + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0));
2348
2349         if (mCanSetPreferApn && cursor.getCount() > 0) {
2350             int pos;
2351             cursor.moveToFirst();
2352             pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
2353             for(ApnSetting p : mAllApnSettings) {
2354                 log("getPreferredApn: apnSetting=" + p);
2355                 if (p.id == pos && p.canHandleType(mRequestedApnType)) {
2356                     log("getPreferredApn: X found apnSetting" + p);
2357                     cursor.close();
2358                     return p;
2359                 }
2360             }
2361         }
2362
2363         if (cursor != null) {
2364             cursor.close();
2365         }
2366
2367         log("getPreferredApn: X not found");
2368         return null;
2369     }
2370
2371     @Override
2372     public void handleMessage (Message msg) {
2373         if (DBG) log("handleMessage msg=" + msg);
2374
2375         if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
2376             loge("handleMessage: Ignore GSM msgs since GSM phone is inactive");
2377             return;
2378         }
2379
2380         if (!isActiveDataSubscription()) {
2381             loge("Ignore msgs since phone is not the current DDS");
2382             return;
2383         }
2384
2385         switch (msg.what) {
2386             case DctConstants.EVENT_RECORDS_LOADED:
2387                 onRecordsLoaded();
2388                 break;
2389
2390             case DctConstants.EVENT_DATA_CONNECTION_DETACHED:
2391                 onDataConnectionDetached();
2392                 break;
2393
2394             case DctConstants.EVENT_DATA_CONNECTION_ATTACHED:
2395                 onDataConnectionAttached();
2396                 break;
2397
2398             case DctConstants.EVENT_DO_RECOVERY:
2399                 doRecovery();
2400                 break;
2401
2402             case DctConstants.EVENT_APN_CHANGED:
2403                 onApnChanged();
2404                 break;
2405
2406             case DctConstants.EVENT_PS_RESTRICT_ENABLED:
2407                 /**
2408                  * We don't need to explicitly to tear down the PDP context
2409                  * when PS restricted is enabled. The base band will deactive
2410                  * PDP context and notify us with PDP_CONTEXT_CHANGED.
2411                  * But we should stop the network polling and prevent reset PDP.
2412                  */
2413                 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
2414                 stopNetStatPoll();
2415                 stopDataStallAlarm();
2416                 mIsPsRestricted = true;
2417                 break;
2418
2419             case DctConstants.EVENT_PS_RESTRICT_DISABLED:
2420                 /**
2421                  * When PS restrict is removed, we need setup PDP connection if
2422                  * PDP connection is down.
2423                  */
2424                 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
2425                 mIsPsRestricted  = false;
2426                 if (isConnected()) {
2427                     startNetStatPoll();
2428                     startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
2429                 } else {
2430                     // TODO: Should all PDN states be checked to fail?
2431                     if (mState == DctConstants.State.FAILED) {
2432                         cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
2433                         mReregisterOnReconnectFailure = false;
2434                     }
2435                     ApnContext apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT);
2436                     if (apnContext != null) {
2437                         apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
2438                         trySetupData(apnContext);
2439                     } else {
2440                         loge("**** Default ApnContext not found ****");
2441                         if (Build.IS_DEBUGGABLE) {
2442                             throw new RuntimeException("Default ApnContext not found");
2443                         }
2444                     }
2445                 }
2446                 break;
2447
2448             case DctConstants.EVENT_TRY_SETUP_DATA:
2449                 if (msg.obj instanceof ApnContext) {
2450                     onTrySetupData((ApnContext)msg.obj);
2451                 } else if (msg.obj instanceof String) {
2452                     onTrySetupData((String)msg.obj);
2453                 } else {
2454                     loge("EVENT_TRY_SETUP request w/o apnContext or String");
2455                 }
2456                 break;
2457
2458             case DctConstants.EVENT_CLEAN_UP_CONNECTION:
2459                 boolean tearDown = (msg.arg1 == 0) ? false : true;
2460                 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
2461                 if (msg.obj instanceof ApnContext) {
2462                     cleanUpConnection(tearDown, (ApnContext)msg.obj);
2463                 } else {
2464                     loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context, call super");
2465                     super.handleMessage(msg);
2466                 }
2467                 break;
2468             case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE:
2469                 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
2470                 onSetInternalDataEnabled(enabled, (Message) msg.obj);
2471                 break;
2472
2473             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS:
2474                 Message mCause = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null);
2475                 if ((msg.obj != null) && (msg.obj instanceof String)) {
2476                     mCause.obj = msg.obj;
2477                 }
2478                 super.handleMessage(mCause);
2479                 break;
2480
2481             case DctConstants.EVENT_DATA_RAT_CHANGED:
2482                 //May new Network allow setupData, so try it here
2483                 setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED);
2484                 break;
2485
2486             default:
2487                 // handle the message in the super class DataConnectionTracker
2488                 super.handleMessage(msg);
2489                 break;
2490         }
2491     }
2492
2493     protected int getApnProfileID(String apnType) {
2494         if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) {
2495             return RILConstants.DATA_PROFILE_IMS;
2496         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_FOTA)) {
2497             return RILConstants.DATA_PROFILE_FOTA;
2498         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_CBS)) {
2499             return RILConstants.DATA_PROFILE_CBS;
2500         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IA)) {
2501             return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now
2502         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_DUN)) {
2503             return RILConstants.DATA_PROFILE_TETHERED;
2504         } else {
2505             return RILConstants.DATA_PROFILE_DEFAULT;
2506         }
2507     }
2508
2509     private int getCellLocationId() {
2510         int cid = -1;
2511         CellLocation loc = mPhone.getCellLocation();
2512
2513         if (loc != null) {
2514             if (loc instanceof GsmCellLocation) {
2515                 cid = ((GsmCellLocation)loc).getCid();
2516             } else if (loc instanceof CdmaCellLocation) {
2517                 cid = ((CdmaCellLocation)loc).getBaseStationId();
2518             }
2519         }
2520         return cid;
2521     }
2522
2523     private IccRecords getUiccRecords(int appFamily) {
2524         return mUiccController.getIccRecords(mPhone.getPhoneId(), appFamily);
2525     }
2526
2527
2528     @Override
2529     protected void onUpdateIcc() {
2530         if (mUiccController == null ) {
2531             return;
2532         }
2533
2534         IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP);
2535
2536         IccRecords r = mIccRecords.get();
2537         if (r != newIccRecords) {
2538             if (r != null) {
2539                 log("Removing stale icc objects.");
2540                 r.unregisterForRecordsLoaded(this);
2541                 mIccRecords.set(null);
2542             }
2543             if (newIccRecords != null) {
2544                 log("New records found");
2545                 mIccRecords.set(newIccRecords);
2546                 newIccRecords.registerForRecordsLoaded(
2547                         this, DctConstants.EVENT_RECORDS_LOADED, null);
2548             }
2549         }
2550     }
2551
2552     // setAsCurrentDataConnectionTracker
2553     public void update() {
2554         log("update sub = " + mPhone.getSubId());
2555         if (isActiveDataSubscription()) {
2556             log("update(): Active DDS, register for all events now!");
2557             registerForAllEvents();
2558             onUpdateIcc();
2559
2560             mUserDataEnabled = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
2561                     Settings.Global.MOBILE_DATA, 1) == 1;
2562
2563             if (mPhone instanceof CDMALTEPhone) {
2564                 ((CDMALTEPhone)mPhone).updateCurrentCarrierInProvider();
2565                 supplyMessenger();
2566             } else if (mPhone instanceof GSMPhone) {
2567                 ((GSMPhone)mPhone).updateCurrentCarrierInProvider();
2568                 supplyMessenger();
2569             } else {
2570                 log("Phone object is not MultiSim. This should not hit!!!!");
2571             }
2572
2573         } else {
2574             unregisterForAllEvents();
2575             log("update(): NOT the active DDS, unregister for all events!");
2576         }
2577     }
2578
2579     @Override
2580     public void cleanUpAllConnections(String cause) {
2581         cleanUpAllConnections(cause, null);
2582     }
2583
2584     public void updateRecords() {
2585         if (isActiveDataSubscription()) {
2586             onUpdateIcc();
2587         }
2588     }
2589
2590     public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) {
2591         log("cleanUpAllConnections");
2592         if (disconnectAllCompleteMsg != null) {
2593             mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg);
2594         }
2595
2596         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
2597         msg.obj = cause;
2598         sendMessage(msg);
2599     }
2600
2601     protected void notifyDataDisconnectComplete() {
2602         log("notifyDataDisconnectComplete");
2603         for (Message m: mDisconnectAllCompleteMsgList) {
2604             m.sendToTarget();
2605         }
2606         mDisconnectAllCompleteMsgList.clear();
2607     }
2608
2609
2610     protected void notifyAllDataDisconnected() {
2611         sEnableFailFastRefCounter = 0;
2612         mFailFast = false;
2613         mAllDataDisconnectedRegistrants.notifyRegistrants();
2614     }
2615
2616     public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
2617         mAllDataDisconnectedRegistrants.addUnique(h, what, obj);
2618
2619         if (isDisconnected()) {
2620             log("notify All Data Disconnected");
2621             notifyAllDataDisconnected();
2622         }
2623     }
2624
2625     public void unregisterForAllDataDisconnected(Handler h) {
2626         mAllDataDisconnectedRegistrants.remove(h);
2627     }
2628
2629
2630     @Override
2631     protected void onSetInternalDataEnabled(boolean enable) {
2632         onSetInternalDataEnabled(enable, null);
2633     }
2634
2635     protected void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) {
2636         boolean sendOnComplete = true;
2637
2638         synchronized (mDataEnabledLock) {
2639             mInternalDataEnabled = enabled;
2640             if (enabled) {
2641                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
2642                 onTrySetupData(Phone.REASON_DATA_ENABLED);
2643             } else {
2644                 sendOnComplete = false;
2645                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
2646                 cleanUpAllConnections(null, onCompleteMsg);
2647             }
2648         }
2649
2650         if (sendOnComplete) {
2651             if (onCompleteMsg != null) {
2652                 onCompleteMsg.sendToTarget();
2653             }
2654         }
2655     }
2656
2657     public boolean setInternalDataEnabledFlag(boolean enable) {
2658         if (DBG)
2659             log("setInternalDataEnabledFlag(" + enable + ")");
2660
2661         if (mInternalDataEnabled != enable) {
2662             mInternalDataEnabled = enable;
2663         }
2664         return true;
2665     }
2666
2667     @Override
2668     public boolean setInternalDataEnabled(boolean enable) {
2669         return setInternalDataEnabled(enable, null);
2670     }
2671
2672     public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
2673         if (DBG)
2674             log("setInternalDataEnabled(" + enable + ")");
2675
2676         Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg);
2677         msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
2678         sendMessage(msg);
2679         return true;
2680     }
2681
2682     /** Returns true if this is current DDS. */
2683     protected boolean isActiveDataSubscription() {
2684         // FIXME This should have code like
2685         // return (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubId());
2686         return true;
2687     }
2688
2689     public void setDataAllowed(boolean enable, Message response) {
2690          mIsCleanupRequired = !enable;
2691          mPhone.mCi.setDataAllowed(enable, response);
2692          mInternalDataEnabled = enable;
2693     }
2694
2695     @Override
2696     protected void log(String s) {
2697         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
2698     }
2699
2700     @Override
2701     protected void loge(String s) {
2702         Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
2703     }
2704
2705     @Override
2706     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2707         pw.println("DataConnectionTracker extends:");
2708         super.dump(fd, pw, args);
2709         pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure);
2710         pw.println(" canSetPreferApn=" + mCanSetPreferApn);
2711         pw.println(" mApnObserver=" + mApnObserver);
2712         pw.println(" getOverallState=" + getOverallState());
2713         pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap);
2714         pw.println(" mAttached=" + mAttached.get());
2715     }
2716
2717     @Override
2718     public String[] getPcscfAddress(String apnType) {
2719         log("getPcscfAddress()");
2720         ApnContext apnContext = null;
2721
2722         if(apnType == null){
2723             log("apnType is null, return null");
2724             return null;
2725         }
2726
2727         if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_EMERGENCY)) {
2728             apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_EMERGENCY);
2729         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) {
2730             apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_IMS);
2731         } else {
2732             log("apnType is invalid, return null");
2733             return null;
2734         }
2735
2736         if (apnContext == null) {
2737             log("apnContext is null, return null");
2738             return null;
2739         }
2740
2741         DcAsyncChannel dcac = apnContext.getDcAc();
2742         String[] result = null;
2743
2744         if (dcac != null) {
2745             result = dcac.getPcscfAddr();
2746
2747             for (int i = 0; i < result.length; i++) {
2748                 log("Pcscf[" + i + "]: " + result[i]);
2749             }
2750             return result;
2751         }
2752         return null;
2753     }
2754
2755     @Override
2756     public void setImsRegistrationState(boolean registered) {
2757         log("setImsRegistrationState - mImsRegistrationState(before): "+ mImsRegistrationState
2758                 + ", registered(current) : " + registered);
2759
2760         if (mPhone == null) return;
2761
2762         ServiceStateTracker sst = mPhone.getServiceStateTracker();
2763         if (sst == null) return;
2764
2765         sst.setImsRegistrationState(registered);
2766     }
2767
2768     /**
2769      * Read APN configuration from Telephony.db for Emergency APN
2770      * All opertors recognize the connection request for EPDN based on APN type
2771      * PLMN name,APN name are not mandatory parameters
2772      */
2773     private void initEmergencyApnSetting() {
2774         // Operator Numeric is not available when sim records are not loaded.
2775         // Query Telephony.db with APN type as EPDN request does not
2776         // require APN name, plmn and all operators support same APN config.
2777         // DB will contain only one entry for Emergency APN
2778         String selection = "type=\"emergency\"";
2779         Cursor cursor = mPhone.getContext().getContentResolver().query(
2780                 Telephony.Carriers.CONTENT_URI, null, selection, null, null);
2781
2782         if (cursor != null) {
2783             if (cursor.getCount() > 0) {
2784                 if (cursor.moveToFirst()) {
2785                     mEmergencyApn = makeApnSetting(cursor);
2786                 }
2787             }
2788             cursor.close();
2789         }
2790     }
2791
2792     /**
2793      * Add the Emergency APN settings to APN settings list
2794      */
2795     private void addEmergencyApnSetting() {
2796         if(mEmergencyApn != null) {
2797             if(mAllApnSettings == null) {
2798                 mAllApnSettings = new ArrayList<ApnSetting>();
2799             } else {
2800                 boolean hasEmergencyApn = false;
2801                 for (ApnSetting apn : mAllApnSettings) {
2802                     if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_EMERGENCY)) {
2803                         hasEmergencyApn = true;
2804                         break;
2805                     }
2806                 }
2807
2808                 if(hasEmergencyApn == false) {
2809                     mAllApnSettings.add(mEmergencyApn);
2810                 } else {
2811                     log("addEmergencyApnSetting - E-APN setting is already present");
2812                 }
2813             }
2814         }
2815     }
2816 }