Merge "Adding API in TelephonyManger for updating Fplmns."
diff --git a/api/current.txt b/api/current.txt
index dda327f..e6e2b40 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45172,6 +45172,7 @@
     method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
     method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
     method public boolean setLine1NumberForDisplay(String, String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean);
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 432978d..b7dab16 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -35,6 +35,15 @@
     /** @hide */
     public static final int INVALID_CHANNEL_NUMBER = -1;
 
+    /**
+     * parameters for validation
+     * @hide
+     */
+    public static final int MCC_LENGTH = 3;
+
+    private static final int MNC_MIN_LENGTH = 2;
+    private static final int MNC_MAX_LENGTH = 3;
+
     // Log tag
     /** @hide */
     protected final String mTag;
@@ -207,6 +216,17 @@
         dest.writeString(mAlphaShort);
     }
 
+    /** Used by phone interface manager to verify if a given string is valid MccMnc
+     * @hide
+     */
+    public static boolean isValidPlmn(@NonNull String plmn) {
+        if (plmn.length() < MCC_LENGTH + MNC_MIN_LENGTH
+                || plmn.length() > MCC_LENGTH + MNC_MAX_LENGTH) {
+            return false;
+        }
+        return (isMcc(plmn.substring(0, MCC_LENGTH)) && isMnc(plmn.substring(MCC_LENGTH)));
+    }
+
     /**
      * Construct from Parcel
      * @hide
@@ -267,10 +287,10 @@
     /** @hide */
     private static boolean isMcc(@NonNull String mcc) {
         // ensure no out of bounds indexing
-        if (mcc.length() != 3) return false;
+        if (mcc.length() != MCC_LENGTH) return false;
 
         // Character.isDigit allows all unicode digits, not just [0-9]
-        for (int i = 0; i < 3; i++) {
+        for (int i = 0; i < MCC_LENGTH; i++) {
             if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
         }
 
@@ -280,7 +300,7 @@
     /** @hide */
     private static boolean isMnc(@NonNull String mnc) {
         // ensure no out of bounds indexing
-        if (mnc.length() < 2 || mnc.length() > 3) return false;
+        if (mnc.length() < MNC_MIN_LENGTH || mnc.length() > MNC_MAX_LENGTH) return false;
 
         // Character.isDigit allows all unicode digits, not just [0-9]
         for (int i = 0; i < mnc.length(); i++) {
@@ -289,4 +309,5 @@
 
         return true;
     }
+
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66571e3..2442023 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6852,6 +6852,40 @@
     }
 
     /**
+     * Replace the contents of the forbidden PLMN SIM file with the provided values.
+     * Passing an empty list will clear the contents of the EFfplmn file.
+     * If the provided list is shorter than the size of EFfplmn, then the list will be padded
+     * up to the file size with 'FFFFFF'. (required by 3GPP TS 31.102 spec 4.2.16)
+     * If the list is longer than the size of EFfplmn, then the file will be written from the
+     * beginning of the list up to the file size.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @param fplmns a list of PLMNs to be forbidden.
+     *
+     * @return number of PLMNs that were successfully written to the SIM FPLMN list.
+     * This may be less than the number of PLMNs passed in where the SIM file does not have enough
+     * room for all of the values passed in. Return -1 in the event of an unexpected failure
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public int setForbiddenPlmns(@NonNull List<String> fplmns) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) return 0;
+            return telephony.setForbiddenPlmns(
+                    getSubId(), APPTYPE_USIM, fplmns, getOpPackageName());
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage());
+        } catch (NullPointerException ex) {
+            // This could happen before phone starts
+            Rlog.e(TAG, "setForbiddenPlmns NullPointerException: " + ex.getMessage());
+        }
+        return 0;
+    }
+
+    /**
      * Get P-CSCF address from PCO after data connection is established or modified.
      * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
      * @return array of P-CSCF address
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4d90579..fd7ec56 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1612,6 +1612,18 @@
     String[] getForbiddenPlmns(int subId, int appType, String callingPackage);
 
     /**
+     * Set the forbidden PLMN list from the givven app type (ex APPTYPE_USIM) on a particular
+     * subscription.
+     *
+     * @param subId subId the id of the subscription
+     * @param appType appType the uicc app type, must be USIM or SIM.
+     * @param fplmns plmns the Forbiden plmns list that needed to be written to the SIM.
+     * @param content callingPackage the op Package name.
+     * @return number of fplmns that is successfully written to the SIM
+     */
+    int setForbiddenPlmns(int subId, int appType, in List<String> fplmns, String callingPackage);
+
+    /**
      * Check if phone is in emergency callback mode
      * @return true if phone is in emergency callback mode
      * @param subId the subscription ID that this action applies to.
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 9c69e2d..f2d4624 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -22,11 +22,13 @@
 import android.graphics.Color;
 import android.telephony.Rlog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.GsmAlphabet;
 
 import dalvik.annotation.compat.UnsupportedAppUsage;
 
 import java.io.UnsupportedEncodingException;
+import java.util.List;
 
 /**
  * Various methods, useful for dealing with SIM data.
@@ -34,6 +36,11 @@
 public class IccUtils {
     static final String LOG_TAG="IccUtils";
 
+    // 3GPP specification constants
+    // Spec reference TS 31.102 section 4.2.16
+    @VisibleForTesting
+    static final int FPLMN_BYTE_SIZE = 3;
+
     // A table mapping from a number to a hex character for fast encoding hex strings.
     private static final char[] HEX_CHARS = {
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
@@ -896,4 +903,27 @@
         }
         return 0;
     }
+
+    /**
+     * Encode the Fplmns into byte array to write to EF.
+     *
+     * @param fplmns Array of fplmns to be serialized.
+     * @param dataLength the size of the EF file.
+     * @return the encoded byte array in the correct format for FPLMN file.
+     */
+    public static byte[] encodeFplmns(List<String> fplmns, int dataLength) {
+        byte[] serializedFplmns = new byte[dataLength];
+        int offset = 0;
+        for (String fplmn : fplmns) {
+            if (offset >= dataLength) break;
+            stringToBcdPlmn(fplmn, serializedFplmns, offset);
+            offset += FPLMN_BYTE_SIZE;
+        }
+        //pads to the length of the EF file.
+        while (offset < dataLength) {
+            // required by 3GPP TS 31.102 spec 4.2.16
+            serializedFplmns[offset++] = (byte) 0xff;
+        }
+        return serializedFplmns;
+    }
 }