Advertisement
Jack2

SIMRecords.java

Oct 23rd, 2013
665
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 63.41 KB | None | 0 0
  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.uicc;
  18.  
  19. import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
  20. import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
  21. import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
  22. import android.content.Context;
  23. import android.os.AsyncResult;
  24. import android.os.Message;
  25. import android.os.SystemProperties;
  26. import android.text.TextUtils;
  27. import android.telephony.Rlog;
  28.  
  29. import com.android.internal.telephony.CommandsInterface;
  30. import com.android.internal.telephony.MccTable;
  31. import com.android.internal.telephony.SmsMessageBase;
  32. import com.android.internal.telephony.gsm.SimTlv;
  33. import com.android.internal.telephony.gsm.SmsMessage;
  34.  
  35. import java.io.FileDescriptor;
  36. import java.io.PrintWriter;
  37. import java.util.ArrayList;
  38. import java.util.Arrays;
  39.  
  40.  
  41. /**
  42.  * {@hide}
  43.  */
  44. public class SIMRecords extends IccRecords {
  45.     protected static final String LOG_TAG = "SIMRecords";
  46.  
  47.     private static final boolean CRASH_RIL = false;
  48.  
  49.     // ***** Instance Variables
  50.  
  51.     VoiceMailConstants mVmConfig;
  52.  
  53.  
  54.     SpnOverride mSpnOverride;
  55.  
  56.     // ***** Cached SIM State; cleared on channel close
  57.  
  58.     private boolean mCallForwardingEnabled;
  59.  
  60.  
  61.     /**
  62.      * States only used by getSpnFsm FSM
  63.      */
  64.     private GetSpnFsmState mSpnState;
  65.  
  66.     /** CPHS service information (See CPHS 4.2 B.3.1.1)
  67.      *  It will be set in onSimReady if reading GET_CPHS_INFO successfully
  68.      *  mCphsInfo[0] is CPHS Phase
  69.      *  mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table
  70.      */
  71.     private byte[] mCphsInfo = null;
  72.     boolean mCspPlmnEnabled = true;
  73.  
  74.     byte[] mEfMWIS = null;
  75.     byte[] mEfCPHS_MWI =null;
  76.     byte[] mEfCff = null;
  77.     byte[] mEfCfis = null;
  78.  
  79.  
  80.     int mSpnDisplayCondition;
  81.     // Numeric network codes listed in TS 51.011 EF[SPDI]
  82.     ArrayList<String> mSpdiNetworks = null;
  83.  
  84.     String mPnnHomeName = null;
  85.  
  86.     UsimServiceTable mUsimServiceTable;
  87.  
  88.     @Override
  89.     public String toString() {
  90.         return "SimRecords: " + super.toString()
  91.                 + " mVmConfig" + mVmConfig
  92.                 + " mSpnOverride=" + "mSpnOverride"
  93.                 + " callForwardingEnabled=" + mCallForwardingEnabled
  94.                 + " spnState=" + mSpnState
  95.                 + " mCphsInfo=" + mCphsInfo
  96.                 + " mCspPlmnEnabled=" + mCspPlmnEnabled
  97.                 + " efMWIS=" + mEfMWIS
  98.                 + " efCPHS_MWI=" + mEfCPHS_MWI
  99.                 + " mEfCff=" + mEfCff
  100.                 + " mEfCfis=" + mEfCfis
  101.                 + " getOperatorNumeric=" + getOperatorNumeric();
  102.     }
  103.  
  104.     // ***** Constants
  105.  
  106.     // From TS 51.011 EF[SPDI] section
  107.     static final int TAG_SPDI = 0xA3;
  108.     static final int TAG_SPDI_PLMN_LIST = 0x80;
  109.  
  110.     // Full Name IEI from TS 24.008
  111.     static final int TAG_FULL_NETWORK_NAME = 0x43;
  112.  
  113.     // Short Name IEI from TS 24.008
  114.     static final int TAG_SHORT_NETWORK_NAME = 0x45;
  115.  
  116.     // active CFF from CPHS 4.2 B.4.5
  117.     static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a;
  118.     static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05;
  119.     static final int CFF_LINE1_MASK = 0x0f;
  120.     static final int CFF_LINE1_RESET = 0xf0;
  121.  
  122.     // CPHS Service Table (See CPHS 4.2 B.3.1)
  123.     private static final int CPHS_SST_MBN_MASK = 0x30;
  124.     private static final int CPHS_SST_MBN_ENABLED = 0x30;
  125.  
  126.     // ***** Event Constants
  127.     private static final int EVENT_GET_IMSI_DONE = 3;
  128.     private static final int EVENT_GET_ICCID_DONE = 4;
  129.     private static final int EVENT_GET_MBI_DONE = 5;
  130.     private static final int EVENT_GET_MBDN_DONE = 6;
  131.     private static final int EVENT_GET_MWIS_DONE = 7;
  132.     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
  133.     protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
  134.     protected static final int EVENT_GET_MSISDN_DONE = 10;
  135.     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
  136.     private static final int EVENT_GET_SPN_DONE = 12;
  137.     private static final int EVENT_GET_SPDI_DONE = 13;
  138.     private static final int EVENT_UPDATE_DONE = 14;
  139.     private static final int EVENT_GET_PNN_DONE = 15;
  140.     protected static final int EVENT_GET_SST_DONE = 17;
  141.     private static final int EVENT_GET_ALL_SMS_DONE = 18;
  142.     private static final int EVENT_MARK_SMS_READ_DONE = 19;
  143.     private static final int EVENT_SET_MBDN_DONE = 20;
  144.     private static final int EVENT_SMS_ON_SIM = 21;
  145.     private static final int EVENT_GET_SMS_DONE = 22;
  146.     private static final int EVENT_GET_CFF_DONE = 24;
  147.     private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25;
  148.     private static final int EVENT_GET_INFO_CPHS_DONE = 26;
  149.     // private static final int EVENT_SET_MSISDN_DONE = 30; Defined in IccRecords as 30
  150.     private static final int EVENT_SIM_REFRESH = 31;
  151.     private static final int EVENT_GET_CFIS_DONE = 32;
  152.     private static final int EVENT_GET_CSP_CPHS_DONE = 33;
  153.     private static final int EVENT_GET_GID1_DONE = 34;
  154.  
  155.     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
  156.  
  157.     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
  158.         "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
  159.         "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
  160.         "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
  161.         "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
  162.         "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
  163.         "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
  164.         "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
  165.         "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
  166.         "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
  167.         "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
  168.         "405849", "405850", "405851", "405852", "405853", "405875", "405876", "405877",
  169.         "405878", "405879", "405880", "405881", "405882", "405883", "405884", "405885",
  170.         "405886", "405908", "405909", "405910", "405911", "405912", "405913", "405914",
  171.         "405915", "405916", "405917", "405918", "405919", "405920", "405921", "405922",
  172.         "405923", "405924", "405925", "405926", "405927", "405928", "405929", "405930",
  173.         "405931", "405932"
  174.     };
  175.  
  176.     // ***** Constructor
  177.  
  178.     public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
  179.         super(app, c, ci);
  180.  
  181.         mAdnCache = new AdnRecordCache(mFh);
  182.  
  183.         mVmConfig = new VoiceMailConstants();
  184.         mSpnOverride = new SpnOverride();
  185.  
  186.         mRecordsRequested = false;  // No load request is made till SIM ready
  187.  
  188.         // recordsToLoad is set to 0 because no requests are made yet
  189.         mRecordsToLoad = 0;
  190.  
  191.         mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
  192.         mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
  193.  
  194.         // Start off by setting empty state
  195.         resetRecords();
  196.         mParentApp.registerForReady(this, EVENT_APP_READY, null);
  197.         if (DBG) log("SIMRecords X ctor this=" + this);
  198.     }
  199.  
  200.     @Override
  201.     public void dispose() {
  202.         if (DBG) log("Disposing SIMRecords this=" + this);
  203.         //Unregister for all events
  204.         mCi.unregisterForIccRefresh(this);
  205.         mCi.unSetOnSmsOnSim(this);
  206.         mParentApp.unregisterForReady(this);
  207.         resetRecords();
  208.         super.dispose();
  209.     }
  210.  
  211.     @Override
  212.     protected void finalize() {
  213.         if(DBG) log("finalized");
  214.     }
  215.  
  216.     protected void resetRecords() {
  217.         mImsi = null;
  218.         mMsisdn = null;
  219.         mVoiceMailNum = null;
  220.         mCountVoiceMessages = 0;
  221.         mMncLength = UNINITIALIZED;
  222.         mIccId = null;
  223.         // -1 means no EF_SPN found; treat accordingly.
  224.         mSpnDisplayCondition = -1;
  225.         mEfMWIS = null;
  226.         mEfCPHS_MWI = null;
  227.         mSpdiNetworks = null;
  228.         mPnnHomeName = null;
  229.         mGid1 = null;
  230.  
  231.         mAdnCache.reset();
  232.  
  233.         log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null");
  234.         SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, null);
  235.         SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, null);
  236.         SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
  237.  
  238.         // recordsRequested is set to false indicating that the SIM
  239.         // read requests made so far are not valid. This is set to
  240.         // true only when fresh set of read requests are made.
  241.         mRecordsRequested = false;
  242.     }
  243.  
  244.  
  245.     //***** Public Methods
  246.  
  247.     /**
  248.      * {@inheritDoc}
  249.      */
  250.     @Override
  251.     public String getIMSI() {
  252.         return mImsi;
  253.     }
  254.  
  255.     @Override
  256.     public String getMsisdnNumber() {
  257.         return mMsisdn;
  258.     }
  259.  
  260.     @Override
  261.     public String getGid1() {
  262.         return mGid1;
  263.     }
  264.  
  265.     @Override
  266.     public UsimServiceTable getUsimServiceTable() {
  267.         return mUsimServiceTable;
  268.     }
  269.  
  270.     /**
  271.      * Set subscriber number to SIM record
  272.      *
  273.      * The subscriber number is stored in EF_MSISDN (TS 51.011)
  274.      *
  275.      * When the operation is complete, onComplete will be sent to its handler
  276.      *
  277.      * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
  278.      * @param number dailing nubmer (up to 20 digits)
  279.      *        if the number starts with '+', then set to international TOA
  280.      * @param onComplete
  281.      *        onComplete.obj will be an AsyncResult
  282.      *        ((AsyncResult)onComplete.obj).exception == null on success
  283.      *        ((AsyncResult)onComplete.obj).exception != null on fail
  284.      */
  285.     @Override
  286.     public void setMsisdnNumber(String alphaTag, String number,
  287.             Message onComplete) {
  288.  
  289.         mMsisdn = number;
  290.         mMsisdnTag = alphaTag;
  291.  
  292.         if(DBG) log("Set MSISDN: " + mMsisdnTag + " " + /*mMsisdn*/ "xxxxxxx");
  293.  
  294.  
  295.         AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn);
  296.  
  297.         new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
  298.                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
  299.     }
  300.  
  301.     @Override
  302.     public String getMsisdnAlphaTag() {
  303.         return mMsisdnTag;
  304.     }
  305.  
  306.     @Override
  307.     public String getVoiceMailNumber() {
  308.         return mVoiceMailNum;
  309.     }
  310.  
  311.     /**
  312.      * Set voice mail number to SIM record
  313.      *
  314.      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
  315.      * EF_MAILBOX_CPHS (CPHS 4.2)
  316.      *
  317.      * If EF_MBDN is available, store the voice mail number to EF_MBDN
  318.      *
  319.      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
  320.      *
  321.      * So the voice mail number will be stored in both EFs if both are available
  322.      *
  323.      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
  324.      *
  325.      * When the operation is complete, onComplete will be sent to its handler
  326.      *
  327.      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
  328.      * @param voiceNumber dailing nubmer (upto 20 digits)
  329.      *        if the number is start with '+', then set to international TOA
  330.      * @param onComplete
  331.      *        onComplete.obj will be an AsyncResult
  332.      *        ((AsyncResult)onComplete.obj).exception == null on success
  333.      *        ((AsyncResult)onComplete.obj).exception != null on fail
  334.      */
  335.     @Override
  336.     public void setVoiceMailNumber(String alphaTag, String voiceNumber,
  337.             Message onComplete) {
  338.         if (mIsVoiceMailFixed) {
  339.             AsyncResult.forMessage((onComplete)).exception =
  340.                     new IccVmFixedException("Voicemail number is fixed by operator");
  341.             onComplete.sendToTarget();
  342.             return;
  343.         }
  344.  
  345.         mNewVoiceMailNum = voiceNumber;
  346.         mNewVoiceMailTag = alphaTag;
  347.  
  348.         AdnRecord adn = new AdnRecord(mNewVoiceMailTag, mNewVoiceMailNum);
  349.  
  350.         if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
  351.  
  352.             new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6,
  353.                     mMailboxIndex, null,
  354.                     obtainMessage(EVENT_SET_MBDN_DONE, onComplete));
  355.  
  356.         } else if (isCphsMailboxEnabled()) {
  357.  
  358.             new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS,
  359.                     EF_EXT1, 1, null,
  360.                     obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete));
  361.  
  362.         } else {
  363.             AsyncResult.forMessage((onComplete)).exception =
  364.                     new IccVmNotSupportedException("Update SIM voice mailbox error");
  365.             onComplete.sendToTarget();
  366.         }
  367.     }
  368.  
  369.     @Override
  370.     public String getVoiceMailAlphaTag()
  371.     {
  372.         return mVoiceMailTag;
  373.     }
  374.  
  375.     /**
  376.      * Sets the SIM voice message waiting indicator records
  377.      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
  378.      * @param countWaiting The number of messages waiting, if known. Use
  379.      *                     -1 to indicate that an unknown number of
  380.      *                      messages are waiting
  381.      */
  382.     @Override
  383.     public void
  384.     setVoiceMessageWaiting(int line, int countWaiting) {
  385.         if (line != 1) {
  386.             // only profile 1 is supported
  387.             return;
  388.         }
  389.  
  390.         // range check
  391.         if (countWaiting < 0) {
  392.             countWaiting = -1;
  393.         } else if (countWaiting > 0xff) {
  394.             // TS 23.040 9.2.3.24.2
  395.             // "The value 255 shall be taken to mean 255 or greater"
  396.             countWaiting = 0xff;
  397.         }
  398.  
  399.         mCountVoiceMessages = countWaiting;
  400.  
  401.         mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
  402.  
  403.         try {
  404.             if (mEfMWIS != null) {
  405.                 // TS 51.011 10.3.45
  406.  
  407.                 // lsb of byte 0 is 'voicemail' status
  408.                 mEfMWIS[0] = (byte)((mEfMWIS[0] & 0xfe)
  409.                                     | (mCountVoiceMessages == 0 ? 0 : 1));
  410.  
  411.                 // byte 1 is the number of voice messages waiting
  412.                 if (countWaiting < 0) {
  413.                     // The spec does not define what this should be
  414.                     // if we don't know the count
  415.                     mEfMWIS[1] = 0;
  416.                 } else {
  417.                     mEfMWIS[1] = (byte) countWaiting;
  418.                 }
  419.  
  420.                 mFh.updateEFLinearFixed(
  421.                     EF_MWIS, 1, mEfMWIS, null,
  422.                     obtainMessage (EVENT_UPDATE_DONE, EF_MWIS));
  423.             }
  424.  
  425.             if (mEfCPHS_MWI != null) {
  426.                     // Refer CPHS4_2.WW6 B4.2.3
  427.                 mEfCPHS_MWI[0] = (byte)((mEfCPHS_MWI[0] & 0xf0)
  428.                             | (mCountVoiceMessages == 0 ? 0x5 : 0xa));
  429.  
  430.                 mFh.updateEFTransparent(
  431.                     EF_VOICE_MAIL_INDICATOR_CPHS, mEfCPHS_MWI,
  432.                     obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
  433.             }
  434.         } catch (ArrayIndexOutOfBoundsException ex) {
  435.             logw("Error saving voice mail state to SIM. Probably malformed SIM record", ex);
  436.         }
  437.     }
  438.  
  439.     // Validate data is !null and the MSP (Multiple Subscriber Profile)
  440.     // byte is between 1 and 4. See ETSI TS 131 102 v11.3.0 section 4.2.64.
  441.     private boolean validEfCfis(byte[] data) {
  442.         return ((data != null) && (data[0] >= 1) && (data[0] <= 4));
  443.     }
  444.  
  445.     /**
  446.      * {@inheritDoc}
  447.      */
  448.     @Override
  449.     public boolean getVoiceCallForwardingFlag() {
  450.         return mCallForwardingEnabled;
  451.     }
  452.  
  453.     /**
  454.      * {@inheritDoc}
  455.      */
  456.     @Override
  457.     public void setVoiceCallForwardingFlag(int line, boolean enable) {
  458.  
  459.         if (line != 1) return; // only line 1 is supported
  460.  
  461.         mCallForwardingEnabled = enable;
  462.  
  463.         mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
  464.  
  465.         try {
  466.             if (validEfCfis(mEfCfis)) {
  467.                 // lsb is of byte 1 is voice status
  468.                 if (enable) {
  469.                     mEfCfis[1] |= 1;
  470.                 } else {
  471.                     mEfCfis[1] &= 0xfe;
  472.                 }
  473.  
  474.                 log("setVoiceCallForwardingFlag: enable=" + enable
  475.                         + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
  476.  
  477.                 // TODO: Should really update other fields in EF_CFIS, eg,
  478.                 // dialing number.  We don't read or use it right now.
  479.  
  480.                 mFh.updateEFLinearFixed(
  481.                         EF_CFIS, 1, mEfCfis, null,
  482.                         obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
  483.             } else {
  484.                 log("setVoiceCallForwardingFlag: ignoring enable=" + enable
  485.                         + " invalid mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
  486.             }
  487.  
  488.             if (mEfCff != null) {
  489.                 if (enable) {
  490.                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
  491.                             | CFF_UNCONDITIONAL_ACTIVE);
  492.                 } else {
  493.                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
  494.                             | CFF_UNCONDITIONAL_DEACTIVE);
  495.                 }
  496.  
  497.                 mFh.updateEFTransparent(
  498.                         EF_CFF_CPHS, mEfCff,
  499.                         obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
  500.             }
  501.         } catch (ArrayIndexOutOfBoundsException ex) {
  502.             logw("Error saving call forwarding flag to SIM. "
  503.                             + "Probably malformed SIM record", ex);
  504.  
  505.         }
  506.     }
  507.  
  508.     /**
  509.      * Called by STK Service when REFRESH is received.
  510.      * @param fileChanged indicates whether any files changed
  511.      * @param fileList if non-null, a list of EF files that changed
  512.      */
  513.     @Override
  514.     public void onRefresh(boolean fileChanged, int[] fileList) {
  515.         if (fileChanged) {
  516.             // A future optimization would be to inspect fileList and
  517.             // only reload those files that we care about.  For now,
  518.             // just re-fetch all SIM records that we cache.
  519.             fetchSimRecords();
  520.         }
  521.     }
  522.  
  523.     /**
  524.      * {@inheritDoc}
  525.      */
  526.     @Override
  527.     public String getOperatorNumeric() {
  528.         if (mImsi == null) {
  529.             log("getOperatorNumeric: IMSI == null");
  530.             return null;
  531.         }
  532.         if (mMncLength == UNINITIALIZED || mMncLength == UNKNOWN) {
  533.             log("getSIMOperatorNumeric: bad mncLength");
  534.             return null;
  535.         }
  536.  
  537.         // Length = length of MCC + length of MNC
  538.         // length of mcc = 3 (TS 23.003 Section 2.2)
  539.         return mImsi.substring(0, 3 + mMncLength);
  540.     }
  541.  
  542.     // ***** Overridden from Handler
  543.     @Override
  544.     public void handleMessage(Message msg) {
  545.         AsyncResult ar;
  546.         AdnRecord adn;
  547.  
  548.         byte data[];
  549.  
  550.         boolean isRecordLoadResponse = false;
  551.  
  552.         if (mDestroyed.get()) {
  553.             loge("Received message " + msg + "[" + msg.what + "] " +
  554.                     " while being destroyed. Ignoring.");
  555.             return;
  556.         }
  557.  
  558.         try { switch (msg.what) {
  559.             case EVENT_APP_READY:
  560.                 onReady();
  561.                 break;
  562.  
  563.             /* IO events */
  564.             case EVENT_GET_IMSI_DONE:
  565.                 isRecordLoadResponse = true;
  566.  
  567.                 ar = (AsyncResult)msg.obj;
  568.  
  569.                 if (ar.exception != null) {
  570.                     loge("Exception querying IMSI, Exception:" + ar.exception);
  571.                     break;
  572.                 }
  573.  
  574.                 mImsi = (String) ar.result;
  575.  
  576.                 // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
  577.                 // than 15 (and usually 15).
  578.                 if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
  579.                     loge("invalid IMSI " + mImsi);
  580.                     mImsi = null;
  581.                 }
  582.  
  583.                 log("IMSI: " + /* imsi.substring(0, 6) +*/ "xxxxxxx");
  584.  
  585.                 if (((mMncLength == UNKNOWN) || (mMncLength == 2)) &&
  586.                         ((mImsi != null) && (mImsi.length() >= 6))) {
  587.                     String mccmncCode = mImsi.substring(0, 6);
  588.                     for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
  589.                         if (mccmnc.equals(mccmncCode)) {
  590.                             mMncLength = 3;
  591.                             break;
  592.                         }
  593.                     }
  594.                 }
  595.  
  596.                 if (mMncLength == UNKNOWN) {
  597.                     // the SIM has told us all it knows, but it didn't know the mnc length.
  598.                     // guess using the mcc
  599.                     try {
  600.                         int mcc = Integer.parseInt(mImsi.substring(0,3));
  601.                         mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
  602.                     } catch (NumberFormatException e) {
  603.                         mMncLength = UNKNOWN;
  604.                         loge("Corrupt IMSI!");
  605.                     }
  606.                 }
  607.  
  608.                 if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED) {
  609.                     // finally have both the imsi and the mncLength and can parse the imsi properly
  610.                     MccTable.updateMccMncConfiguration(mContext, mImsi.substring(0, 3 + mMncLength));
  611.                 }
  612.                 mImsiReadyRegistrants.notifyRegistrants();
  613.             break;
  614.  
  615.             case EVENT_GET_MBI_DONE:
  616.                 boolean isValidMbdn;
  617.                 isRecordLoadResponse = true;
  618.  
  619.                 ar = (AsyncResult)msg.obj;
  620.                 data = (byte[]) ar.result;
  621.  
  622.                 isValidMbdn = false;
  623.                 if (ar.exception == null) {
  624.                     // Refer TS 51.011 Section 10.3.44 for content details
  625.                     log("EF_MBI: " + IccUtils.bytesToHexString(data));
  626.  
  627.                     // Voice mail record number stored first
  628.                     mMailboxIndex = data[0] & 0xff;
  629.  
  630.                     // check if dailing numbe id valid
  631.                     if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
  632.                         log("Got valid mailbox number for MBDN");
  633.                         isValidMbdn = true;
  634.                     }
  635.                 }
  636.  
  637.                 // one more record to load
  638.                 mRecordsToLoad += 1;
  639.  
  640.                 if (isValidMbdn) {
  641.                     // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
  642.                     new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
  643.                             mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
  644.                 } else {
  645.                     // If this EF not present, try mailbox as in CPHS standard
  646.                     // CPHS (CPHS4_2.WW6) is a european standard.
  647.                     new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
  648.                             EF_EXT1, 1,
  649.                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
  650.                 }
  651.  
  652.                 break;
  653.             case EVENT_GET_CPHS_MAILBOX_DONE:
  654.             case EVENT_GET_MBDN_DONE:
  655.                 //Resetting the voice mail number and voice mail tag to null
  656.                 //as these should be updated from the data read from EF_MBDN.
  657.                 //If they are not reset, incase of invalid data/exception these
  658.                 //variables are retaining their previous values and are
  659.                 //causing invalid voice mailbox info display to user.
  660.                 mVoiceMailNum = null;
  661.                 mVoiceMailTag = null;
  662.                 isRecordLoadResponse = true;
  663.  
  664.                 ar = (AsyncResult)msg.obj;
  665.  
  666.                 if (ar.exception != null) {
  667.  
  668.                     log("Invalid or missing EF"
  669.                         + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]"));
  670.  
  671.                     // Bug #645770 fall back to CPHS
  672.                     // FIXME should use SST to decide
  673.  
  674.                     if (msg.what == EVENT_GET_MBDN_DONE) {
  675.                         //load CPHS on fail...
  676.                         // FIXME right now, only load line1's CPHS voice mail entry
  677.  
  678.                         mRecordsToLoad += 1;
  679.                         new AdnRecordLoader(mFh).loadFromEF(
  680.                                 EF_MAILBOX_CPHS, EF_EXT1, 1,
  681.                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
  682.                     }
  683.                     break;
  684.                 }
  685.  
  686.                 adn = (AdnRecord)ar.result;
  687.  
  688.                 log("VM: " + adn +
  689.                         ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
  690.  
  691.                 if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
  692.                     // Bug #645770 fall back to CPHS
  693.                     // FIXME should use SST to decide
  694.                     // FIXME right now, only load line1's CPHS voice mail entry
  695.                     mRecordsToLoad += 1;
  696.                     new AdnRecordLoader(mFh).loadFromEF(
  697.                             EF_MAILBOX_CPHS, EF_EXT1, 1,
  698.                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
  699.  
  700.                     break;
  701.                 }
  702.  
  703.                 mVoiceMailNum = adn.getNumber();
  704.                 mVoiceMailTag = adn.getAlphaTag();
  705.             break;
  706.  
  707.             case EVENT_GET_MSISDN_DONE:
  708.                 isRecordLoadResponse = true;
  709.  
  710.                 ar = (AsyncResult)msg.obj;
  711.  
  712.                 if (ar.exception != null) {
  713.                     log("Invalid or missing EF[MSISDN]");
  714.                     break;
  715.                 }
  716.  
  717.                 adn = (AdnRecord)ar.result;
  718.  
  719.                 mMsisdn = adn.getNumber();
  720.                 mMsisdnTag = adn.getAlphaTag();
  721.  
  722.                 log("MSISDN: " + /*mMsisdn*/ "xxxxxxx");
  723.             break;
  724.  
  725.             case EVENT_SET_MSISDN_DONE:
  726.                 isRecordLoadResponse = false;
  727.                 ar = (AsyncResult)msg.obj;
  728.  
  729.                 if (ar.userObj != null) {
  730.                     AsyncResult.forMessage(((Message) ar.userObj)).exception
  731.                             = ar.exception;
  732.                     ((Message) ar.userObj).sendToTarget();
  733.                 }
  734.                 break;
  735.  
  736.             case EVENT_GET_MWIS_DONE:
  737.                 isRecordLoadResponse = true;
  738.  
  739.                 ar = (AsyncResult)msg.obj;
  740.                 data = (byte[])ar.result;
  741.  
  742.                 if (ar.exception != null) {
  743.                     break;
  744.                 }
  745.  
  746.                 log("EF_MWIS: " + IccUtils.bytesToHexString(data));
  747.  
  748.                 mEfMWIS = data;
  749.  
  750.                 if ((data[0] & 0xff) == 0xff) {
  751.                     log("Uninitialized record MWIS");
  752.                     break;
  753.                 }
  754.  
  755.                 // Refer TS 51.011 Section 10.3.45 for the content description
  756.                 boolean voiceMailWaiting = ((data[0] & 0x01) != 0);
  757.                 mCountVoiceMessages = data[1] & 0xff;
  758.  
  759.                 if (voiceMailWaiting && mCountVoiceMessages == 0) {
  760.                     // Unknown count = -1
  761.                     mCountVoiceMessages = -1;
  762.                 }
  763.  
  764.                 mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
  765.             break;
  766.  
  767.             case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
  768.                 isRecordLoadResponse = true;
  769.  
  770.                 ar = (AsyncResult)msg.obj;
  771.                 data = (byte[])ar.result;
  772.  
  773.                 if (ar.exception != null) {
  774.                     break;
  775.                 }
  776.  
  777.                 mEfCPHS_MWI = data;
  778.  
  779.                 // Use this data if the EF[MWIS] exists and
  780.                 // has been loaded
  781.  
  782.                 if (mEfMWIS == null) {
  783.                     int indicator = data[0] & 0xf;
  784.  
  785.                     // Refer CPHS4_2.WW6 B4.2.3
  786.                     if (indicator == 0xA) {
  787.                         // Unknown count = -1
  788.                         mCountVoiceMessages = -1;
  789.                     } else if (indicator == 0x5) {
  790.                         mCountVoiceMessages = 0;
  791.                     }
  792.  
  793.                     mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
  794.                 }
  795.             break;
  796.  
  797.             case EVENT_GET_ICCID_DONE:
  798.                 isRecordLoadResponse = true;
  799.  
  800.                 ar = (AsyncResult)msg.obj;
  801.                 data = (byte[])ar.result;
  802.  
  803.                 if (ar.exception != null) {
  804.                     break;
  805.                 }
  806.  
  807.                 mIccId = IccUtils.bcdToString(data, 0, data.length);
  808.  
  809.                 log("iccid: " + mIccId);
  810.  
  811.             break;
  812.  
  813.  
  814.             case EVENT_GET_AD_DONE:
  815.                 try {
  816.                     isRecordLoadResponse = true;
  817.  
  818.                     ar = (AsyncResult)msg.obj;
  819.                     data = (byte[])ar.result;
  820.  
  821.                     if (ar.exception != null) {
  822.                         break;
  823.                     }
  824.  
  825.                     log("EF_AD: " + IccUtils.bytesToHexString(data));
  826.  
  827.                     if (data.length < 3) {
  828.                         log("Corrupt AD data on SIM");
  829.                         break;
  830.                     }
  831.  
  832.                     if (data.length == 3) {
  833.                         log("MNC length not present in EF_AD");
  834.                         break;
  835.                     }
  836.  
  837.                     mMncLength = data[3] & 0xf;
  838.  
  839.                     if (mMncLength == 0xf) {
  840.                         mMncLength = UNKNOWN;
  841.                     }
  842.                 } finally {
  843.                     if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN) ||
  844.                             (mMncLength == 2)) && ((mImsi != null) && (mImsi.length() >= 6))) {
  845.                         String mccmncCode = mImsi.substring(0, 6);
  846.                         for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
  847.                             if (mccmnc.equals(mccmncCode)) {
  848.                                 mMncLength = 3;
  849.                                 break;
  850.                             }
  851.                         }
  852.                     }
  853.  
  854.                     if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) {
  855.                         if (mImsi != null) {
  856.                             try {
  857.                                 int mcc = Integer.parseInt(mImsi.substring(0,3));
  858.  
  859.                                 mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
  860.                             } catch (NumberFormatException e) {
  861.                                 mMncLength = UNKNOWN;
  862.                                 loge("Corrupt IMSI!");
  863.                             }
  864.                         } else {
  865.                             // Indicate we got this info, but it didn't contain the length.
  866.                             mMncLength = UNKNOWN;
  867.  
  868.                             log("MNC length not present in EF_AD");
  869.                         }
  870.                     }
  871.                     if (mImsi != null && mMncLength != UNKNOWN) {
  872.                         // finally have both imsi and the length of the mnc and can parse
  873.                         // the imsi properly
  874.                         MccTable.updateMccMncConfiguration(mContext,
  875.                                 mImsi.substring(0, 3 + mMncLength));
  876.                     }
  877.                 }
  878.             break;
  879.  
  880.             case EVENT_GET_SPN_DONE:
  881.                 isRecordLoadResponse = true;
  882.                 ar = (AsyncResult) msg.obj;
  883.                 getSpnFsm(false, ar);
  884.             break;
  885.  
  886.             case EVENT_GET_CFF_DONE:
  887.                 isRecordLoadResponse = true;
  888.  
  889.                 ar = (AsyncResult) msg.obj;
  890.                 data = (byte[]) ar.result;
  891.  
  892.                 if (ar.exception != null) {
  893.                     break;
  894.                 }
  895.  
  896.                 log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
  897.                 mEfCff = data;
  898.  
  899.                 // if EF_CFIS is valid, prefer it to EF_CFF_CPHS
  900.                 if (!validEfCfis(mEfCfis)) {
  901.                     mCallForwardingEnabled =
  902.                         ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
  903.  
  904.                     mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
  905.                 } else {
  906.                     log("EVENT_GET_CFF_DONE: EF_CFIS is valid, ignoring EF_CFF_CPHS");
  907.                 }
  908.                 break;
  909.  
  910.             case EVENT_GET_SPDI_DONE:
  911.                 isRecordLoadResponse = true;
  912.  
  913.                 ar = (AsyncResult)msg.obj;
  914.                 data = (byte[])ar.result;
  915.  
  916.                 if (ar.exception != null) {
  917.                     break;
  918.                 }
  919.  
  920.                 parseEfSpdi(data);
  921.             break;
  922.  
  923.             case EVENT_UPDATE_DONE:
  924.                 ar = (AsyncResult)msg.obj;
  925.                 if (ar.exception != null) {
  926.                     logw("update failed. ", ar.exception);
  927.                 }
  928.             break;
  929.  
  930.             case EVENT_GET_PNN_DONE:
  931.                 isRecordLoadResponse = true;
  932.  
  933.                 ar = (AsyncResult)msg.obj;
  934.                 data = (byte[])ar.result;
  935.  
  936.                 if (ar.exception != null) {
  937.                     break;
  938.                 }
  939.  
  940.                 SimTlv tlv = new SimTlv(data, 0, data.length);
  941.  
  942.                 for ( ; tlv.isValidObject() ; tlv.nextObject()) {
  943.                     if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
  944.                         mPnnHomeName
  945.                             = IccUtils.networkNameToString(
  946.                                 tlv.getData(), 0, tlv.getData().length);
  947.                         break;
  948.                     }
  949.                 }
  950.             break;
  951.  
  952.             case EVENT_GET_ALL_SMS_DONE:
  953.                 isRecordLoadResponse = true;
  954.  
  955.                 ar = (AsyncResult)msg.obj;
  956.                 if (ar.exception != null)
  957.                     break;
  958.  
  959.                 handleSmses((ArrayList<byte []>) ar.result);
  960.                 break;
  961.  
  962.             case EVENT_MARK_SMS_READ_DONE:
  963.                 Rlog.i("ENF", "marked read: sms " + msg.arg1);
  964.                 break;
  965.  
  966.  
  967.             case EVENT_SMS_ON_SIM:
  968.                 isRecordLoadResponse = false;
  969.  
  970.                 ar = (AsyncResult)msg.obj;
  971.  
  972.                 int[] index = (int[])ar.result;
  973.  
  974.                 if (ar.exception != null || index.length != 1) {
  975.                     loge("Error on SMS_ON_SIM with exp "
  976.                             + ar.exception + " length " + index.length);
  977.                 } else {
  978.                     log("READ EF_SMS RECORD index=" + index[0]);
  979.                     mFh.loadEFLinearFixed(EF_SMS,index[0],
  980.                             obtainMessage(EVENT_GET_SMS_DONE));
  981.                 }
  982.                 break;
  983.  
  984.             case EVENT_GET_SMS_DONE:
  985.                 isRecordLoadResponse = false;
  986.                 ar = (AsyncResult)msg.obj;
  987.                 if (ar.exception == null) {
  988.                     handleSms((byte[])ar.result);
  989.                 } else {
  990.                     loge("Error on GET_SMS with exp " + ar.exception);
  991.                 }
  992.                 break;
  993.             case EVENT_GET_SST_DONE:
  994.                 isRecordLoadResponse = true;
  995.  
  996.                 ar = (AsyncResult)msg.obj;
  997.                 data = (byte[])ar.result;
  998.  
  999.                 if (ar.exception != null) {
  1000.                     break;
  1001.                 }
  1002.  
  1003.                 mUsimServiceTable = new UsimServiceTable(data);
  1004.                 if (DBG) log("SST: " + mUsimServiceTable);
  1005.                 break;
  1006.  
  1007.             case EVENT_GET_INFO_CPHS_DONE:
  1008.                 isRecordLoadResponse = true;
  1009.  
  1010.                 ar = (AsyncResult)msg.obj;
  1011.  
  1012.                 if (ar.exception != null) {
  1013.                     break;
  1014.                 }
  1015.  
  1016.                 mCphsInfo = (byte[])ar.result;
  1017.  
  1018.                 if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
  1019.             break;
  1020.  
  1021.             case EVENT_SET_MBDN_DONE:
  1022.                 isRecordLoadResponse = false;
  1023.                 ar = (AsyncResult)msg.obj;
  1024.  
  1025.                 if (ar.exception == null) {
  1026.                     mVoiceMailNum = mNewVoiceMailNum;
  1027.                     mVoiceMailTag = mNewVoiceMailTag;
  1028.                 }
  1029.  
  1030.                 if (isCphsMailboxEnabled()) {
  1031.                     adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
  1032.                     Message onCphsCompleted = (Message) ar.userObj;
  1033.  
  1034.                     /* write to cphs mailbox whenever it is available but
  1035.                     * we only need notify caller once if both updating are
  1036.                     * successful.
  1037.                     *
  1038.                     * so if set_mbdn successful, notify caller here and set
  1039.                     * onCphsCompleted to null
  1040.                     */
  1041.                     if (ar.exception == null && ar.userObj != null) {
  1042.                         AsyncResult.forMessage(((Message) ar.userObj)).exception
  1043.                                 = null;
  1044.                         ((Message) ar.userObj).sendToTarget();
  1045.  
  1046.                         if (DBG) log("Callback with MBDN successful.");
  1047.  
  1048.                         onCphsCompleted = null;
  1049.                     }
  1050.  
  1051.                     new AdnRecordLoader(mFh).
  1052.                             updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
  1053.                             obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
  1054.                                     onCphsCompleted));
  1055.                 } else {
  1056.                     if (ar.userObj != null) {
  1057.                         AsyncResult.forMessage(((Message) ar.userObj)).exception
  1058.                                 = ar.exception;
  1059.                         ((Message) ar.userObj).sendToTarget();
  1060.                     }
  1061.                 }
  1062.                 break;
  1063.             case EVENT_SET_CPHS_MAILBOX_DONE:
  1064.                 isRecordLoadResponse = false;
  1065.                 ar = (AsyncResult)msg.obj;
  1066.                 if(ar.exception == null) {
  1067.                     mVoiceMailNum = mNewVoiceMailNum;
  1068.                     mVoiceMailTag = mNewVoiceMailTag;
  1069.                 } else {
  1070.                     if (DBG) log("Set CPHS MailBox with exception: "
  1071.                             + ar.exception);
  1072.                 }
  1073.                 if (ar.userObj != null) {
  1074.                     if (DBG) log("Callback with CPHS MB successful.");
  1075.                     AsyncResult.forMessage(((Message) ar.userObj)).exception
  1076.                             = ar.exception;
  1077.                     ((Message) ar.userObj).sendToTarget();
  1078.                 }
  1079.                 break;
  1080.             case EVENT_SIM_REFRESH:
  1081.                 isRecordLoadResponse = false;
  1082.                 ar = (AsyncResult)msg.obj;
  1083.                 if (DBG) log("Sim REFRESH with exception: " + ar.exception);
  1084.                 if (ar.exception == null) {
  1085.                     handleSimRefresh((IccRefreshResponse)ar.result);
  1086.                 }
  1087.                 break;
  1088.             case EVENT_GET_CFIS_DONE:
  1089.                 isRecordLoadResponse = true;
  1090.  
  1091.                 ar = (AsyncResult)msg.obj;
  1092.                 data = (byte[])ar.result;
  1093.  
  1094.                 if (ar.exception != null) {
  1095.                     break;
  1096.                 }
  1097.  
  1098.                 log("EF_CFIS: " + IccUtils.bytesToHexString(data));
  1099.  
  1100.                 if (validEfCfis(data)) {
  1101.                     mEfCfis = data;
  1102.  
  1103.                     // Refer TS 51.011 Section 10.3.46 for the content description
  1104.                     mCallForwardingEnabled = ((data[1] & 0x01) != 0);
  1105.                     log("EF_CFIS: callForwardingEnabled=" + mCallForwardingEnabled);
  1106.  
  1107.                     mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
  1108.                 } else {
  1109.                     log("EF_CFIS: invalid data=" + IccUtils.bytesToHexString(data));
  1110.                 }
  1111.                 break;
  1112.  
  1113.             case EVENT_GET_CSP_CPHS_DONE:
  1114.                 isRecordLoadResponse = true;
  1115.  
  1116.                 ar = (AsyncResult)msg.obj;
  1117.  
  1118.                 if (ar.exception != null) {
  1119.                     loge("Exception in fetching EF_CSP data " + ar.exception);
  1120.                     break;
  1121.                 }
  1122.  
  1123.                 data = (byte[])ar.result;
  1124.  
  1125.                 log("EF_CSP: " + IccUtils.bytesToHexString(data));
  1126.                 handleEfCspData(data);
  1127.                 break;
  1128.  
  1129.             case EVENT_GET_GID1_DONE:
  1130.                 isRecordLoadResponse = true;
  1131.  
  1132.                 ar = (AsyncResult)msg.obj;
  1133.                 data =(byte[])ar.result;
  1134.  
  1135.                 if (ar.exception != null) {
  1136.                     loge("Exception in get GID1 " + ar.exception);
  1137.                     mGid1 = null;
  1138.                     break;
  1139.                 }
  1140.                 mGid1 = IccUtils.bytesToHexString(data);
  1141.                 log("GID1: " + mGid1);
  1142.  
  1143.                 break;
  1144.  
  1145.             default:
  1146.                 super.handleMessage(msg);   // IccRecords handles generic record load responses
  1147.  
  1148.         }}catch (RuntimeException exc) {
  1149.             // I don't want these exceptions to be fatal
  1150.             logw("Exception parsing SIM record", exc);
  1151.         } finally {
  1152.             // Count up record load responses even if they are fails
  1153.             if (isRecordLoadResponse) {
  1154.                 onRecordLoaded();
  1155.             }
  1156.         }
  1157.     }
  1158.  
  1159.     private void handleFileUpdate(int efid) {
  1160.         switch(efid) {
  1161.             case EF_MBDN:
  1162.                 mRecordsToLoad++;
  1163.                 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
  1164.                         mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
  1165.                 break;
  1166.             case EF_MAILBOX_CPHS:
  1167.                 mRecordsToLoad++;
  1168.                 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
  1169.                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
  1170.                 break;
  1171.             case EF_CSP_CPHS:
  1172.                 mRecordsToLoad++;
  1173.                 log("[CSP] SIM Refresh for EF_CSP_CPHS");
  1174.                 mFh.loadEFTransparent(EF_CSP_CPHS,
  1175.                         obtainMessage(EVENT_GET_CSP_CPHS_DONE));
  1176.                 break;
  1177.             default:
  1178.                 // For now, fetch all records if this is not a
  1179.                 // voicemail number.
  1180.                 // TODO: Handle other cases, instead of fetching all.
  1181.                 mAdnCache.reset();
  1182.                 fetchSimRecords();
  1183.                 break;
  1184.         }
  1185.     }
  1186.  
  1187.     private void handleSimRefresh(IccRefreshResponse refreshResponse){
  1188.         if (refreshResponse == null) {
  1189.             if (DBG) log("handleSimRefresh received without input");
  1190.             return;
  1191.         }
  1192.  
  1193.         if (refreshResponse.aid != null &&
  1194.                 !refreshResponse.aid.equals(mParentApp.getAid())) {
  1195.             // This is for different app. Ignore.
  1196.             return;
  1197.         }
  1198.  
  1199.         switch (refreshResponse.refreshResult) {
  1200.             case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
  1201.                 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
  1202.                 handleFileUpdate(refreshResponse.efId);
  1203.                 break;
  1204.             case IccRefreshResponse.REFRESH_RESULT_INIT:
  1205.                 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
  1206.                 // need to reload all files (that we care about)
  1207.                 onIccRefreshInit();
  1208.                 break;
  1209.             case IccRefreshResponse.REFRESH_RESULT_RESET:
  1210.                 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
  1211.                 mCi.setRadioPower(false, null);
  1212.                 /* Note: no need to call setRadioPower(true).  Assuming the desired
  1213.                 * radio power state is still ON (as tracked by ServiceStateTracker),
  1214.                 * ServiceStateTracker will call setRadioPower when it receives the
  1215.                 * RADIO_STATE_CHANGED notification for the power off.  And if the
  1216.                 * desired power state has changed in the interim, we don't want to
  1217.                 * override it with an unconditional power on.
  1218.                 */
  1219.                 break;
  1220.             default:
  1221.                 // unknown refresh operation
  1222.                 if (DBG) log("handleSimRefresh with unknown operation");
  1223.                 break;
  1224.         }
  1225.     }
  1226.  
  1227.     /**
  1228.      * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone})
  1229.      * to pass to the 3GPP SMS dispatcher for delivery.
  1230.      */
  1231.     protected int dispatchGsmMessage(SmsMessageBase message) {
  1232.         mNewSmsRegistrants.notifyResult(message);
  1233.         return 0;
  1234.     }
  1235.  
  1236.     private void handleSms(byte[] ba) {
  1237.         if (ba[0] != 0)
  1238.             Rlog.d("ENF", "status : " + ba[0]);
  1239.  
  1240.         // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
  1241.         // 3 == "received by MS from network; message to be read"
  1242.         if (ba[0] == 3) {
  1243.             int n = ba.length;
  1244.  
  1245.             // Note: Data may include trailing FF's.  That's OK; message
  1246.             // should still parse correctly.
  1247.             byte[] pdu = new byte[n - 1];
  1248.             System.arraycopy(ba, 1, pdu, 0, n - 1);
  1249.             SmsMessage message = SmsMessage.createFromPdu(pdu);
  1250.  
  1251.             dispatchGsmMessage(message);
  1252.         }
  1253.     }
  1254.  
  1255.  
  1256.     private void handleSmses(ArrayList<byte[]> messages) {
  1257.         int count = messages.size();
  1258.  
  1259.         for (int i = 0; i < count; i++) {
  1260.             byte[] ba = messages.get(i);
  1261.  
  1262.             if (ba[0] != 0)
  1263.                 Rlog.i("ENF", "status " + i + ": " + ba[0]);
  1264.  
  1265.             // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
  1266.             // 3 == "received by MS from network; message to be read"
  1267.  
  1268.             if (ba[0] == 3) {
  1269.                 int n = ba.length;
  1270.  
  1271.                 // Note: Data may include trailing FF's.  That's OK; message
  1272.                 // should still parse correctly.
  1273.                 byte[] pdu = new byte[n - 1];
  1274.                 System.arraycopy(ba, 1, pdu, 0, n - 1);
  1275.                 SmsMessage message = SmsMessage.createFromPdu(pdu);
  1276.  
  1277.                 dispatchGsmMessage(message);
  1278.  
  1279.                 // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
  1280.                 // 1 == "received by MS from network; message read"
  1281.  
  1282.                 ba[0] = 1;
  1283.  
  1284.                 if (false) { // FIXME: writing seems to crash RdoServD
  1285.                     mFh.updateEFLinearFixed(EF_SMS,
  1286.                             i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
  1287.                 }
  1288.             }
  1289.         }
  1290.     }
  1291.  
  1292.     @Override
  1293.     protected void onRecordLoaded() {
  1294.         // One record loaded successfully or failed, In either case
  1295.         // we need to update the recordsToLoad count
  1296.         mRecordsToLoad -= 1;
  1297.         if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
  1298.  
  1299.         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
  1300.             onAllRecordsLoaded();
  1301.         } else if (mRecordsToLoad < 0) {
  1302.             loge("recordsToLoad <0, programmer error suspected");
  1303.             mRecordsToLoad = 0;
  1304.         }
  1305.     }
  1306.  
  1307.     @Override
  1308.     protected void onAllRecordsLoaded() {
  1309.         if (DBG) log("record load complete");
  1310.  
  1311.         // Some fields require more than one SIM record to set
  1312.  
  1313.         String operator = getOperatorNumeric();
  1314.         if (!TextUtils.isEmpty(operator)) {
  1315.             log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
  1316.                     operator + "'");
  1317.             SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
  1318.         } else {
  1319.             log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
  1320.         }
  1321.  
  1322.         if (!TextUtils.isEmpty(mImsi)) {
  1323.             log("onAllRecordsLoaded set mcc imsi=" + mImsi);
  1324.             SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
  1325.                     MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3))));
  1326.         } else {
  1327.             log("onAllRecordsLoaded empty imsi skipping setting mcc");
  1328.         }
  1329.  
  1330.         setVoiceMailByCountry(operator);
  1331.         setSpnFromConfig(operator);
  1332.  
  1333.         mRecordsLoadedRegistrants.notifyRegistrants(
  1334.             new AsyncResult(null, null, null));
  1335.     }
  1336.  
  1337.     //***** Private methods
  1338.  
  1339.     private void setSpnFromConfig(String carrier) {
  1340.         if (mSpnOverride.containsCarrier(carrier)) {
  1341.             mSpn = mSpnOverride.getSpn(carrier);
  1342.         }
  1343.     }
  1344.  
  1345.  
  1346.     private void setVoiceMailByCountry (String spn) {
  1347.         if (mVmConfig.containsCarrier(spn)) {
  1348.             mIsVoiceMailFixed = true;
  1349.             mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
  1350.             mVoiceMailTag = mVmConfig.getVoiceMailTag(spn);
  1351.         }
  1352.     }
  1353.  
  1354.     @Override
  1355.     public void onReady() {
  1356.         fetchSimRecords();
  1357.     }
  1358.  
  1359.     protected void fetchSimRecords() {
  1360.         mRecordsRequested = true;
  1361.  
  1362.         if (DBG) log("fetchSimRecords " + mRecordsToLoad);
  1363.  
  1364.         mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
  1365.         mRecordsToLoad++;
  1366.  
  1367.         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
  1368.         mRecordsToLoad++;
  1369.  
  1370.         // FIXME should examine EF[MSISDN]'s capability configuration
  1371.         // to determine which is the voice/data/fax line
  1372.         new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1,
  1373.                     obtainMessage(EVENT_GET_MSISDN_DONE));
  1374.         mRecordsToLoad++;
  1375.  
  1376.         // Record number is subscriber profile
  1377.         mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
  1378.         mRecordsToLoad++;
  1379.  
  1380.         mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
  1381.         mRecordsToLoad++;
  1382.  
  1383.         // Record number is subscriber profile
  1384.         mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
  1385.         mRecordsToLoad++;
  1386.  
  1387.  
  1388.         // Also load CPHS-style voice mail indicator, which stores
  1389.         // the same info as EF[MWIS]. If both exist, both are updated
  1390.         // but the EF[MWIS] data is preferred
  1391.         // Please note this must be loaded after EF[MWIS]
  1392.         mFh.loadEFTransparent(
  1393.                 EF_VOICE_MAIL_INDICATOR_CPHS,
  1394.                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
  1395.         mRecordsToLoad++;
  1396.  
  1397.         // Same goes for Call Forward Status indicator: fetch both
  1398.         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
  1399.         mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
  1400.         mRecordsToLoad++;
  1401.         mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
  1402.         mRecordsToLoad++;
  1403.  
  1404.  
  1405.         getSpnFsm(true, null);
  1406.  
  1407.         mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
  1408.         mRecordsToLoad++;
  1409.  
  1410.         mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
  1411.         mRecordsToLoad++;
  1412.  
  1413.         mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
  1414.         mRecordsToLoad++;
  1415.  
  1416.         mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
  1417.         mRecordsToLoad++;
  1418.  
  1419.         mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
  1420.         mRecordsToLoad++;
  1421.  
  1422.         mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
  1423.         mRecordsToLoad++;
  1424.  
  1425.         // XXX should seek instead of examining them all
  1426.         if (false) { // XXX
  1427.             mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
  1428.             mRecordsToLoad++;
  1429.         }
  1430.  
  1431.         if (CRASH_RIL) {
  1432.             String sms = "0107912160130310f20404d0110041007030208054832b0120"
  1433.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  1434.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  1435.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  1436.                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  1437.                          + "ffffffffffffffffffffffffffffff";
  1438.             byte[] ba = IccUtils.hexStringToBytes(sms);
  1439.  
  1440.             mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
  1441.                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
  1442.         }
  1443.         if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
  1444.     }
  1445.  
  1446.     /**
  1447.      * Returns the SpnDisplayRule based on settings on the SIM and the
  1448.      * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
  1449.      * and TS 51.011 10.3.11 for details.
  1450.      *
  1451.      * If the SPN is not found on the SIM or is empty, the rule is
  1452.      * always PLMN_ONLY.
  1453.      */
  1454.     @Override
  1455.     public int getDisplayRule(String plmn) {
  1456.         int rule;
  1457.         if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) {
  1458.             // No EF_SPN content was found on the SIM, or not yet loaded.  Just show ONS.
  1459.             rule = SPN_RULE_SHOW_PLMN;
  1460.         } else if (isOnMatchingPlmn(plmn)) {
  1461.             rule = SPN_RULE_SHOW_SPN;
  1462.             if ((mSpnDisplayCondition & 0x01) == 0x01) {
  1463.                 // ONS required when registered to HPLMN or PLMN in EF_SPDI
  1464.                 rule |= SPN_RULE_SHOW_PLMN;
  1465.             }
  1466.         } else {
  1467.             rule = SPN_RULE_SHOW_PLMN;
  1468.             if ((mSpnDisplayCondition & 0x02) == 0x00) {
  1469.                 // SPN required if not registered to HPLMN or PLMN in EF_SPDI
  1470.                 rule |= SPN_RULE_SHOW_SPN;
  1471.             }
  1472.         }
  1473.         return rule;
  1474.     }
  1475.  
  1476.     /**
  1477.      * Checks if plmn is HPLMN or on the spdiNetworks list.
  1478.      */
  1479.     private boolean isOnMatchingPlmn(String plmn) {
  1480.         if (plmn == null) return false;
  1481.  
  1482.         if (plmn.equals(getOperatorNumeric())) {
  1483.             return true;
  1484.         }
  1485.  
  1486.         if (mSpdiNetworks != null) {
  1487.             for (String spdiNet : mSpdiNetworks) {
  1488.                 if (plmn.equals(spdiNet)) {
  1489.                     return true;
  1490.                 }
  1491.             }
  1492.         }
  1493.         return false;
  1494.     }
  1495.  
  1496.     /**
  1497.      * States of Get SPN Finite State Machine which only used by getSpnFsm()
  1498.      */
  1499.     private enum GetSpnFsmState {
  1500.         IDLE,               // No initialized
  1501.         INIT,               // Start FSM
  1502.         READ_SPN_3GPP,      // Load EF_SPN firstly
  1503.         READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
  1504.         READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
  1505.     }
  1506.  
  1507.     /**
  1508.      * Finite State Machine to load Service Provider Name , which can be stored
  1509.      * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
  1510.      *
  1511.      * After starting, FSM will search SPN EFs in order and stop after finding
  1512.      * the first valid SPN
  1513.      *
  1514.      * If the FSM gets restart while waiting for one of
  1515.      * SPN EFs results (i.e. a SIM refresh occurs after issuing
  1516.      * read EF_CPHS_SPN), it will re-initialize only after
  1517.      * receiving and discarding the unfinished SPN EF result.
  1518.      *
  1519.      * @param start set true only for initialize loading
  1520.      * @param ar the AsyncResult from loadEFTransparent
  1521.      *        ar.exception holds exception in error
  1522.      *        ar.result is byte[] for data in success
  1523.      */
  1524.     private void getSpnFsm(boolean start, AsyncResult ar) {
  1525.         byte[] data;
  1526.  
  1527.         if (start) {
  1528.             // Check previous state to see if there is outstanding
  1529.             // SPN read
  1530.             if(mSpnState == GetSpnFsmState.READ_SPN_3GPP ||
  1531.                mSpnState == GetSpnFsmState.READ_SPN_CPHS ||
  1532.                mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS ||
  1533.                mSpnState == GetSpnFsmState.INIT) {
  1534.                 // Set INIT then return so the INIT code
  1535.                 // will run when the outstanding read done.
  1536.                 mSpnState = GetSpnFsmState.INIT;
  1537.                 return;
  1538.             } else {
  1539.                 mSpnState = GetSpnFsmState.INIT;
  1540.             }
  1541.         }
  1542.  
  1543.         switch(mSpnState){
  1544.             case INIT:
  1545.                 mSpn = null;
  1546.  
  1547.                 mFh.loadEFTransparent(EF_SPN,
  1548.                         obtainMessage(EVENT_GET_SPN_DONE));
  1549.                 mRecordsToLoad++;
  1550.  
  1551.                 mSpnState = GetSpnFsmState.READ_SPN_3GPP;
  1552.                 break;
  1553.             case READ_SPN_3GPP:
  1554.                 if (ar != null && ar.exception == null) {
  1555.                     data = (byte[]) ar.result;
  1556.                     mSpnDisplayCondition = 0xff & data[0];
  1557.                     mSpn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
  1558.  
  1559.                     if (DBG) log("Load EF_SPN: " + mSpn
  1560.                             + " spnDisplayCondition: " + mSpnDisplayCondition);
  1561.                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
  1562.  
  1563.                     mSpnState = GetSpnFsmState.IDLE;
  1564.                 } else {
  1565.                     mFh.loadEFTransparent( EF_SPN_CPHS,
  1566.                             obtainMessage(EVENT_GET_SPN_DONE));
  1567.                     mRecordsToLoad++;
  1568.  
  1569.                     mSpnState = GetSpnFsmState.READ_SPN_CPHS;
  1570.  
  1571.                     // See TS 51.011 10.3.11.  Basically, default to
  1572.                     // show PLMN always, and SPN also if roaming.
  1573.                     mSpnDisplayCondition = -1;
  1574.                 }
  1575.                 break;
  1576.             case READ_SPN_CPHS:
  1577.                 if (ar != null && ar.exception == null) {
  1578.                     data = (byte[]) ar.result;
  1579.                     mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
  1580.  
  1581.                     if (DBG) log("Load EF_SPN_CPHS: " + mSpn);
  1582.                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
  1583.  
  1584.                     mSpnState = GetSpnFsmState.IDLE;
  1585.                 } else {
  1586.                     mFh.loadEFTransparent(
  1587.                             EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
  1588.                     mRecordsToLoad++;
  1589.  
  1590.                     mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
  1591.                 }
  1592.                 break;
  1593.             case READ_SPN_SHORT_CPHS:
  1594.                 if (ar != null && ar.exception == null) {
  1595.                     data = (byte[]) ar.result;
  1596.                     mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
  1597.  
  1598.                     if (DBG) log("Load EF_SPN_SHORT_CPHS: " + mSpn);
  1599.                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
  1600.                 }else {
  1601.                     if (DBG) log("No SPN loaded in either CHPS or 3GPP");
  1602.                 }
  1603.  
  1604.                 mSpnState = GetSpnFsmState.IDLE;
  1605.                 break;
  1606.             default:
  1607.                 mSpnState = GetSpnFsmState.IDLE;
  1608.         }
  1609.     }
  1610.  
  1611.     /**
  1612.      * Parse TS 51.011 EF[SPDI] record
  1613.      * This record contains the list of numeric network IDs that
  1614.      * are treated specially when determining SPN display
  1615.      */
  1616.     private void
  1617.     parseEfSpdi(byte[] data) {
  1618.         SimTlv tlv = new SimTlv(data, 0, data.length);
  1619.  
  1620.         byte[] plmnEntries = null;
  1621.  
  1622.         for ( ; tlv.isValidObject() ; tlv.nextObject()) {
  1623.             // Skip SPDI tag, if existant
  1624.             if (tlv.getTag() == TAG_SPDI) {
  1625.               tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
  1626.             }
  1627.             // There should only be one TAG_SPDI_PLMN_LIST
  1628.             if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
  1629.                 plmnEntries = tlv.getData();
  1630.                 break;
  1631.             }
  1632.         }
  1633.  
  1634.         if (plmnEntries == null) {
  1635.             return;
  1636.         }
  1637.  
  1638.         mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3);
  1639.  
  1640.         for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
  1641.             String plmnCode;
  1642.             plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
  1643.  
  1644.             // Valid operator codes are 5 or 6 digits
  1645.             if (plmnCode.length() >= 5) {
  1646.                 log("EF_SPDI network: " + plmnCode);
  1647.                 mSpdiNetworks.add(plmnCode);
  1648.             }
  1649.         }
  1650.     }
  1651.  
  1652.     /**
  1653.      * check to see if Mailbox Number is allocated and activated in CPHS SST
  1654.      */
  1655.     private boolean isCphsMailboxEnabled() {
  1656.         if (mCphsInfo == null)  return false;
  1657.         return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
  1658.     }
  1659.  
  1660.     @Override
  1661.     protected void log(String s) {
  1662.         Rlog.d(LOG_TAG, "[SIMRecords] " + s);
  1663.     }
  1664.  
  1665.     @Override
  1666.     protected void loge(String s) {
  1667.         Rlog.e(LOG_TAG, "[SIMRecords] " + s);
  1668.     }
  1669.  
  1670.     protected void logw(String s, Throwable tr) {
  1671.         Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
  1672.     }
  1673.  
  1674.     protected void logv(String s) {
  1675.         Rlog.v(LOG_TAG, "[SIMRecords] " + s);
  1676.     }
  1677.  
  1678.     /**
  1679.      * Return true if "Restriction of menu options for manual PLMN selection"
  1680.      * bit is set or EF_CSP data is unavailable, return false otherwise.
  1681.      */
  1682.     @Override
  1683.     public boolean isCspPlmnEnabled() {
  1684.         return mCspPlmnEnabled;
  1685.     }
  1686.  
  1687.     /**
  1688.      * Parse EF_CSP data and check if
  1689.      * "Restriction of menu options for manual PLMN selection" is
  1690.      * Enabled/Disabled
  1691.      *
  1692.      * @param data EF_CSP hex data.
  1693.      */
  1694.     private void handleEfCspData(byte[] data) {
  1695.         // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
  1696.         // 18 bytes (i.e 9 service groups info) and additional data specific to
  1697.         // operator. The valueAddedServicesGroup is not part of standard
  1698.         // services. This is operator specific and can be programmed any where.
  1699.         // Normally this is programmed as 10th service after the standard
  1700.         // services.
  1701.         int usedCspGroups = data.length / 2;
  1702.         // This is the "Service Group Number" of "Value Added Services Group".
  1703.         byte valueAddedServicesGroup = (byte)0xC0;
  1704.  
  1705.         mCspPlmnEnabled = true;
  1706.         for (int i = 0; i < usedCspGroups; i++) {
  1707.              if (data[2 * i] == valueAddedServicesGroup) {
  1708.                  log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]);
  1709.                  if ((data[(2 * i) + 1] & 0x80) == 0x80) {
  1710.                      // Bit 8 is for
  1711.                      // "Restriction of menu options for manual PLMN selection".
  1712.                      // Operator Selection menu should be enabled.
  1713.                      mCspPlmnEnabled = true;
  1714.                  } else {
  1715.                      mCspPlmnEnabled = false;
  1716.                      // Operator Selection menu should be disabled.
  1717.                      // Operator Selection Mode should be set to Automatic.
  1718.                      log("[CSP] Set Automatic Network Selection");
  1719.                      mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
  1720.                  }
  1721.                  return;
  1722.              }
  1723.         }
  1724.  
  1725.         log("[CSP] Value Added Service Group (0xC0), not found!");
  1726.     }
  1727.  
  1728.     @Override
  1729.     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  1730.         pw.println("SIMRecords: " + this);
  1731.         pw.println(" extends:");
  1732.         super.dump(fd, pw, args);
  1733.         pw.println(" mVmConfig=" + mVmConfig);
  1734.         pw.println(" mSpnOverride=" + mSpnOverride);
  1735.         pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled);
  1736.         pw.println(" mSpnState=" + mSpnState);
  1737.         pw.println(" mCphsInfo=" + mCphsInfo);
  1738.         pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled);
  1739.         pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS));
  1740.         pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI));
  1741.         pw.println(" mEfCff[]=" + Arrays.toString(mEfCff));
  1742.         pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis));
  1743.         pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition);
  1744.         pw.println(" mSpdiNetworks[]=" + mSpdiNetworks);
  1745.         pw.println(" mPnnHomeName=" + mPnnHomeName);
  1746.         pw.println(" mUsimServiceTable=" + mUsimServiceTable);
  1747.         pw.println(" mGid1=" + mGid1);
  1748.         pw.flush();
  1749.     }
  1750. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement