DO NOT MERGE - Merge pie-platform-release (PPRL.181205.001, history only) into master

Bug: 120502534
Change-Id: I81e7b906732f23efcb0f9b8ec0035f30e8e807d2
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 31e5364..125a3ae 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -112,6 +112,13 @@
                   android:singleUser="true"
                   android:multiprocess="false" />
 
+        <provider android:name="RcsProvider"
+                  android:authorities="rcs"
+                  android:multiprocess="false"
+                  android:exported="true"
+                  android:singleUser="true"
+                  android:readPermission="android.permission.READ_SMS" />
+
         <service
             android:name=".TelephonyBackupAgent$DeferredSmsMmsRestoreService"
             android:exported="false" />
diff --git a/OWNERS b/OWNERS
index 0716d33..92458db 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,4 +6,7 @@
 mpq@google.com
 jminjie@google.com
 shuoq@google.com
-
+hallliu@google.com
+tgunn@google.com
+breadley@google.com
+nazaninb@google.com
diff --git a/assets/carrier_list.pb b/assets/carrier_list.pb
index 856c5bc..f685099 100644
--- a/assets/carrier_list.pb
+++ b/assets/carrier_list.pb
Binary files differ
diff --git a/assets/carrier_list.textpb b/assets/carrier_list.textpb
index 23196a5..776cd91 100644
--- a/assets/carrier_list.textpb
+++ b/assets/carrier_list.textpb
@@ -28,10 +28,12 @@
   carrier_name: "EE"
   carrier_attribute {
     mccmnc_tuple: "23430"
+    mccmnc_tuple: "23433"
     imsi_prefix_xpattern: "2343041"
   }
   carrier_attribute {
     mccmnc_tuple: "23430"
+    mccmnc_tuple: "23433"
     gid1: "ee"
     gid1: "eeff"
   }
@@ -185,11 +187,12 @@
     mccmnc_tuple: "23201"
     mccmnc_tuple: "23211"
     mccmnc_tuple: "23212"
+    spn: ""
   }
 }
 carrier_id {
   canonical_id: 15
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone - AU"
   carrier_attribute {
     mccmnc_tuple: "50503"
   }
@@ -204,7 +207,7 @@
 }
 carrier_id {
   canonical_id: 18
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone - GR"
   carrier_attribute {
     mccmnc_tuple: "20205"
     spn: "vodafone GR"
@@ -240,14 +243,15 @@
 }
 carrier_id {
   canonical_id: 21
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone - NZ"
   carrier_attribute {
     mccmnc_tuple: "53001"
+    spn: "vodafone NZ"
   }
 }
 carrier_id {
   canonical_id: 22
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone - PT"
   carrier_attribute {
     mccmnc_tuple: "26801"
     spn: ""
@@ -257,7 +261,7 @@
 }
 carrier_id {
   canonical_id: 23
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone - RO"
   carrier_attribute {
     mccmnc_tuple: "22601"
     spn: "Vodafone RO"
@@ -265,7 +269,7 @@
 }
 carrier_id {
   canonical_id: 24
-  carrier_name: "Vodacom"
+  carrier_name: "Vodafone - ZA"
   carrier_attribute {
     mccmnc_tuple: "65501"
   }
@@ -347,7 +351,6 @@
   carrier_name: "Vodafone"
   carrier_attribute {
     mccmnc_tuple: "23415"
-    mccmnc_tuple: "23491"
     spn: ""
     spn: "vodafone UK"
   }
@@ -639,7 +642,7 @@
 }
 carrier_id {
   canonical_id: 568
-  carrier_name: "Velcom"
+  carrier_name: "MDC Velcom"
   carrier_attribute {
     mccmnc_tuple: "25701"
   }
@@ -712,6 +715,10 @@
     gid1: "2c"
     gid1: "4d"
   }
+  carrier_attribute {
+    mccmnc_tuple: "302660"
+    gid1: "MTS"
+  }
 }
 carrier_id {
   canonical_id: 579
@@ -729,6 +736,10 @@
     mccmnc_tuple: "302680"
     mccmnc_tuple: "302780"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    gid1: "5a"
+  }
 }
 carrier_id {
   canonical_id: 581
@@ -747,7 +758,7 @@
 }
 carrier_id {
   canonical_id: 625
-  carrier_name: "Telefónica Móviles Colombia S.A."
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "732123"
   }
@@ -860,9 +871,10 @@
 }
 carrier_id {
   canonical_id: 676
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone Egypt"
   carrier_attribute {
     mccmnc_tuple: "60202"
+    spn: "vodafone"
   }
 }
 carrier_id {
@@ -870,6 +882,7 @@
   carrier_name: "Orange"
   carrier_attribute {
     mccmnc_tuple: "21403"
+    spn: "Orange"
   }
 }
 carrier_id {
@@ -898,6 +911,7 @@
   carrier_name: "Virgin"
   carrier_attribute {
     mccmnc_tuple: "23430"
+    mccmnc_tuple: "23433"
     mccmnc_tuple: "23438"
     gid1: "2800000000000000"
   }
@@ -911,28 +925,7 @@
   carrier_name: "EE"
   carrier_attribute {
     mccmnc_tuple: "23430"
-    imsi_prefix_xpattern: "234300"
-    imsi_prefix_xpattern: "234301"
-    imsi_prefix_xpattern: "234302"
-    imsi_prefix_xpattern: "234303"
-    imsi_prefix_xpattern: "2343040"
-    imsi_prefix_xpattern: "2343042"
-    imsi_prefix_xpattern: "2343043"
-    imsi_prefix_xpattern: "2343044"
-    imsi_prefix_xpattern: "2343045"
-    imsi_prefix_xpattern: "2343046"
-    imsi_prefix_xpattern: "2343047"
-    imsi_prefix_xpattern: "2343048"
-    imsi_prefix_xpattern: "2343049"
-    imsi_prefix_xpattern: "234305"
-    imsi_prefix_xpattern: "234306"
-    imsi_prefix_xpattern: "234307"
-    imsi_prefix_xpattern: "234308"
-    imsi_prefix_xpattern: "234309"
-  }
-  carrier_attribute {
     mccmnc_tuple: "23433"
-    imsi_prefix_xpattern: "x"
   }
 }
 carrier_id {
@@ -1228,6 +1221,7 @@
   carrier_name: "Partner Communications Co. Ltd."
   carrier_attribute {
     mccmnc_tuple: "42501"
+    mccmnc_tuple: "42510"
   }
 }
 carrier_id {
@@ -1271,6 +1265,10 @@
     mccmnc_tuple: "405850"
     mccmnc_tuple: "405852"
     mccmnc_tuple: "405853"
+    mccmnc_tuple: "405908"
+    mccmnc_tuple: "405909"
+    mccmnc_tuple: "405910"
+    mccmnc_tuple: "405911"
   }
 }
 carrier_id {
@@ -1285,6 +1283,7 @@
   carrier_name: "NTT DOCOMO"
   carrier_attribute {
     mccmnc_tuple: "44010"
+    gid1: "00FFFF"
   }
 }
 carrier_id {
@@ -1292,6 +1291,7 @@
   carrier_name: "Safaricom"
   carrier_attribute {
     mccmnc_tuple: "63902"
+    spn: "Safaricom"
   }
 }
 carrier_id {
@@ -1487,7 +1487,7 @@
 }
 carrier_id {
   canonical_id: 959
-  carrier_name: "Netcom GSM AS"
+  carrier_name: "Telia"
   carrier_attribute {
     mccmnc_tuple: "24202"
   }
@@ -1580,7 +1580,7 @@
 }
 carrier_id {
   canonical_id: 974
-  carrier_name: "movistar (Telefónica Moviles Panama S.A.)"
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "71402"
     mccmnc_tuple: "714020"
@@ -2363,7 +2363,7 @@
 }
 carrier_id {
   canonical_id: 1329
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone Albania"
   carrier_attribute {
     mccmnc_tuple: "27602"
     spn: "VODAFONE AL"
@@ -2420,7 +2420,7 @@
 }
 carrier_id {
   canonical_id: 1337
-  carrier_name: "Telefonica Comunicaciones Personales S.A."
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "722070"
     mccmnc_tuple: "72207"
@@ -2652,7 +2652,7 @@
 }
 carrier_id {
   canonical_id: 1370
-  carrier_name: "Mtel"
+  carrier_name: "A1"
   carrier_attribute {
     mccmnc_tuple: "28401"
   }
@@ -2883,6 +2883,7 @@
     mccmnc_tuple: "302221"
     mccmnc_tuple: "30222"
     mccmnc_tuple: "30286"
+    gid1: "5455"
   }
 }
 carrier_id {
@@ -3050,7 +3051,7 @@
 }
 carrier_id {
   canonical_id: 1428
-  carrier_name: "Telefónica Móvil"
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "73002"
     mccmnc_tuple: "73007"
@@ -3065,9 +3066,10 @@
 }
 carrier_id {
   canonical_id: 1430
-  carrier_name: "Centennial Cayman Corp. Chile S.A."
+  carrier_name: "WOM"
   carrier_attribute {
     mccmnc_tuple: "73004"
+    mccmnc_tuple: "73009"
   }
 }
 carrier_id {
@@ -3105,7 +3107,6 @@
   carrier_name: "China Unicom"
   carrier_attribute {
     mccmnc_tuple: "46001"
-    mccmnc_tuple: "46003"
   }
 }
 carrier_id {
@@ -3333,6 +3334,7 @@
   carrier_name: "Claro RD"
   carrier_attribute {
     mccmnc_tuple: "37002"
+    mccmnc_tuple: "370020"
   }
 }
 carrier_id {
@@ -3365,7 +3367,7 @@
 }
 carrier_id {
   canonical_id: 1472
-  carrier_name: "Movistar (Otecel S.A.)"
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "74000"
   }
@@ -3418,6 +3420,10 @@
   carrier_attribute {
     mccmnc_tuple: "24421"
   }
+  carrier_attribute {
+    mccmnc_tuple: "24405"
+    imsi_prefix_xpattern: "2440541"
+  }
 }
 carrier_id {
   canonical_id: 1480
@@ -3593,6 +3599,7 @@
   carrier_name: "Three Mobile"
   carrier_attribute {
     mccmnc_tuple: "23420"
+    mccmnc_tuple: "23494"
   }
 }
 carrier_id {
@@ -3675,13 +3682,7 @@
   carrier_name: "Vodafone"
   carrier_attribute {
     mccmnc_tuple: "62002"
-  }
-}
-carrier_id {
-  canonical_id: 1517
-  carrier_name: "Mobitel"
-  carrier_attribute {
-    mccmnc_tuple: "62003"
+    spn: "Vodafone GH"
   }
 }
 carrier_id {
@@ -3714,7 +3715,7 @@
 }
 carrier_id {
   canonical_id: 1522
-  carrier_name: "Telefónica Centroamérica Guatemala S.A."
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "70403"
     mccmnc_tuple: "704030"
@@ -3774,7 +3775,7 @@
 }
 carrier_id {
   canonical_id: 1530
-  carrier_name: "Vip/Tomato"
+  carrier_name: "A1/Tomato"
   carrier_attribute {
     mccmnc_tuple: "21910"
   }
@@ -3815,6 +3816,10 @@
     spn: ""
     spn: "vodafone HU"
   }
+  carrier_attribute {
+    mccmnc_tuple: "21670"
+    imsi_prefix_xpattern: "21670xx2"
+  }
 }
 carrier_id {
   canonical_id: 1536
@@ -3841,6 +3846,27 @@
     mccmnc_tuple: "40452"
     mccmnc_tuple: "40467"
     mccmnc_tuple: "40485"
+    mccmnc_tuple: "40501"
+    mccmnc_tuple: "40503"
+    mccmnc_tuple: "40504"
+    mccmnc_tuple: "40505"
+    mccmnc_tuple: "40506"
+    mccmnc_tuple: "40507"
+    mccmnc_tuple: "40508"
+    mccmnc_tuple: "40509"
+    mccmnc_tuple: "40510"
+    mccmnc_tuple: "40511"
+    mccmnc_tuple: "40512"
+    mccmnc_tuple: "40513"
+    mccmnc_tuple: "40514"
+    mccmnc_tuple: "40515"
+    mccmnc_tuple: "40517"
+    mccmnc_tuple: "40518"
+    mccmnc_tuple: "40519"
+    mccmnc_tuple: "40520"
+    mccmnc_tuple: "40521"
+    mccmnc_tuple: "40522"
+    mccmnc_tuple: "40523"
   }
 }
 carrier_id {
@@ -3900,6 +3926,13 @@
   }
 }
 carrier_id {
+  canonical_id: 1557
+  carrier_name: "Hexicom India"
+  carrier_attribute {
+    mccmnc_tuple: "40470"
+  }
+}
+carrier_id {
   canonical_id: 1559
   carrier_name: "Reliable Internet Services Ltd."
   carrier_attribute {
@@ -4171,6 +4204,7 @@
   carrier_name: "Vodacom Lesotho (pty) Ltd."
   carrier_attribute {
     mccmnc_tuple: "65101"
+    spn: "Vodacom"
   }
 }
 carrier_id {
@@ -4287,9 +4321,10 @@
 }
 carrier_id {
   canonical_id: 1619
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone Malta"
   carrier_attribute {
     mccmnc_tuple: "27801"
+    spn: "vodafone MT"
   }
 }
 carrier_id {
@@ -4360,6 +4395,8 @@
   carrier_name: "Digi"
   carrier_attribute {
     mccmnc_tuple: "50210"
+    mccmnc_tuple: "502143"
+    mccmnc_tuple: "502146"
     mccmnc_tuple: "50216"
   }
 }
@@ -4397,6 +4434,7 @@
   carrier_name: "Vodacom"
   carrier_attribute {
     mccmnc_tuple: "64304"
+    spn: "Vodacom"
   }
 }
 carrier_id {
@@ -4486,15 +4524,9 @@
 }
 carrier_id {
   canonical_id: 1649
-  carrier_name: "Bmobile"
+  carrier_name: "Vodafone"
   carrier_attribute {
     mccmnc_tuple: "53701"
-  }
-}
-carrier_id {
-  canonical_id: 1650
-  carrier_name: "Greencom"
-  carrier_attribute {
     mccmnc_tuple: "53702"
   }
 }
@@ -4530,6 +4562,10 @@
   canonical_id: 1655
   carrier_name: "Sun"
   carrier_attribute {
+    mccmnc_tuple: "51503"
+    imsi_prefix_xpattern: "5150363"
+  }
+  carrier_attribute {
     mccmnc_tuple: "51505"
   }
 }
@@ -4538,6 +4574,7 @@
   carrier_name: "Jazz"
   carrier_attribute {
     mccmnc_tuple: "41001"
+    mccmnc_tuple: "41007"
   }
 }
 carrier_id {
@@ -4619,7 +4656,7 @@
 }
 carrier_id {
   canonical_id: 1668
-  carrier_name: "Optimus - Telecomunicações, S.A."
+  carrier_name: "NOS"
   carrier_attribute {
     mccmnc_tuple: "26803"
   }
@@ -4633,7 +4670,7 @@
 }
 carrier_id {
   canonical_id: 1670
-  carrier_name: "TMN - Telecomunicações Móveis Nacionais, S.A."
+  carrier_name: "MEO"
   carrier_attribute {
     mccmnc_tuple: "26806"
   }
@@ -4778,6 +4815,10 @@
   carrier_attribute {
     mccmnc_tuple: "24001"
   }
+  carrier_attribute {
+    mccmnc_tuple: "24005"
+    spn: "Telia"
+  }
 }
 carrier_id {
   canonical_id: 1691
@@ -4821,6 +4862,10 @@
   carrier_attribute {
     mccmnc_tuple: "24007"
   }
+  carrier_attribute {
+    mccmnc_tuple: "24024"
+    spn: "Tele2"
+  }
 }
 carrier_id {
   canonical_id: 1697
@@ -5150,6 +5195,7 @@
   carrier_name: "Vodacom (T) Ltd."
   carrier_attribute {
     mccmnc_tuple: "64004"
+    spn: "VodaCom Tanzania"
   }
 }
 carrier_id {
@@ -5336,7 +5382,7 @@
 }
 carrier_id {
   canonical_id: 1771
-  carrier_name: "Vodafone"
+  carrier_name: "Vodafone Malta"
   carrier_attribute {
     mccmnc_tuple: "90119"
   }
@@ -5509,7 +5555,6 @@
   carrier_name: "New Cell Inc. dba Cellcom"
   carrier_attribute {
     mccmnc_tuple: "310600"
-    mccmnc_tuple: "31060"
   }
 }
 carrier_id {
@@ -5675,7 +5720,7 @@
 }
 carrier_id {
   canonical_id: 1827
-  carrier_name: "Taylor Telecommunications Ltd."
+  carrier_name: "Mid-Rivers"
   carrier_attribute {
     mccmnc_tuple: "310900"
   }
@@ -5689,7 +5734,7 @@
 }
 carrier_id {
   canonical_id: 1829
-  carrier_name: "Get Mobile"
+  carrier_name: "James Valley"
   carrier_attribute {
     mccmnc_tuple: "310920"
   }
@@ -5731,11 +5776,15 @@
 }
 carrier_id {
   canonical_id: 1836
-  carrier_name: "Cellular South Inc."
+  carrier_name: "C Spire"
   carrier_attribute {
     mccmnc_tuple: "311230"
     mccmnc_tuple: "310023"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    spn: "C Spire"
+  }
 }
 carrier_id {
   canonical_id: 1837
@@ -5760,6 +5809,10 @@
   }
   carrier_attribute {
     mccmnc_tuple: "310004"
+    spn: "Verizon"
+    spn: "Verizon Wireless"
+  }
+  carrier_attribute {
     mccmnc_tuple: "310012"
     mccmnc_tuple: "311280"
     mccmnc_tuple: "311281"
@@ -5834,14 +5887,14 @@
 }
 carrier_id {
   canonical_id: 1847
-  carrier_name: "Northwest Missouri Cellular Limited Partnership"
+  carrier_name: "northwestcell"
   carrier_attribute {
     mccmnc_tuple: "311420"
   }
 }
 carrier_id {
   canonical_id: 1848
-  carrier_name: "RSA 1 Limited Partnership dba Cellular 29 Plus"
+  carrier_name: "Chat Mobility"
   carrier_attribute {
     mccmnc_tuple: "311430"
   }
@@ -5855,7 +5908,7 @@
 }
 carrier_id {
   canonical_id: 1850
-  carrier_name: "Panhandle Telecommunication Systems Inc."
+  carrier_name: "PTCI"
   carrier_attribute {
     mccmnc_tuple: "311450"
   }
@@ -5880,6 +5933,11 @@
   carrier_attribute {
     mccmnc_tuple: "311490"
   }
+  carrier_attribute {
+    mccmnc_tuple: "310120"
+    mccmnc_tuple: "312530"
+    gid1: "000003"
+  }
 }
 carrier_id {
   canonical_id: 1854
@@ -6164,7 +6222,7 @@
 }
 carrier_id {
   canonical_id: 1894
-  carrier_name: "SoftBank・Y!mobile"
+  carrier_name: "SoftBank"
   carrier_attribute {
     mccmnc_tuple: "44020"
   }
@@ -6175,6 +6233,11 @@
   carrier_attribute {
     mccmnc_tuple: "302490"
   }
+  carrier_attribute {
+    mccmnc_tuple: "22201"
+    mccmnc_tuple: "22288"
+    gid1: "ffffff00"
+  }
 }
 carrier_id {
   canonical_id: 1896
@@ -6276,6 +6339,10 @@
     mccmnc_tuple: "21406"
     mccmnc_tuple: "21408"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20403"
+    imsi_prefix_xpattern: "2140359"
+  }
 }
 carrier_id {
   canonical_id: 1910
@@ -6299,6 +6366,11 @@
     mccmnc_tuple: "334090"
     mccmnc_tuple: "33409"
   }
+  carrier_attribute {
+    mccmnc_tuple: "22201"
+    spn: "IUSACELL"
+    spn: "UNEFON"
+  }
 }
 carrier_id {
   canonical_id: 1913
@@ -6398,6 +6470,7 @@
   carrier_name: "Digicel"
   carrier_attribute {
     mccmnc_tuple: "71404"
+    mccmnc_tuple: "714040"
   }
 }
 carrier_id {
@@ -6416,7 +6489,7 @@
 }
 carrier_id {
   canonical_id: 1929
-  carrier_name: "Telefonica Moviles Peru"
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "71606"
   }
@@ -6559,6 +6632,22 @@
   carrier_name: "MetroPCS"
   carrier_attribute {
     mccmnc_tuple: "310260"
+    mccmnc_tuple: "310800"
+    mccmnc_tuple: "310660"
+    mccmnc_tuple: "310640"
+    mccmnc_tuple: "310590"
+    mccmnc_tuple: "310530"
+    mccmnc_tuple: "310490"
+    mccmnc_tuple: "310310"
+    mccmnc_tuple: "310300"
+    mccmnc_tuple: "310270"
+    mccmnc_tuple: "310250"
+    mccmnc_tuple: "310240"
+    mccmnc_tuple: "310230"
+    mccmnc_tuple: "310220"
+    mccmnc_tuple: "310210"
+    mccmnc_tuple: "310200"
+    mccmnc_tuple: "310160"
     gid1: "6D38"
   }
 }
@@ -6575,6 +6664,11 @@
   carrier_attribute {
     mccmnc_tuple: "311870"
   }
+  carrier_attribute {
+    mccmnc_tuple: "310120"
+    mccmnc_tuple: "312530"
+    gid1: "000002"
+  }
 }
 carrier_id {
   canonical_id: 1952
@@ -6583,6 +6677,10 @@
     mccmnc_tuple: "311580"
     mccmnc_tuple: "311220"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    spn: "U.S. Cellular"
+  }
 }
 carrier_id {
   canonical_id: 1953
@@ -6648,13 +6746,11 @@
   carrier_attribute {
     mccmnc_tuple: "40402"
     mccmnc_tuple: "40403"
-    mccmnc_tuple: "40410"
     mccmnc_tuple: "40416"
     mccmnc_tuple: "40431"
     mccmnc_tuple: "40440"
     mccmnc_tuple: "40445"
     mccmnc_tuple: "40449"
-    mccmnc_tuple: "40470"
     mccmnc_tuple: "40490"
     mccmnc_tuple: "40492"
     mccmnc_tuple: "40493"
@@ -6710,6 +6806,7 @@
     mccmnc_tuple: "405754"
     mccmnc_tuple: "405755"
     mccmnc_tuple: "405756"
+    spn: "Vodafone IN"
   }
 }
 carrier_id {
@@ -6789,6 +6886,12 @@
   carrier_attribute {
     mccmnc_tuple: "21421"
   }
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    mccmnc_tuple: "21407"
+    spn: "JAZZTEL"
+    spn: "Jazztel"
+  }
 }
 carrier_id {
   canonical_id: 1975
@@ -6834,13 +6937,6 @@
   }
 }
 carrier_id {
-  canonical_id: 1981
-  carrier_name: "WaridTel"
-  carrier_attribute {
-    mccmnc_tuple: "41007"
-  }
-}
-carrier_id {
   canonical_id: 1982
   carrier_name: "TATA DOCOMO"
   carrier_attribute {
@@ -6884,7 +6980,7 @@
 }
 carrier_id {
   canonical_id: 1985
-  carrier_name: "Wana"
+  carrier_name: "Inwi"
   carrier_attribute {
     mccmnc_tuple: "60402"
   }
@@ -6927,6 +7023,15 @@
     spn: "nova"
   }
   carrier_attribute {
+    mccmnc_tuple: "310120"
+    gid1: "A00184"
+    gid1: "A00184FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "310120"
+    privilege_access_rule: "4C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859"
+  }
+  carrier_attribute {
     mccmnc_tuple: "310260"
     imsi_prefix_xpattern: "31026097"
   }
@@ -6949,6 +7054,10 @@
     mccmnc_tuple: "42507"
     mccmnc_tuple: "42577"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    spn: "HOT mobile"
+  }
 }
 carrier_id {
   canonical_id: 1992
@@ -6997,6 +7106,7 @@
   carrier_name: "Vodafone"
   carrier_attribute {
     mccmnc_tuple: "42702"
+    spn: "Vodafone Qatar"
   }
 }
 carrier_id {
@@ -7029,7 +7139,7 @@
 }
 carrier_id {
   canonical_id: 2003
-  carrier_name: "movistar"
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "71204"
   }
@@ -7047,6 +7157,11 @@
   carrier_attribute {
     mccmnc_tuple: "20826"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20801"
+    mccmnc_tuple: "20810"
+    gid1: "4E"
+  }
 }
 carrier_id {
   canonical_id: 2006
@@ -7073,7 +7188,7 @@
 }
 carrier_id {
   canonical_id: 2009
-  carrier_name: "Movistar (Telefonica Moviles El Salvador)"
+  carrier_name: "Movistar"
   carrier_attribute {
     mccmnc_tuple: "70604"
     mccmnc_tuple: "706040"
@@ -7151,7 +7266,7 @@
     mccmnc_tuple: "302221"
     mccmnc_tuple: "30222"
     mccmnc_tuple: "30286"
-    gid1: "4b4f"
+    gid1: "4B4F"
   }
 }
 carrier_id {
@@ -7255,7 +7370,7 @@
 }
 carrier_id {
   canonical_id: 2032
-  carrier_name: "XFINITY Mobile"
+  carrier_name: "XFINIY Mobile"
   carrier_attribute {
     mccmnc_tuple: "311480"
     gid1: "BA01450000000000"
@@ -7305,6 +7420,96 @@
   }
 }
 carrier_id {
+  canonical_id: 2039
+  carrier_name: "Fastweb"
+  carrier_attribute {
+    mccmnc_tuple: "22299"
+    spn: "FASTWEB"
+  }
+}
+carrier_id {
+  canonical_id: 2040
+  carrier_name: "Digi.Mobil"
+  carrier_attribute {
+    mccmnc_tuple: "22299"
+    spn: "DIGI.Mobil"
+  }
+}
+carrier_id {
+  canonical_id: 2041
+  carrier_name: "mms mobil"
+  carrier_attribute {
+    mccmnc_tuple: "23210"
+    spn: "MMmobil"
+  }
+}
+carrier_id {
+  canonical_id: 2042
+  carrier_name: "eety"
+  carrier_attribute {
+    mccmnc_tuple: "23210"
+    mccmnc_tuple: "2321283"
+    spn: "eety"
+  }
+}
+carrier_id {
+  canonical_id: 2043
+  carrier_name: "UPC"
+  carrier_attribute {
+    mccmnc_tuple: "23213"
+    gid1: "uat1"
+  }
+}
+carrier_id {
+  canonical_id: 2044
+  carrier_name: "spusu"
+  carrier_attribute {
+    mccmnc_tuple: "23217"
+    spn: "spusu"
+    gid1: "C7FF"
+  }
+}
+carrier_id {
+  canonical_id: 2045
+  carrier_name: "simpli"
+  carrier_attribute {
+    mccmnc_tuple: "23218"
+    spn: "simpli"
+  }
+}
+carrier_id {
+  canonical_id: 2046
+  carrier_name: "HGES"
+  carrier_attribute {
+    mccmnc_tuple: "23420"
+    gid1: "0304"
+  }
+}
+carrier_id {
+  canonical_id: 2047
+  carrier_name: "Kapow"
+  carrier_attribute {
+    mccmnc_tuple: "23420"
+    gid1: "0305"
+  }
+}
+carrier_id {
+  canonical_id: 2049
+  carrier_name: "Generic Wholesale?"
+  carrier_attribute {
+    mccmnc_tuple: "23420"
+    gid1: "0307"
+  }
+}
+carrier_id {
+  canonical_id: 2050
+  carrier_name: "OTONO"
+  carrier_attribute {
+    mccmnc_tuple: "23420"
+    gid1: "0308"
+  }
+}
+carrier_id {
   canonical_id: 2052
   carrier_name: "Virgin"
   carrier_attribute {
@@ -7323,6 +7528,7 @@
   }
   carrier_attribute {
     mccmnc_tuple: "302220"
+    mccmnc_tuple: "302221"
     gid1: "5043"
   }
 }
@@ -7341,9 +7547,16 @@
   canonical_id: 2055
   carrier_name: "Chatr Mobile"
   carrier_attribute {
+    mccmnc_tuple: "302320"
+  }
+  carrier_attribute {
     mccmnc_tuple: "302720"
     imsi_prefix_xpattern: "302720x94"
-    gid1: "ff"
+    imsi_prefix_xpattern: "302720x84"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "302720"
+    gid1: "d2"
   }
 }
 carrier_id {
@@ -7352,7 +7565,10 @@
   carrier_attribute {
     mccmnc_tuple: "302720"
     imsi_prefix_xpattern: "302720x98"
-    gid1: "ff"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "302720"
+    gid1: "d4"
   }
 }
 carrier_id {
@@ -7363,6 +7579,10 @@
     imsi_prefix_xpattern: "302720x97"
     gid1: "cc"
   }
+  carrier_attribute {
+    mccmnc_tuple: "302720"
+    spn: "CITYFONE"
+  }
 }
 carrier_id {
   canonical_id: 2060
@@ -7565,7 +7785,8 @@
   carrier_name: "Public Mobile"
   carrier_attribute {
     mccmnc_tuple: "302220"
-    gid1: "4d4f"
+    mccmnc_tuple: "302221"
+    gid1: "4D4F"
   }
 }
 carrier_id {
@@ -7700,6 +7921,10 @@
     mccmnc_tuple: "44010"
     preferred_apn: "iijmio.jp"
   }
+  carrier_attribute {
+    mccmnc_tuple: "20601"
+    spn: "IIJ"
+  }
 }
 carrier_id {
   canonical_id: 2107
@@ -7710,8 +7935,9 @@
 }
 carrier_id {
   canonical_id: 2108
-  carrier_name: "Airtel"
+  carrier_name: "AirtelTigo"
   carrier_attribute {
+    mccmnc_tuple: "62003"
     mccmnc_tuple: "62006"
   }
 }
@@ -7723,11 +7949,16 @@
     preferred_apn: "rmobile.co"
     preferred_apn: "rmobile.jp"
   }
+  carrier_attribute {
+    mccmnc_tuple: "44051"
+    preferred_apn: "a.rmobile.jp"
+  }
 }
 carrier_id {
   canonical_id: 2110
   carrier_name: "UQ mobile"
   carrier_attribute {
+    mccmnc_tuple: "44050"
     mccmnc_tuple: "44051"
     preferred_apn: "uqmobile.jp"
   }
@@ -7745,12 +7976,25 @@
   canonical_id: 2112
   carrier_name: "Telecable"
   carrier_attribute {
-    mccmnc_tuple: "21405"
     mccmnc_tuple: "21416"
     spn: "telecable"
     spn: "Telecable"
     spn: "TeleCable"
   }
+  carrier_attribute {
+    mccmnc_tuple: "21405"
+    imsi_prefix_xpattern: "214050111"
+    spn: "telecable"
+    spn: "Telecable"
+    spn: "TeleCable"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "21406"
+    imsi_prefix_xpattern: "2140613"
+    spn: "telecable"
+    spn: "Telecable"
+    spn: "TeleCable"
+  }
 }
 carrier_id {
   canonical_id: 2113
@@ -7802,5 +8046,1717 @@
     mccmnc_tuple: "23410"
     gid1: "508"
   }
+  carrier_attribute {
+    mccmnc_tuple: "23410"
+    spn: "giffgaff"
+  }
 }
-version: 4
+carrier_id {
+  canonical_id: 2119
+  carrier_name: "FirstNet"
+  carrier_attribute {
+    mccmnc_tuple: "313100"
+  }
+}
+carrier_id {
+  canonical_id: 2120
+  carrier_name: "FirstNet (Lab)"
+  carrier_attribute {
+    mccmnc_tuple: "312670"
+  }
+}
+carrier_id {
+  canonical_id: 2121
+  carrier_name: "mineo"
+  carrier_attribute {
+    mccmnc_tuple: "44010"
+    preferred_apn: "mineo-d.jp"
+  }
+}
+carrier_id {
+  canonical_id: 2122
+  carrier_name: "Lucky Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "30264"
+    mccmnc_tuple: "302610"
+    mccmnc_tuple: "302630"
+    mccmnc_tuple: "302640"
+    gid1: "42"
+  }
+}
+carrier_id {
+  canonical_id: 2123
+  carrier_name: "Vodafone"
+  carrier_attribute {
+    mccmnc_tuple: "54002"
+  }
+}
+carrier_id {
+  canonical_id: 2124
+  carrier_name: "Iliad"
+  carrier_attribute {
+    mccmnc_tuple: "22250"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20815"
+    gid1: "F003"
+  }
+}
+carrier_id {
+  canonical_id: 2125
+  carrier_name: "Simyo"
+  carrier_attribute {
+    mccmnc_tuple: "21419"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    spn: "simyo"
+  }
+}
+carrier_id {
+  canonical_id: 2126
+  carrier_name: "Spectrum Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "311480"
+    gid1: "BA01490000000000"
+  }
+}
+carrier_id {
+  canonical_id: 2127
+  carrier_name: "Free RE"
+  carrier_attribute {
+    mccmnc_tuple: "64703"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20815"
+    gid1: "F2330002"
+  }
+}
+carrier_id {
+  canonical_id: 2128
+  carrier_name: "Sprint Wholesale"
+  carrier_attribute {
+    mccmnc_tuple: "310120"
+    gid1: "A00022FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00305FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00209FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00250FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00207FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00105FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00181FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00263FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00271FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00006FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00151FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00058FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00301FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00143FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00247FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00274FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00042FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00092FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00312FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00050FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+    gid1: "A00034FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+  }
+}
+carrier_id {
+  canonical_id: 2129
+  carrier_name: "ALDI mobile"
+  carrier_attribute {
+    mccmnc_tuple: "50501"
+    spn: "aldimobile"
+  }
+}
+carrier_id {
+  canonical_id: 2130
+  carrier_name: "ALIV BS"
+  carrier_attribute {
+    mccmnc_tuple: "20809"
+    imsi_prefix_xpattern: "208090021"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "36449"
+  }
+}
+carrier_id {
+  canonical_id: 2131
+  carrier_name: "Altecom"
+  carrier_attribute {
+    mccmnc_tuple: "21402"
+  }
+}
+carrier_id {
+  canonical_id: 2132
+  carrier_name: "Bics"
+  carrier_attribute {
+    mccmnc_tuple: "20628"
+    mccmnc_tuple: "90158"
+  }
+}
+carrier_id {
+  canonical_id: 2133
+  carrier_name: "Carrefour"
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    imsi_prefix_xpattern: "2140352"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20801"
+    gid1: "33"
+  }
+}
+carrier_id {
+  canonical_id: 2134
+  carrier_name: "com4"
+  carrier_attribute {
+    mccmnc_tuple: "24209"
+  }
+}
+carrier_id {
+  canonical_id: 2135
+  carrier_name: "Coriolis"
+  carrier_attribute {
+    mccmnc_tuple: "20827"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    mccmnc_tuple: "64710"
+    gid1: "12"
+  }
+}
+carrier_id {
+  canonical_id: 2136
+  carrier_name: "Fibracat"
+  carrier_attribute {
+    mccmnc_tuple: "21402"
+    spn: "fibracat"
+  }
+}
+carrier_id {
+  canonical_id: 2137
+  carrier_name: "Gamma"
+  carrier_attribute {
+    mccmnc_tuple: "23439"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "24007"
+    imsi_prefix_xpattern: "24007561"
+  }
+}
+carrier_id {
+  canonical_id: 2138
+  carrier_name: "Jump"
+  carrier_attribute {
+    mccmnc_tuple: "23410"
+    mccmnc_tuple: "23439"
+    mccmnc_tuple: "24007"
+    spn: "jump"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    spn: "Jump"
+  }
+}
+carrier_id {
+  canonical_id: 2139
+  carrier_name: "Sky"
+  carrier_attribute {
+    mccmnc_tuple: "23457"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "24007"
+    gid1: "0c"
+  }
+}
+carrier_id {
+  canonical_id: 2140
+  carrier_name: "Smarty"
+  carrier_attribute {
+    mccmnc_tuple: "23420"
+    gid1: "0309"
+  }
+}
+carrier_id {
+  canonical_id: 2141
+  carrier_name: "Superdrug"
+  carrier_attribute {
+    mccmnc_tuple: "23420"
+    gid1: "0310"
+  }
+}
+carrier_id {
+  canonical_id: 2142
+  carrier_name: "Tinkoff"
+  carrier_attribute {
+    mccmnc_tuple: "25062"
+  }
+}
+carrier_id {
+  canonical_id: 2143
+  carrier_name: "Truphone"
+  carrier_attribute {
+    mccmnc_tuple: "20433"
+    mccmnc_tuple: "21427"
+    mccmnc_tuple: "23425"
+    mccmnc_tuple: "26033"
+    mccmnc_tuple: "26242"
+    mccmnc_tuple: "31030"
+    mccmnc_tuple: "50538"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    imsi_prefix_xpattern: "204043914"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "23450"
+    imsi_prefix_xpattern: "234500008"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "50502"
+    imsi_prefix_xpattern: "50502100"
+  }
+}
+carrier_id {
+  canonical_id: 2144
+  carrier_name: "Unleashed"
+  carrier_attribute {
+    mccmnc_tuple: "20630"
+  }
+}
+carrier_id {
+  canonical_id: 2145
+  carrier_name: "Virgin"
+  carrier_attribute {
+    mccmnc_tuple: "50502"
+    imsi_prefix_xpattern: "505029"
+  }
+}
+carrier_id {
+  canonical_id: 2146
+  carrier_name: "Visible"
+  carrier_attribute {
+    mccmnc_tuple: "311480"
+    gid1: "bae1000000000000"
+  }
+}
+carrier_id {
+  canonical_id: 2147
+  carrier_name: "Vodafone Lab"
+  carrier_attribute {
+    mccmnc_tuple: "26209"
+  }
+}
+carrier_id {
+  canonical_id: 2148
+  carrier_name: "BIGLOBE"
+  carrier_attribute {
+    mccmnc_tuple: "44010"
+    preferred_apn: "biglobe.jp"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "44051"
+    preferred_apn: "biglobe.jp"
+  }
+}
+carrier_id {
+  canonical_id: 2149
+  carrier_name: "Voiceworks"
+  carrier_attribute {
+    mccmnc_tuple: "20403"
+  }
+}
+carrier_id {
+  canonical_id: 2150
+  carrier_name: "Telenet"
+  carrier_attribute {
+    mccmnc_tuple: "20605"
+  }
+}
+carrier_id {
+  canonical_id: 2151
+  carrier_name: "Legos"
+  carrier_attribute {
+    mccmnc_tuple: "20817"
+  }
+}
+carrier_id {
+  canonical_id: 2152
+  carrier_name: "Lycamobile"
+  carrier_attribute {
+    mccmnc_tuple: "23426"
+  }
+}
+carrier_id {
+  canonical_id: 2153
+  carrier_name: "Unité"
+  carrier_attribute {
+    mccmnc_tuple: "25905"
+  }
+}
+carrier_id {
+  canonical_id: 2154
+  carrier_name: "Tesco"
+  carrier_attribute {
+    mccmnc_tuple: "27211"
+  }
+}
+carrier_id {
+  canonical_id: 2155
+  carrier_name: "Nova"
+  carrier_attribute {
+    mccmnc_tuple: "27411"
+  }
+}
+carrier_id {
+  canonical_id: 2156
+  carrier_name: "PrimeTel"
+  carrier_attribute {
+    mccmnc_tuple: "28020"
+  }
+}
+carrier_id {
+  canonical_id: 2157
+  carrier_name: "IT&E OverSeas"
+  carrier_attribute {
+    mccmnc_tuple: "310032"
+  }
+}
+carrier_id {
+  canonical_id: 2158
+  carrier_name: "North Dakota Network Company"
+  carrier_attribute {
+    mccmnc_tuple: "311610"
+  }
+}
+carrier_id {
+  canonical_id: 2159
+  carrier_name: "United Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "311650"
+    spn: "unitedwireless"
+  }
+}
+carrier_id {
+  canonical_id: 2160
+  carrier_name: "Pine Belt"
+  carrier_attribute {
+    mccmnc_tuple: "311670"
+    spn: "pinebelt"
+  }
+}
+carrier_id {
+  canonical_id: 2161
+  carrier_name: "Missouri RSA No 5 Partnership"
+  carrier_attribute {
+    mccmnc_tuple: "311920"
+  }
+}
+carrier_id {
+  canonical_id: 2162
+  carrier_name: "Custer"
+  carrier_attribute {
+    mccmnc_tuple: "312040"
+  }
+}
+carrier_id {
+  canonical_id: 2163
+  carrier_name: "Digicel"
+  carrier_attribute {
+    mccmnc_tuple: "36302"
+  }
+}
+carrier_id {
+  canonical_id: 2164
+  carrier_name: "ALTEL"
+  carrier_attribute {
+    mccmnc_tuple: "40107"
+  }
+}
+carrier_id {
+  canonical_id: 2165
+  carrier_name: "TashiCell"
+  carrier_attribute {
+    mccmnc_tuple: "40277"
+  }
+}
+carrier_id {
+  canonical_id: 2166
+  carrier_name: "SanaTel"
+  carrier_attribute {
+    mccmnc_tuple: "41808"
+  }
+}
+carrier_id {
+  canonical_id: 2167
+  carrier_name: "Omnnea"
+  carrier_attribute {
+    mccmnc_tuple: "41892"
+  }
+}
+carrier_id {
+  canonical_id: 2168
+  carrier_name: "HiTS-UNITEL"
+  carrier_attribute {
+    mccmnc_tuple: "42104"
+  }
+}
+carrier_id {
+  canonical_id: 2169
+  carrier_name: "Alon Cellular Ltd"
+  carrier_attribute {
+    mccmnc_tuple: "42514"
+  }
+}
+carrier_id {
+  canonical_id: 2170
+  carrier_name: "Home Cellular"
+  carrier_attribute {
+    mccmnc_tuple: "42515"
+  }
+}
+carrier_id {
+  canonical_id: 2171
+  carrier_name: "Rami Levy"
+  carrier_attribute {
+    mccmnc_tuple: "42516"
+  }
+}
+carrier_id {
+  canonical_id: 2172
+  carrier_name: "Skytel"
+  carrier_attribute {
+    mccmnc_tuple: "42891"
+  }
+}
+carrier_id {
+  canonical_id: 2173
+  carrier_name: "G.Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "42898"
+  }
+}
+carrier_id {
+  canonical_id: 2174
+  carrier_name: "Tcell"
+  carrier_attribute {
+    mccmnc_tuple: "43612"
+  }
+}
+carrier_id {
+  canonical_id: 2175
+  carrier_name: "AkTel LLC"
+  carrier_attribute {
+    mccmnc_tuple: "43703"
+  }
+}
+carrier_id {
+  canonical_id: 2176
+  carrier_name: "MegaCom"
+  carrier_attribute {
+    mccmnc_tuple: "43705"
+  }
+}
+carrier_id {
+  canonical_id: 2177
+  carrier_name: "O!"
+  carrier_attribute {
+    mccmnc_tuple: "43709"
+  }
+}
+carrier_id {
+  canonical_id: 2178
+  carrier_name: "Gmobile"
+  carrier_attribute {
+    mccmnc_tuple: "45207"
+  }
+}
+carrier_id {
+  canonical_id: 2179
+  carrier_name: "Viettel Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "45208"
+  }
+}
+carrier_id {
+  canonical_id: 2180
+  carrier_name: "qb"
+  carrier_attribute {
+    mccmnc_tuple: "45604"
+  }
+}
+carrier_id {
+  canonical_id: 2181
+  carrier_name: "Metfone"
+  carrier_attribute {
+    mccmnc_tuple: "45608"
+  }
+}
+carrier_id {
+  canonical_id: 2182
+  carrier_name: "Telkomcel"
+  carrier_attribute {
+    mccmnc_tuple: "51401"
+  }
+}
+carrier_id {
+  canonical_id: 2183
+  carrier_name: "Timor Telecom"
+  carrier_attribute {
+    mccmnc_tuple: "51402"
+  }
+}
+carrier_id {
+  canonical_id: 2184
+  carrier_name: "Redinternet"
+  carrier_attribute {
+    mccmnc_tuple: "51518"
+  }
+}
+carrier_id {
+  canonical_id: 2185
+  carrier_name: "BREEZE"
+  carrier_attribute {
+    mccmnc_tuple: "54001"
+  }
+}
+carrier_id {
+  canonical_id: 2186
+  carrier_name: "Digicel"
+  carrier_attribute {
+    mccmnc_tuple: "54202"
+  }
+}
+carrier_id {
+  canonical_id: 2187
+  carrier_name: "Kiribati Frigate"
+  carrier_attribute {
+    mccmnc_tuple: "54509"
+  }
+}
+carrier_id {
+  canonical_id: 2188
+  carrier_name: "Palau Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "55280"
+  }
+}
+carrier_id {
+  canonical_id: 2189
+  carrier_name: "Al-Jeel"
+  carrier_attribute {
+    mccmnc_tuple: "60602"
+  }
+}
+carrier_id {
+  canonical_id: 2190
+  carrier_name: "Hatef"
+  carrier_attribute {
+    mccmnc_tuple: "60606"
+  }
+}
+carrier_id {
+  canonical_id: 2191
+  carrier_name: "QCell"
+  carrier_attribute {
+    mccmnc_tuple: "60704"
+  }
+}
+carrier_id {
+  canonical_id: 2192
+  carrier_name: "Expresso"
+  carrier_attribute {
+    mccmnc_tuple: "60803"
+  }
+}
+carrier_id {
+  canonical_id: 2193
+  carrier_name: "Intercel"
+  carrier_attribute {
+    mccmnc_tuple: "61103"
+  }
+}
+carrier_id {
+  canonical_id: 2194
+  carrier_name: "Lonestar"
+  carrier_attribute {
+    mccmnc_tuple: "61801"
+  }
+}
+carrier_id {
+  canonical_id: 2195
+  carrier_name: "Libercell"
+  carrier_attribute {
+    mccmnc_tuple: "61802"
+  }
+}
+carrier_id {
+  canonical_id: 2196
+  carrier_name: "LIBTELCO"
+  carrier_attribute {
+    mccmnc_tuple: "61820"
+  }
+}
+carrier_id {
+  canonical_id: 2197
+  carrier_name: "Salam"
+  carrier_attribute {
+    mccmnc_tuple: "62204"
+  }
+}
+carrier_id {
+  canonical_id: 2198
+  carrier_name: "Nationlink"
+  carrier_attribute {
+    mccmnc_tuple: "62304"
+  }
+}
+carrier_id {
+  canonical_id: 2199
+  carrier_name: "Hits-GE"
+  carrier_attribute {
+    mccmnc_tuple: "62703"
+  }
+}
+carrier_id {
+  canonical_id: 2200
+  carrier_name: "Azur"
+  carrier_attribute {
+    mccmnc_tuple: "62804"
+  }
+}
+carrier_id {
+  canonical_id: 2201
+  carrier_name: "MOVICEL"
+  carrier_attribute {
+    mccmnc_tuple: "63104"
+  }
+}
+carrier_id {
+  canonical_id: 2202
+  carrier_name: "Sudani"
+  carrier_attribute {
+    mccmnc_tuple: "63407"
+  }
+}
+carrier_id {
+  canonical_id: 2203
+  carrier_name: "Tigo"
+  carrier_attribute {
+    mccmnc_tuple: "63513"
+  }
+}
+carrier_id {
+  canonical_id: 2204
+  carrier_name: "Airtel"
+  carrier_attribute {
+    mccmnc_tuple: "63514"
+  }
+}
+carrier_id {
+  canonical_id: 2205
+  carrier_name: "Telesom"
+  carrier_attribute {
+    mccmnc_tuple: "63701"
+  }
+}
+carrier_id {
+  canonical_id: 2206
+  carrier_name: "Nationlink"
+  carrier_attribute {
+    mccmnc_tuple: "63710"
+  }
+}
+carrier_id {
+  canonical_id: 2207
+  carrier_name: "Somtel"
+  carrier_attribute {
+    mccmnc_tuple: "63771"
+  }
+}
+carrier_id {
+  canonical_id: 2208
+  carrier_name: "Telcom"
+  carrier_attribute {
+    mccmnc_tuple: "63782"
+  }
+}
+carrier_id {
+  canonical_id: 2209
+  carrier_name: "Yu"
+  carrier_attribute {
+    mccmnc_tuple: "63905"
+  }
+}
+carrier_id {
+  canonical_id: 2210
+  carrier_name: "Telkom"
+  carrier_attribute {
+    mccmnc_tuple: "63907"
+  }
+}
+carrier_id {
+  canonical_id: 2211
+  carrier_name: "Lumitel/Viettel"
+  carrier_attribute {
+    mccmnc_tuple: "64208"
+  }
+}
+carrier_id {
+  canonical_id: 2212
+  carrier_name: "Leo"
+  carrier_attribute {
+    mccmnc_tuple: "64282"
+  }
+}
+carrier_id {
+  canonical_id: 2213
+  carrier_name: "Movitel"
+  carrier_attribute {
+    mccmnc_tuple: "64303"
+  }
+}
+carrier_id {
+  canonical_id: 2214
+  carrier_name: "switch"
+  carrier_attribute {
+    mccmnc_tuple: "64902"
+  }
+}
+carrier_id {
+  canonical_id: 2215
+  carrier_name: "Porto Seguro TeleComumicacoes"
+  carrier_attribute {
+    mccmnc_tuple: "72454"
+  }
+}
+carrier_id {
+  canonical_id: 2216
+  carrier_name: "VTR Banda Ancha SA"
+  carrier_attribute {
+    mccmnc_tuple: "73008"
+  }
+}
+carrier_id {
+  canonical_id: 2217
+  carrier_name: "GT&T Cellink Plus"
+  carrier_attribute {
+    mccmnc_tuple: "73802"
+    mccmnc_tuple: "738002"
+  }
+}
+carrier_id {
+  canonical_id: 2218
+  carrier_name: "ETB 4G"
+  carrier_attribute {
+    mccmnc_tuple: "732187"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "732103"
+    spn: "ETB MOVI"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "732111"
+    spn: "ETB MOVIL"
+  }
+}
+carrier_id {
+  canonical_id: 2219
+  carrier_name: "Digicel"
+  carrier_attribute {
+    mccmnc_tuple: "54105"
+  }
+}
+carrier_id {
+  canonical_id: 2220
+  carrier_name: "Digicel"
+  carrier_attribute {
+    mccmnc_tuple: "53988"
+  }
+}
+carrier_id {
+  canonical_id: 2221
+  carrier_name: "Etisalat"
+  carrier_attribute {
+    mccmnc_tuple: "41250"
+  }
+}
+carrier_id {
+  canonical_id: 2222
+  carrier_name: "Globacom"
+  carrier_attribute {
+    mccmnc_tuple: "62007"
+  }
+}
+carrier_id {
+  canonical_id: 2223
+  carrier_name: "Grenada:Lime"
+  carrier_attribute {
+    mccmnc_tuple: "352110"
+  }
+}
+carrier_id {
+  canonical_id: 2224
+  carrier_name: "Cable & Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "33818"
+    mccmnc_tuple: "338180"
+  }
+}
+carrier_id {
+  canonical_id: 2225
+  carrier_name: "MTN/Areeba"
+  carrier_attribute {
+    mccmnc_tuple: "61104"
+  }
+}
+carrier_id {
+  canonical_id: 2227
+  carrier_name: "Tigo/Milicom/Tchad Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "62203"
+  }
+}
+carrier_id {
+  canonical_id: 2229
+  carrier_name: "Rebtel"
+  carrier_attribute {
+    mccmnc_tuple: "26044"
+  }
+}
+carrier_id {
+  canonical_id: 2230
+  carrier_name: "bulsatcom"
+  carrier_attribute {
+    mccmnc_tuple: "28411"
+  }
+}
+carrier_id {
+  canonical_id: 2231
+  carrier_name: "MAX TELECOM"
+  carrier_attribute {
+    mccmnc_tuple: "28413"
+  }
+}
+carrier_id {
+  canonical_id: 2232
+  carrier_name: "BICS"
+  carrier_attribute {
+    mccmnc_tuple: "29509"
+    spn: "BICS"
+  }
+}
+carrier_id {
+  canonical_id: 2233
+  carrier_name: "EMnify"
+  carrier_attribute {
+    mccmnc_tuple: "29509"
+  }
+}
+carrier_id {
+  canonical_id: 2234
+  carrier_name: "Itisaluna"
+  carrier_attribute {
+    mccmnc_tuple: "41862"
+  }
+}
+carrier_id {
+  canonical_id: 2235
+  carrier_name: "Perfectum Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "43406"
+  }
+}
+carrier_id {
+  canonical_id: 2236
+  carrier_name: "SEATEL"
+  carrier_attribute {
+    mccmnc_tuple: "45611"
+  }
+}
+carrier_id {
+  canonical_id: 2237
+  carrier_name: "China Telecom"
+  carrier_attribute {
+    mccmnc_tuple: "46003"
+    mccmnc_tuple: "46011"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20404"
+    spn: "中国电信"
+  }
+}
+carrier_id {
+  canonical_id: 2238
+  carrier_name: "Sunsurf"
+  carrier_attribute {
+    mccmnc_tuple: "52504"
+  }
+}
+carrier_id {
+  canonical_id: 2239
+  carrier_name: "AIL"
+  carrier_attribute {
+    mccmnc_tuple: "54100"
+  }
+}
+carrier_id {
+  canonical_id: 2240
+  carrier_name: "Kiribati - TSKL"
+  carrier_attribute {
+    mccmnc_tuple: "54501"
+  }
+}
+carrier_id {
+  canonical_id: 2241
+  carrier_name: "Guinetel"
+  carrier_attribute {
+    mccmnc_tuple: "63207"
+  }
+}
+carrier_id {
+  canonical_id: 2242
+  carrier_name: "Privet"
+  carrier_attribute {
+    mccmnc_tuple: "63409"
+  }
+}
+carrier_id {
+  canonical_id: 2243
+  carrier_name: "Rwandatel"
+  carrier_attribute {
+    mccmnc_tuple: "63512"
+  }
+}
+carrier_id {
+  canonical_id: 2244
+  carrier_name: "Somafone"
+  carrier_attribute {
+    mccmnc_tuple: "63704"
+  }
+}
+carrier_id {
+  canonical_id: 2245
+  carrier_name: "Hormuud"
+  carrier_attribute {
+    mccmnc_tuple: "63725"
+  }
+}
+carrier_id {
+  canonical_id: 2246
+  carrier_name: "Unitel"
+  carrier_attribute {
+    mccmnc_tuple: "63757"
+  }
+}
+carrier_id {
+  canonical_id: 2247
+  carrier_name: "Eritel"
+  carrier_attribute {
+    mccmnc_tuple: "65701"
+  }
+}
+carrier_id {
+  canonical_id: 2248
+  carrier_name: "Digicel"
+  carrier_attribute {
+    mccmnc_tuple: "70804"
+    mccmnc_tuple: "708040"
+  }
+}
+carrier_id {
+  canonical_id: 2249
+  carrier_name: "Quam_WEB"
+  carrier_attribute {
+    mccmnc_tuple: "72201"
+    spn: "QUAM"
+    spn: "CELULAR"
+  }
+}
+carrier_id {
+  canonical_id: 2250
+  carrier_name: "Argentina:Nuestro"
+  carrier_attribute {
+    mccmnc_tuple: "72236"
+  }
+}
+carrier_id {
+  canonical_id: 2251
+  carrier_name: "Sberbank-Telecom"
+  carrier_attribute {
+    mccmnc_tuple: "250050"
+  }
+}
+carrier_id {
+  canonical_id: 2252
+  carrier_name: "EastLink"
+  carrier_attribute {
+    mccmnc_tuple: "302270"
+  }
+}
+carrier_id {
+  canonical_id: 2253
+  carrier_name: "ALU Test-SIM"
+  carrier_attribute {
+    mccmnc_tuple: "310028"
+  }
+}
+carrier_id {
+  canonical_id: 2254
+  carrier_name: "etex"
+  carrier_attribute {
+    mccmnc_tuple: "310035"
+  }
+}
+carrier_id {
+  canonical_id: 2255
+  carrier_name: "NexTech Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "311100"
+  }
+}
+carrier_id {
+  canonical_id: 2256
+  carrier_name: "TelAlaska Cellular"
+  carrier_attribute {
+    mccmnc_tuple: "311740"
+  }
+}
+carrier_id {
+  canonical_id: 2257
+  carrier_name: "Cleartalk"
+  carrier_attribute {
+    mccmnc_tuple: "311750"
+  }
+}
+carrier_id {
+  canonical_id: 2258
+  carrier_name: "MobileNation"
+  carrier_attribute {
+    mccmnc_tuple: "311910"
+  }
+}
+carrier_id {
+  canonical_id: 2259
+  carrier_name: "Syringa"
+  carrier_attribute {
+    mccmnc_tuple: "311930"
+  }
+}
+carrier_id {
+  canonical_id: 2260
+  carrier_name: "NexTech Ota"
+  carrier_attribute {
+    mccmnc_tuple: "312420"
+  }
+}
+carrier_id {
+  canonical_id: 2261
+  carrier_name: "Blue Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "312570"
+  }
+}
+carrier_id {
+  canonical_id: 2262
+  carrier_name: "Open Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "330000"
+  }
+}
+carrier_id {
+  canonical_id: 2263
+  carrier_name: "Claro"
+  carrier_attribute {
+    mccmnc_tuple: "338070"
+  }
+}
+carrier_id {
+  canonical_id: 2264
+  carrier_name: "Videocon"
+  carrier_attribute {
+    mccmnc_tuple: "405823"
+    mccmnc_tuple: "405824"
+    mccmnc_tuple: "405825"
+    mccmnc_tuple: "405826"
+    mccmnc_tuple: "405827"
+    mccmnc_tuple: "405828"
+    mccmnc_tuple: "405829"
+    mccmnc_tuple: "405830"
+    mccmnc_tuple: "405832"
+    mccmnc_tuple: "405833"
+    mccmnc_tuple: "405834"
+    mccmnc_tuple: "405835"
+    mccmnc_tuple: "405836"
+    mccmnc_tuple: "405837"
+    mccmnc_tuple: "405838"
+    mccmnc_tuple: "405841"
+    mccmnc_tuple: "405842"
+    mccmnc_tuple: "405843"
+    mccmnc_tuple: "405932"
+  }
+}
+carrier_id {
+  canonical_id: 2265
+  carrier_name: "STEL"
+  carrier_attribute {
+    mccmnc_tuple: "405881"
+    mccmnc_tuple: "405882"
+    mccmnc_tuple: "405883"
+    mccmnc_tuple: "405884"
+    mccmnc_tuple: "405885"
+    mccmnc_tuple: "405886"
+  }
+}
+carrier_id {
+  canonical_id: 2266
+  carrier_name: "Cheers"
+  carrier_attribute {
+    mccmnc_tuple: "405912"
+    mccmnc_tuple: "405913"
+    mccmnc_tuple: "405914"
+    mccmnc_tuple: "405915"
+    mccmnc_tuple: "405916"
+    mccmnc_tuple: "405917"
+    mccmnc_tuple: "405918"
+    mccmnc_tuple: "405919"
+    mccmnc_tuple: "405920"
+    mccmnc_tuple: "405921"
+    mccmnc_tuple: "405922"
+    mccmnc_tuple: "405923"
+    mccmnc_tuple: "405930"
+  }
+}
+carrier_id {
+  canonical_id: 2267
+  carrier_name: "Tuyo"
+  carrier_attribute {
+    mccmnc_tuple: "712019"
+    mccmnc_tuple: "712190"
+  }
+}
+carrier_id {
+  canonical_id: 2268
+  carrier_name: "Viettel"
+  carrier_attribute {
+    mccmnc_tuple: "51403"
+  }
+}
+carrier_id {
+  canonical_id: 2270
+  carrier_name: "Telenet"
+  carrier_attribute {
+    mccmnc_tuple: "20601"
+    imsi_prefix_xpattern: "20601889"
+  }
+}
+carrier_id {
+  canonical_id: 2271
+  carrier_name: "Transatel"
+  carrier_attribute {
+    mccmnc_tuple: "20610"
+    spn: "BE-Transatel"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "20610"
+    gid1: "BB00"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "22803"
+    spn: "CH-Transatel"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "22803"
+    gid1: "BB00"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "27077"
+    gid1: "BB00"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "27077"
+    spn: "LU-Transatel"
+  }
+}
+carrier_id {
+  canonical_id: 2272
+  carrier_name: "Auchan"
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    spn: "A MOBILE"
+  }
+}
+carrier_id {
+  canonical_id: 2273
+  carrier_name: "Reglo"
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    spn: "LeclercMobile"
+    spn: "RegloMobile"
+  }
+}
+carrier_id {
+  canonical_id: 2274
+  carrier_name: "La Poste"
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    gid1: "4C"
+  }
+}
+carrier_id {
+  canonical_id: 2275
+  carrier_name: "Darty"
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    gid1: "44"
+  }
+}
+carrier_id {
+  canonical_id: 2276
+  carrier_name: "Keyyo"
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    spn: "Keyyo Mobile"
+  }
+}
+carrier_id {
+  canonical_id: 2277
+  carrier_name: "Zero forfait"
+  carrier_attribute {
+    mccmnc_tuple: "20810"
+    spn: "ZERO FORFAIT"
+  }
+}
+carrier_id {
+  canonical_id: 2278
+  carrier_name: "R"
+  carrier_attribute {
+    mccmnc_tuple: "21406"
+    imsi_prefix_xpattern: "2140612"
+  }
+}
+carrier_id {
+  canonical_id: 2279
+  carrier_name: "eroskimovil"
+  carrier_attribute {
+    mccmnc_tuple: "21406"
+    imsi_prefix_xpattern: "2140606"
+  }
+}
+carrier_id {
+  canonical_id: 2280
+  carrier_name: "pepephone"
+  carrier_attribute {
+    mccmnc_tuple: "21406"
+    spn: "pepephone"
+  }
+}
+carrier_id {
+  canonical_id: 2281
+  carrier_name: "T-2"
+  carrier_attribute {
+    mccmnc_tuple: "21407"
+    imsi_prefix_xpattern: "2140759577"
+    imsi_prefix_xpattern: "2140796692"
+  }
+}
+carrier_id {
+  canonical_id: 2282
+  carrier_name: "Noverca"
+  carrier_attribute {
+    mccmnc_tuple: "22201"
+    spn: "Noverca"
+  }
+}
+carrier_id {
+  canonical_id: 2283
+  carrier_name: "LIFE"
+  carrier_attribute {
+    mccmnc_tuple: "23433"
+    spn: "LIFE"
+  }
+}
+carrier_id {
+  canonical_id: 2284
+  carrier_name: "Telmore"
+  carrier_attribute {
+    mccmnc_tuple: "23801"
+    spn: "TELMORE"
+  }
+}
+carrier_id {
+  canonical_id: 2285
+  carrier_name: "Call Me"
+  carrier_attribute {
+    mccmnc_tuple: "23820"
+    spn: "Call me"
+  }
+}
+carrier_id {
+  canonical_id: 2286
+  carrier_name: "DLG Tele"
+  carrier_attribute {
+    mccmnc_tuple: "23820"
+    spn: "DLG Tele"
+  }
+}
+carrier_id {
+  canonical_id: 2287
+  carrier_name: "Halebop"
+  carrier_attribute {
+    mccmnc_tuple: "24001"
+    imsi_prefix_xpattern: "240017"
+  }
+  carrier_attribute {
+    mccmnc_tuple: "24005"
+    spn: "Halebop"
+  }
+}
+carrier_id {
+  canonical_id: 2288
+  carrier_name: "GSC"
+  carrier_attribute {
+    mccmnc_tuple: "311590"
+    spn: "gsc"
+  }
+}
+carrier_id {
+  canonical_id: 2289
+  carrier_name: "Cable & Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "348170"
+  }
+}
+carrier_id {
+  canonical_id: 2290
+  carrier_name: "Cable & Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "366110"
+  }
+}
+carrier_id {
+  canonical_id: 2291
+  carrier_name: "Cable & Wireless West Indies Ltd (Turks & Caicos)"
+  carrier_attribute {
+    mccmnc_tuple: "376350"
+  }
+}
+carrier_id {
+  canonical_id: 2292
+  carrier_name: "Cable & Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "354860"
+  }
+}
+carrier_id {
+  canonical_id: 2293
+  carrier_name: "Cable & Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "358110"
+  }
+}
+carrier_id {
+  canonical_id: 2294
+  carrier_name: "Cable & Wireless (St. Vincent & the Grenadines) Ltd"
+  carrier_attribute {
+    mccmnc_tuple: "360110"
+  }
+}
+carrier_id {
+  canonical_id: 2295
+  carrier_name: "Cable & Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "365840"
+  }
+}
+carrier_id {
+  canonical_id: 2297
+  carrier_name: "Happy"
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    spn: "Happy"
+  }
+}
+carrier_id {
+  canonical_id: 2298
+  carrier_name: "RACC"
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    spn: "RACC"
+  }
+}
+carrier_id {
+  canonical_id: 2299
+  carrier_name: "CABLE movil"
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    spn: "CABLE movil"
+  }
+}
+carrier_id {
+  canonical_id: 2300
+  carrier_name: "MASMovil"
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    spn: "MASMovil"
+  }
+}
+carrier_id {
+  canonical_id: 2301
+  carrier_name: "Ibercom"
+  carrier_attribute {
+    mccmnc_tuple: "21403"
+    spn: "Ibercom"
+  }
+}
+carrier_id {
+  canonical_id: 2303
+  carrier_name: "PosteMobile"
+  carrier_attribute {
+    mccmnc_tuple: "22210"
+    spn: "PosteMobile"
+  }
+}
+carrier_id {
+  canonical_id: 2304
+  carrier_name: "ERG"
+  carrier_attribute {
+    mccmnc_tuple: "22210"
+    spn: "ERG"
+  }
+}
+carrier_id {
+  canonical_id: 2308
+  carrier_name: "Sainsbury's"
+  carrier_attribute {
+    mccmnc_tuple: "23415"
+    spn: "Sainsbury's"
+  }
+}
+carrier_id {
+  canonical_id: 2309
+  carrier_name: "Lebara"
+  carrier_attribute {
+    mccmnc_tuple: "23415"
+    spn: "Lebara"
+  }
+}
+carrier_id {
+  canonical_id: 2310
+  carrier_name: "Debitel"
+  carrier_attribute {
+    mccmnc_tuple: "26201"
+    spn: "debitel"
+  }
+}
+carrier_id {
+  canonical_id: 2315
+  carrier_name: "Norvado"
+  carrier_attribute {
+    mccmnc_tuple: "311500"
+    spn: "Norvado Wireless"
+    spn: "Norvado Wireless RPA"
+    spn: "Norvado Wireless RPT"
+    spn: "Norvado Wireless RPO"
+  }
+}
+carrier_id {
+  canonical_id: 2316
+  carrier_name: "Mosaic Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "311500"
+    spn: "Mosaic RPA"
+    spn: "Mosaic Mobile"
+    spn: "Mosaic RPT"
+    spn: "Mosaic RPO"
+  }
+}
+carrier_id {
+  canonical_id: 2317
+  carrier_name: "Nemont"
+  carrier_attribute {
+    mccmnc_tuple: "311350"
+    spn: "nemont"
+  }
+}
+carrier_id {
+  canonical_id: 2318
+  carrier_name: "Bravado wireless"
+  carrier_attribute {
+    mccmnc_tuple: "311140"
+    spn: "sprocket"
+  }
+}
+carrier_id {
+  canonical_id: 2319
+  carrier_name: "Element Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "311070"
+    spn: "elementmobile"
+  }
+}
+carrier_id {
+  canonical_id: 2320
+  carrier_name: "strata"
+  carrier_attribute {
+    mccmnc_tuple: "310960"
+    spn: "strata"
+  }
+}
+carrier_id {
+  canonical_id: 2321
+  carrier_name: "southcentral"
+  carrier_attribute {
+    mccmnc_tuple: "310960"
+    spn: "southcentral"
+  }
+}
+carrier_id {
+  canonical_id: 2322
+  carrier_name: "snakeriver"
+  carrier_attribute {
+    mccmnc_tuple: "310960"
+    spn: "snakeriver"
+  }
+}
+carrier_id {
+  canonical_id: 2323
+  carrier_name: "silverstar"
+  carrier_attribute {
+    mccmnc_tuple: "310960"
+    spn: "silverstar"
+  }
+}
+carrier_id {
+  canonical_id: 2324
+  carrier_name: "NNTC Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "310960"
+    spn: "nntcwire"
+  }
+}
+carrier_id {
+  canonical_id: 2325
+  carrier_name: "Clear Sky Wireless"
+  carrier_attribute {
+    mccmnc_tuple: "310820"
+    spn: "nepa"
+  }
+}
+carrier_id {
+  canonical_id: 2326
+  carrier_name: "EMnify"
+  carrier_attribute {
+    mccmnc_tuple: "53703"
+    mccmnc_tuple: "29505"
+    spn: "EMnify"
+  }
+}
+carrier_id {
+  canonical_id: 2327
+  carrier_name: "Telemach"
+  carrier_attribute {
+    mccmnc_tuple: "29370"
+    imsi_prefix_xpattern: "29370029"
+  }
+}
+carrier_id {
+  canonical_id: 2328
+  carrier_name: "Fonic Prepaid"
+  carrier_attribute {
+    mccmnc_tuple: "26207"
+    imsi_prefix_xpattern: "26207515"
+  }
+}
+carrier_id {
+  canonical_id: 2329
+  carrier_name: "Lidl Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "26207"
+    imsi_prefix_xpattern: "26207520"
+  }
+}
+carrier_id {
+  canonical_id: 2330
+  carrier_name: "Tchibo"
+  carrier_attribute {
+    mccmnc_tuple: "26207"
+    imsi_prefix_xpattern: "26207500"
+  }
+}
+carrier_id {
+  canonical_id: 2331
+  carrier_name: "Djuice"
+  carrier_attribute {
+    mccmnc_tuple: "25503"
+    spn: "djuice"
+  }
+}
+carrier_id {
+  canonical_id: 2332
+  carrier_name: "Send"
+  carrier_attribute {
+    mccmnc_tuple: "24801"
+    imsi_prefix_xpattern: "248010x2"
+    imsi_prefix_xpattern: "248010x3"
+  }
+}
+carrier_id {
+  canonical_id: 2333
+  carrier_name: "Ventelo"
+  carrier_attribute {
+    mccmnc_tuple: "24201"
+    imsi_prefix_xpattern: "24201700"
+  }
+}
+carrier_id {
+  canonical_id: 2334
+  carrier_name: "Chess"
+  carrier_attribute {
+    mccmnc_tuple: "24202"
+    imsi_prefix_xpattern: "2420256"
+  }
+}
+carrier_id {
+  canonical_id: 2335
+  carrier_name: "Virgin"
+  carrier_attribute {
+    mccmnc_tuple: "65507"
+    imsi_prefix_xpattern: "6550710"
+  }
+}
+carrier_id {
+  canonical_id: 2336
+  carrier_name: "TrueMove H"
+  carrier_attribute {
+    mccmnc_tuple: "52000"
+    gid1: "01"
+  }
+}
+carrier_id {
+  canonical_id: 2337
+  carrier_name: "Movil exito"
+  carrier_attribute {
+    mccmnc_tuple: "732103"
+    mccmnc_tuple: "732111"
+    spn: "movil exito"
+  }
+}
+carrier_id {
+  canonical_id: 2338
+  carrier_name: "UNE"
+  carrier_attribute {
+    mccmnc_tuple: "732103"
+    mccmnc_tuple: "732111"
+    spn: "UNE"
+  }
+}
+carrier_id {
+  canonical_id: 2339
+  carrier_name: "Virgin Mobile"
+  carrier_attribute {
+    mccmnc_tuple: "732123"
+    spn: "Virgin Mobile"
+  }
+}
+version: 5
diff --git a/res/values-as/config.xml b/res/values-as/config.xml
deleted file mode 100644
index 99877a6..0000000
--- a/res/values-as/config.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="persist_apns_for_plmn">
-    <item msgid="6413072509259000954">"20404"</item>
-    <item msgid="5639159280778239123">"310004"</item>
-    <item msgid="3860605521380788028">"310120"</item>
-    <item msgid="537693705785480198">"311480"</item>
-  </string-array>
-</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
deleted file mode 100644
index 5a39f18..0000000
--- a/res/values-as/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" product="tablet" msgid="9194799012395299737">"ম\'বাইল নেটৱৰ্ক কনফিগাৰেশ্বন"</string>
-    <string name="app_label" product="default" msgid="8338087656149558019">"ফ\'ন আৰু বাৰ্তাৰ সঞ্চয়াগাৰ"</string>
-</resources>
diff --git a/res/values-or/config.xml b/res/values-or/config.xml
deleted file mode 100644
index 99877a6..0000000
--- a/res/values-or/config.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="persist_apns_for_plmn">
-    <item msgid="6413072509259000954">"20404"</item>
-    <item msgid="5639159280778239123">"310004"</item>
-    <item msgid="3860605521380788028">"310120"</item>
-    <item msgid="537693705785480198">"311480"</item>
-  </string-array>
-</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
deleted file mode 100644
index b004c4f..0000000
--- a/res/values-or/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" product="tablet" msgid="9194799012395299737">"ମୋବାଇଲ୍ ନେଟ୍‌ୱର୍କ କନଫିଗରେଶନ୍"</string>
-    <string name="app_label" product="default" msgid="8338087656149558019">"ଫୋନ୍ ଓ ମେସେଜିଙ୍ଗ ଷ୍ଟୋରେଜ୍"</string>
-</resources>
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index 1c2e5e5..7f2de12 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
@@ -74,7 +75,7 @@
     private static final String TAG = CarrierIdProvider.class.getSimpleName();
 
     private static final String DATABASE_NAME = "carrierIdentification.db";
-    private static final int DATABASE_VERSION = 3;
+    private static final int DATABASE_VERSION = 5;
 
     private static final String ASSETS_PB_FILE = "carrier_list.pb";
     private static final String VERSION_KEY = "version";
@@ -119,10 +120,15 @@
     * index 7: {@link CarrierId.All#ICCID_PREFIX}
     */
     private static final int ICCID_PREFIX_INDEX          = 7;
+
+    /**
+     * index 8: {@link CarrierId.All#PRIVILEGE_ACCESS_RULE}
+     */
+    private static final int PRIVILEGE_ACCESS_RULE       = 8;
     /**
      * ending index of carrier attribute list.
      */
-    private static final int CARRIER_ATTR_END_IDX        = ICCID_PREFIX_INDEX;
+    private static final int CARRIER_ATTR_END_IDX        = PRIVILEGE_ACCESS_RULE;
     /**
      * The authority string for the CarrierIdProvider
      */
@@ -139,15 +145,18 @@
             CarrierId.All.IMSI_PREFIX_XPATTERN,
             CarrierId.All.SPN,
             CarrierId.All.APN,
-            CarrierId.All.ICCID_PREFIX));
+            CarrierId.All.ICCID_PREFIX,
+            CarrierId.All.PRIVILEGE_ACCESS_RULE,
+            CarrierId.PARENT_CARRIER_ID));
 
     private CarrierIdDatabaseHelper mDbHelper;
 
     /**
      * Stores carrier id information for the current active subscriptions.
-     * Key is the active subId and entryValue is a pair of carrier id(int) and Carrier Name(String).
+     * Key is the active subId and entryValue is carrier id(int), mno carrier id (int) and
+     * carrier name(String).
      */
-    private final Map<Integer, Pair<Integer, String>> mCurrentSubscriptionMap =
+    private final Map<Integer, ContentValues> mCurrentSubscriptionMap =
             new ConcurrentHashMap<>();
 
     @VisibleForTesting
@@ -162,8 +171,10 @@
                 + CarrierId.All.SPN + " TEXT,"
                 + CarrierId.All.APN + " TEXT,"
                 + CarrierId.All.ICCID_PREFIX + " TEXT,"
+                + CarrierId.All.PRIVILEGE_ACCESS_RULE + " TEXT,"
                 + CarrierId.CARRIER_NAME + " TEXT,"
                 + CarrierId.CARRIER_ID + " INTEGER DEFAULT -1,"
+                + CarrierId.PARENT_CARRIER_ID + " INTEGER DEFAULT -1,"
                 + "UNIQUE (" + TextUtils.join(", ", CARRIERS_ID_UNIQUE_FIELDS) + "));";
     }
 
@@ -317,6 +328,7 @@
          */
         public CarrierIdDatabaseHelper(Context context) {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
+            setWriteAheadLoggingEnabled(false);
         }
 
         @Override
@@ -341,6 +353,9 @@
             if (oldVersion < DATABASE_VERSION) {
                 dropCarrierTable(db);
                 createCarrierTable(db);
+                // force rewrite carrier id db
+                setAppliedVersion(0);
+                updateDatabaseFromPb(db);
             }
         }
     }
@@ -403,7 +418,9 @@
     private void convertCarrierAttrToContentValues(ContentValues cv, List<ContentValues> cvs,
             CarrierIdProto.CarrierAttribute attr, int index) {
         if (index > CARRIER_ATTR_END_IDX) {
-            cvs.add(new ContentValues(cv));
+            ContentValues carrier = new ContentValues(cv);
+            if (!cvs.contains(carrier))
+            cvs.add(carrier);
             return;
         }
         boolean found = false;
@@ -426,7 +443,7 @@
                 break;
             case GID1_INDEX:
                 for (String str : attr.gid1) {
-                    cv.put(CarrierId.All.GID1, str);
+                    cv.put(CarrierId.All.GID1, str.toLowerCase());
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
                     cv.remove(CarrierId.All.GID1);
                     found = true;
@@ -434,7 +451,7 @@
                 break;
             case GID2_INDEX:
                 for (String str : attr.gid2) {
-                    cv.put(CarrierId.All.GID2, str);
+                    cv.put(CarrierId.All.GID2, str.toLowerCase());
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
                     cv.remove(CarrierId.All.GID2);
                     found = true;
@@ -450,7 +467,7 @@
                 break;
             case SPN_INDEX:
                 for (String str : attr.spn) {
-                    cv.put(CarrierId.All.SPN, str);
+                    cv.put(CarrierId.All.SPN, str.toLowerCase());
                     convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
                     cv.remove(CarrierId.All.SPN);
                     found = true;
@@ -472,6 +489,14 @@
                     found = true;
                 }
                 break;
+            case PRIVILEGE_ACCESS_RULE:
+                for (String str : attr.privilegeAccessRule) {
+                    cv.put(CarrierId.All.PRIVILEGE_ACCESS_RULE, str);
+                    convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+                    cv.remove(CarrierId.All.PRIVILEGE_ACCESS_RULE);
+                    found = true;
+                }
+                break;
             default:
                 Log.e(TAG, "unsupported index: " + index);
                 break;
@@ -584,9 +609,7 @@
             }
             return count;
         } else {
-            mCurrentSubscriptionMap.put(subId,
-                    new Pair(cv.getAsInteger(CarrierId.CARRIER_ID),
-                    cv.getAsString(CarrierId.CARRIER_NAME)));
+            mCurrentSubscriptionMap.put(subId, new ContentValues(cv));
             getContext().getContentResolver().notifyChange(CarrierId.CONTENT_URI, null);
             return 1;
         }
@@ -618,9 +641,11 @@
         for (int i = 0; i < c.getColumnCount(); i++) {
             final String columnName = c.getColumnName(i);
             if (CarrierId.CARRIER_ID.equals(columnName)) {
-                row.add(mCurrentSubscriptionMap.get(subId).first);
+                row.add(mCurrentSubscriptionMap.get(subId).get(CarrierId.CARRIER_ID));
             } else if (CarrierId.CARRIER_NAME.equals(columnName)) {
-                row.add(mCurrentSubscriptionMap.get(subId).second);
+                row.add(mCurrentSubscriptionMap.get(subId).get(CarrierId.CARRIER_NAME));
+            } else if (CarrierId.MNO_CARRIER_ID.equals(columnName)) {
+                row.add(mCurrentSubscriptionMap.get(subId).get(CarrierId.MNO_CARRIER_ID));
             } else {
                 throw new IllegalArgumentException("Invalid column " + projectionIn[i]);
             }
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index f4ae9cc..f7a446b 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -23,6 +23,8 @@
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.database.Cursor;
+import android.database.DatabaseErrorHandler;
+import android.database.DefaultDatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
@@ -239,6 +241,7 @@
 
     private static MmsSmsDatabaseHelper sDeInstance = null;
     private static MmsSmsDatabaseHelper sCeInstance = null;
+    private static MmsSmsDatabaseErrorHandler sDbErrorHandler = null;
 
     private static final String[] BIND_ARGS_NONE = new String[0];
 
@@ -258,8 +261,36 @@
     // cache for INITIAL_CREATE_DONE shared pref so access to it can be avoided when possible
     private static AtomicBoolean sInitialCreateDone = new AtomicBoolean(false);
 
-    private MmsSmsDatabaseHelper(Context context) {
-        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    // TODO(sahinc): Turn this to true once the schema finalizes, so that people can update their
+    // messaging databases. NOTE: move the switch/case update to the latest version of the database
+    // before turning this flag to true.
+    private static final boolean IS_RCS_TABLE_SCHEMA_CODE_COMPLETE = false;
+
+    /**
+     * The primary purpose of this DatabaseErrorHandler is to broadcast an intent on corruption and
+     * print a Slog.wtf so database corruption can be caught earlier.
+     */
+    private static class MmsSmsDatabaseErrorHandler implements DatabaseErrorHandler {
+        private DefaultDatabaseErrorHandler mDefaultDatabaseErrorHandler
+                = new DefaultDatabaseErrorHandler();
+        private Context mContext;
+
+        MmsSmsDatabaseErrorHandler(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public void onCorruption(SQLiteDatabase dbObj) {
+            String logMsg = "Corruption reported by sqlite on database: " + dbObj.getPath();
+            localLogWtf(logMsg);
+            sendDbLostIntent(mContext, true);
+            // Let the default error handler take other actions
+            mDefaultDatabaseErrorHandler.onCorruption(dbObj);
+        }
+    }
+
+    private MmsSmsDatabaseHelper(Context context, MmsSmsDatabaseErrorHandler dbErrorHandler) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION, dbErrorHandler);
         mContext = context;
         // Memory optimization - close idle connections after 30s of inactivity
         setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
@@ -270,12 +301,27 @@
         }
     }
 
+    private static synchronized MmsSmsDatabaseErrorHandler getDbErrorHandler(Context context) {
+        if (sDbErrorHandler == null) {
+            sDbErrorHandler = new MmsSmsDatabaseErrorHandler(context);
+        }
+        return sDbErrorHandler;
+    }
+
+    private static void sendDbLostIntent(Context context, boolean isCorrupted) {
+        // Broadcast ACTION_SMS_MMS_DB_LOST
+        Intent intent = new Intent(Sms.Intents.ACTION_SMS_MMS_DB_LOST);
+        intent.putExtra(Sms.Intents.EXTRA_IS_CORRUPTED, isCorrupted);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        context.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+    }
     /**
      * Returns a singleton helper for the combined MMS and SMS database in device encrypted storage.
      */
     /* package */ static synchronized MmsSmsDatabaseHelper getInstanceForDe(Context context) {
         if (sDeInstance == null) {
-            sDeInstance = new MmsSmsDatabaseHelper(ProviderUtil.getDeviceEncryptedContext(context));
+            Context deContext = ProviderUtil.getDeviceEncryptedContext(context);
+            sDeInstance = new MmsSmsDatabaseHelper(deContext, getDbErrorHandler(deContext));
         }
         return sDeInstance;
     }
@@ -287,8 +333,8 @@
     /* package */ static synchronized MmsSmsDatabaseHelper getInstanceForCe(Context context) {
         if (sCeInstance == null) {
             if (StorageManager.isFileEncryptedNativeOrEmulated()) {
-                sCeInstance = new MmsSmsDatabaseHelper(
-                    ProviderUtil.getCredentialEncryptedContext(context));
+                Context ceContext = ProviderUtil.getCredentialEncryptedContext(context);
+                sCeInstance = new MmsSmsDatabaseHelper(ceContext, getDbErrorHandler(ceContext));
             } else {
                 sCeInstance = getInstanceForDe(context);
             }
@@ -493,6 +539,7 @@
                 // disappeared mysteriously?
                 localLogWtf("onCreate: was already called once earlier");
                 intent.putExtra(Intents.EXTRA_IS_INITIAL_CREATE, false);
+                sendDbLostIntent(mContext, false);
             } else {
                 setInitialCreateDone();
                 intent.putExtra(Intents.EXTRA_IS_INITIAL_CREATE, true);
@@ -503,18 +550,23 @@
         createMmsTables(db);
         createSmsTables(db);
         createCommonTables(db);
+
+        if (IS_RCS_TABLE_SCHEMA_CODE_COMPLETE) {
+            RcsProviderHelper.createRcsTables(db);
+        }
+
         createCommonTriggers(db);
         createMmsTriggers(db);
         createWordsTables(db);
         createIndices(db);
     }
 
-    private void localLog(String logMsg) {
+    private static void localLog(String logMsg) {
         Log.d(TAG, logMsg);
         PhoneFactory.localLog(TAG, logMsg);
     }
 
-    private void localLogWtf(String logMsg) {
+    private static void localLogWtf(String logMsg) {
         Slog.wtf(TAG, logMsg);
         PhoneFactory.localLog(TAG, logMsg);
     }
@@ -1583,6 +1635,12 @@
             } finally {
                 db.endTransaction();
             }
+            // fall through
+        case 67:
+            if (currentVersion <= 67 || !IS_RCS_TABLE_SCHEMA_CODE_COMPLETE) {
+                return;
+            }
+            RcsProviderHelper.createRcsTables(db);
             return;
         }
 
diff --git a/src/com/android/providers/telephony/RcsProvider.java b/src/com/android/providers/telephony/RcsProvider.java
new file mode 100644
index 0000000..83ff130
--- /dev/null
+++ b/src/com/android/providers/telephony/RcsProvider.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.telephony;
+
+import static com.android.providers.telephony.RcsProviderHelper.ID;
+import static com.android.providers.telephony.RcsProviderHelper.THREAD_TABLE;
+
+import android.app.AppOpsManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * Content provider to handle RCS messages. The functionality here is similar to SmsProvider,
+ * MmsProvider etc. This is not meant to be public.
+ * @hide
+ */
+public class RcsProvider extends ContentProvider {
+    private final static String TAG = "RcsProvider";
+    static final String AUTHORITY = "rcs";
+    private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+
+    private static final int THREAD = 1;
+
+    SQLiteOpenHelper mDbOpenHelper;
+
+    static {
+        URL_MATCHER.addURI(AUTHORITY, "thread", THREAD);
+    }
+
+    @Override
+    public boolean onCreate() {
+        setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
+        // Use the credential encrypted mmssms.db for RCS messages.
+        mDbOpenHelper = MmsSmsDatabaseHelper.getInstanceForCe(getContext());
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        int match = URL_MATCHER.match(uri);
+        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+        SQLiteDatabase readableDatabase = mDbOpenHelper.getReadableDatabase();
+
+        switch (match) {
+            case THREAD:
+                RcsProviderHelper.buildThreadQuery(qb);
+                break;
+            default:
+                Log.e(TAG, "Invalid query: " + uri);
+        }
+
+        return qb.query(
+                readableDatabase, projection, selection, selectionArgs, null, null, sortOrder);
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        int match = URL_MATCHER.match(uri);
+        SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+
+        switch (match) {
+            case THREAD:
+                writableDatabase.insert(THREAD_TABLE, ID, values);
+                break;
+            default:
+                Log.e(TAG, "Invalid insert: " + uri);
+        }
+
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        int match = URL_MATCHER.match(uri);
+        int deletedCount = 0;
+        SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+
+        switch (match) {
+            case THREAD:
+                deletedCount = writableDatabase.delete(THREAD_TABLE, selection, selectionArgs);
+                break;
+            default:
+                Log.e(TAG, "Invalid delete: " + uri);
+        }
+
+        return deletedCount;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        int match = URL_MATCHER.match(uri);
+        int updatedCount = 0;
+        SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+
+        switch (match) {
+            case THREAD:
+                updatedCount = writableDatabase.update(
+                        THREAD_TABLE, values, selection, selectionArgs);
+                break;
+            default:
+                Log.e(TAG, "Invalid update: " + uri);
+        }
+
+        return updatedCount;
+    }
+}
diff --git a/src/com/android/providers/telephony/RcsProviderHelper.java b/src/com/android/providers/telephony/RcsProviderHelper.java
new file mode 100644
index 0000000..3966f53
--- /dev/null
+++ b/src/com/android/providers/telephony/RcsProviderHelper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.telephony;
+
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Constants and helpers for RcsProvider to keep the code clean.
+ * @hide
+ */
+class RcsProviderHelper {
+    static final String ID = "_id";
+    static final String THREAD_TABLE = "rcs_thread";
+    static final String OWNER_PARTICIPANT = "owner_participant";
+
+    @VisibleForTesting
+    public static void createRcsTables(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE " + THREAD_TABLE + " (" +
+                ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+                OWNER_PARTICIPANT + " INTEGER " +
+                ");");
+    }
+
+    static void buildThreadQuery(SQLiteQueryBuilder qb) {
+        qb.setTables(THREAD_TABLE);
+    }
+}
diff --git a/src/com/android/providers/telephony/ServiceStateProvider.java b/src/com/android/providers/telephony/ServiceStateProvider.java
index e589171..7f870b0 100644
--- a/src/com/android/providers/telephony/ServiceStateProvider.java
+++ b/src/com/android/providers/telephony/ServiceStateProvider.java
@@ -61,7 +61,6 @@
 import static android.provider.Telephony.ServiceStateTable.CDMA_ERI_ICON_INDEX;
 import static android.provider.Telephony.ServiceStateTable.CDMA_ERI_ICON_MODE;
 import static android.provider.Telephony.ServiceStateTable.IS_EMERGENCY_ONLY;
-import static android.provider.Telephony.ServiceStateTable.IS_DATA_ROAMING_FROM_REGISTRATION;
 import static android.provider.Telephony.ServiceStateTable.IS_USING_CARRIER_AGGREGATION;
 
 
@@ -94,7 +93,6 @@
         CDMA_ERI_ICON_INDEX,
         CDMA_ERI_ICON_MODE,
         IS_EMERGENCY_ONLY,
-        IS_DATA_ROAMING_FROM_REGISTRATION,
         IS_USING_CARRIER_AGGREGATION,
     };
 
@@ -153,8 +151,6 @@
             newSS.setCdmaEriIconIndex(values.getAsInteger(CDMA_ERI_ICON_INDEX));
             newSS.setCdmaEriIconMode(values.getAsInteger(CDMA_ERI_ICON_MODE));
             newSS.setEmergencyOnly(values.getAsBoolean(IS_EMERGENCY_ONLY));
-            newSS.setDataRoamingFromRegistration(
-                    values.getAsBoolean(IS_DATA_ROAMING_FROM_REGISTRATION));
             newSS.setIsUsingCarrierAggregation(values.getAsBoolean(IS_USING_CARRIER_AGGREGATION));
 
             // notify listeners
@@ -235,8 +231,6 @@
             final int cdma_eri_icon_index = ss.getCdmaEriIconIndex();
             final int cdma_eri_icon_mode = ss.getCdmaEriIconMode();
             final int is_emergency_only = (ss.isEmergencyOnly()) ? 1 : 0;
-            final int is_data_roaming_from_registration =
-                    (ss.getDataRoamingFromRegistration()) ? 1 : 0;
             final int is_using_carrier_aggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
 
             return buildSingleRowResult(projection, sColumns, new Object[] {
@@ -261,7 +255,6 @@
                         cdma_eri_icon_index,
                         cdma_eri_icon_mode,
                         is_emergency_only,
-                        is_data_roaming_from_registration,
                         is_using_carrier_aggregation,
             });
         }
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index 2b40d7e..95db869 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -464,7 +464,6 @@
 
         int match = sURLMatcher.match(url);
         String table = TABLE_SMS;
-        boolean notifyIfNotDefault = true;
 
         switch (match) {
             case SMS_ALL:
@@ -503,10 +502,6 @@
 
             case SMS_RAW_MESSAGE:
                 table = "raw";
-                // The raw table is used by the telephony layer for storing an sms before
-                // sending out a notification that an sms has arrived. We don't want to notify
-                // the default sms app of changes to this table.
-                notifyIfNotDefault = false;
                 break;
 
             case SMS_STATUS_PENDING:
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index df1e58c..b83dc05 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -26,28 +26,29 @@
 import static android.provider.Telephony.Carriers.CARRIER_DELETED_BUT_PRESENT_IN_XML;
 import static android.provider.Telephony.Carriers.CARRIER_EDITED;
 import static android.provider.Telephony.Carriers.CARRIER_ENABLED;
+import static android.provider.Telephony.Carriers.CARRIER_ID;
 import static android.provider.Telephony.Carriers.CONTENT_URI;
 import static android.provider.Telephony.Carriers.CURRENT;
 import static android.provider.Telephony.Carriers.DEFAULT_SORT_ORDER;
-import static android.provider.Telephony.Carriers.EDITED;
-import static android.provider.Telephony.Carriers.MAX_CONNS;
-import static android.provider.Telephony.Carriers.MAX_CONNS_TIME;
+import static android.provider.Telephony.Carriers.EDITED_STATUS;
+import static android.provider.Telephony.Carriers.MAX_CONNECTIONS;
+import static android.provider.Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS;
 import static android.provider.Telephony.Carriers.MCC;
 import static android.provider.Telephony.Carriers.MMSC;
 import static android.provider.Telephony.Carriers.MMSPORT;
 import static android.provider.Telephony.Carriers.MMSPROXY;
 import static android.provider.Telephony.Carriers.MNC;
-import static android.provider.Telephony.Carriers.MODEM_COGNITIVE;
+import static android.provider.Telephony.Carriers.MODEM_PERSIST;
 import static android.provider.Telephony.Carriers.MTU;
 import static android.provider.Telephony.Carriers.MVNO_MATCH_DATA;
 import static android.provider.Telephony.Carriers.MVNO_TYPE;
 import static android.provider.Telephony.Carriers.NAME;
 import static android.provider.Telephony.Carriers.NETWORK_TYPE_BITMASK;
-import static android.provider.Telephony.Carriers.NO_SET_SET;
+import static android.provider.Telephony.Carriers.NO_APN_SET_ID;
 import static android.provider.Telephony.Carriers.NUMERIC;
 import static android.provider.Telephony.Carriers.OWNED_BY;
-import static android.provider.Telephony.Carriers.OWNED_BY_OTHERS;
 import static android.provider.Telephony.Carriers.OWNED_BY_DPC;
+import static android.provider.Telephony.Carriers.OWNED_BY_OTHERS;
 import static android.provider.Telephony.Carriers.PASSWORD;
 import static android.provider.Telephony.Carriers.PORT;
 import static android.provider.Telephony.Carriers.PROFILE_ID;
@@ -64,11 +65,12 @@
 import static android.provider.Telephony.Carriers.USER_EDITABLE;
 import static android.provider.Telephony.Carriers.USER_EDITED;
 import static android.provider.Telephony.Carriers.USER_VISIBLE;
-import static android.provider.Telephony.Carriers.WAIT_TIME;
+import static android.provider.Telephony.Carriers.WAIT_TIME_RETRY;
 import static android.provider.Telephony.Carriers._ID;
 
 import android.content.ComponentName;
 import android.content.ContentProvider;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
@@ -95,10 +97,12 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.Telephony;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -108,7 +112,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IApnSourceService;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.dataconnection.ApnSetting;
+import com.android.internal.telephony.dataconnection.ApnSettingUtils;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.util.XmlUtils;
@@ -116,15 +120,21 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
+import java.util.zip.CRC32;
 
 public class TelephonyProvider extends ContentProvider
 {
@@ -133,7 +143,7 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false; // STOPSHIP if true
 
-    private static final int DATABASE_VERSION = 26 << 16;
+    private static final int DATABASE_VERSION = 32 << 16;
     private static final int URL_UNKNOWN = 0;
     private static final int URL_TELEPHONY = 1;
     private static final int URL_CURRENT = 2;
@@ -157,7 +167,9 @@
     private static final int URL_ENFORCE_MANAGED = 20;
     private static final int URL_PREFERAPNSET = 21;
     private static final int URL_PREFERAPNSET_USING_SUBID = 22;
-
+    private static final int URL_SIM_APN_LIST = 23;
+    private static final int URL_SIM_APN_LIST_ID = 24;
+    private static final int URL_FILTERED_USING_SUBID = 25;
 
     private static final String TAG = "TelephonyProvider";
     private static final String CARRIERS_TABLE = "carriers";
@@ -194,24 +206,24 @@
     private static final ContentValues s_currentNullMap;
     private static final ContentValues s_currentSetMap;
 
-    private static final String IS_UNEDITED = EDITED + "=" + UNEDITED;
-    private static final String IS_EDITED = EDITED + "!=" + UNEDITED;
-    private static final String IS_USER_EDITED = EDITED + "=" + USER_EDITED;
-    private static final String IS_NOT_USER_EDITED = EDITED + "!=" + USER_EDITED;
-    private static final String IS_USER_DELETED = EDITED + "=" + USER_DELETED;
-    private static final String IS_NOT_USER_DELETED = EDITED + "!=" + USER_DELETED;
+    private static final String IS_UNEDITED = EDITED_STATUS + "=" + UNEDITED;
+    private static final String IS_EDITED = EDITED_STATUS + "!=" + UNEDITED;
+    private static final String IS_USER_EDITED = EDITED_STATUS + "=" + USER_EDITED;
+    private static final String IS_NOT_USER_EDITED = EDITED_STATUS + "!=" + USER_EDITED;
+    private static final String IS_USER_DELETED = EDITED_STATUS + "=" + USER_DELETED;
+    private static final String IS_NOT_USER_DELETED = EDITED_STATUS + "!=" + USER_DELETED;
     private static final String IS_USER_DELETED_BUT_PRESENT_IN_XML =
-            EDITED + "=" + USER_DELETED_BUT_PRESENT_IN_XML;
+            EDITED_STATUS + "=" + USER_DELETED_BUT_PRESENT_IN_XML;
     private static final String IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML =
-            EDITED + "!=" + USER_DELETED_BUT_PRESENT_IN_XML;
-    private static final String IS_CARRIER_EDITED = EDITED + "=" + CARRIER_EDITED;
-    private static final String IS_NOT_CARRIER_EDITED = EDITED + "!=" + CARRIER_EDITED;
-    private static final String IS_CARRIER_DELETED = EDITED + "=" + CARRIER_DELETED;
-    private static final String IS_NOT_CARRIER_DELETED = EDITED + "!=" + CARRIER_DELETED;
+            EDITED_STATUS + "!=" + USER_DELETED_BUT_PRESENT_IN_XML;
+    private static final String IS_CARRIER_EDITED = EDITED_STATUS + "=" + CARRIER_EDITED;
+    private static final String IS_NOT_CARRIER_EDITED = EDITED_STATUS + "!=" + CARRIER_EDITED;
+    private static final String IS_CARRIER_DELETED = EDITED_STATUS + "=" + CARRIER_DELETED;
+    private static final String IS_NOT_CARRIER_DELETED = EDITED_STATUS + "!=" + CARRIER_DELETED;
     private static final String IS_CARRIER_DELETED_BUT_PRESENT_IN_XML =
-            EDITED + "=" + CARRIER_DELETED_BUT_PRESENT_IN_XML;
+            EDITED_STATUS + "=" + CARRIER_DELETED_BUT_PRESENT_IN_XML;
     private static final String IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML =
-            EDITED + "!=" + CARRIER_DELETED_BUT_PRESENT_IN_XML;
+            EDITED_STATUS + "!=" + CARRIER_DELETED_BUT_PRESENT_IN_XML;
     private static final String IS_OWNED_BY_DPC = OWNED_BY + "=" + OWNED_BY_DPC;
     private static final String IS_NOT_OWNED_BY_DPC = OWNED_BY + "!=" + OWNED_BY_DPC;
 
@@ -220,6 +232,7 @@
 
     private static final int INVALID_APN_ID = -1;
     private static final List<String> CARRIERS_UNIQUE_FIELDS = new ArrayList<String>();
+    private static final Set<String> CARRIERS_BOOLEAN_FIELDS = new HashSet<String>();
     private static final Map<String, String> CARRIERS_UNIQUE_FIELDS_DEFAULTS = new HashMap();
 
     @VisibleForTesting
@@ -254,9 +267,19 @@
         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ROAMING_PROTOCOL, "IP");
         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(USER_EDITABLE, "1");
         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(OWNED_BY, String.valueOf(OWNED_BY_OTHERS));
-        CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN_SET_ID, String.valueOf(NO_SET_SET));
+        CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN_SET_ID, String.valueOf(NO_APN_SET_ID));
+        CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ID,
+                String.valueOf(TelephonyManager.UNKNOWN_CARRIER_ID));
 
         CARRIERS_UNIQUE_FIELDS.addAll(CARRIERS_UNIQUE_FIELDS_DEFAULTS.keySet());
+
+        // SQLite databases store bools as ints but the ContentValues objects passed in through
+        // queries use bools. As a result there is some special handling of boolean fields within
+        // the TelephonyProvider.
+        CARRIERS_BOOLEAN_FIELDS.add(CARRIER_ENABLED);
+        CARRIERS_BOOLEAN_FIELDS.add(MODEM_PERSIST);
+        CARRIERS_BOOLEAN_FIELDS.add(USER_VISIBLE);
+        CARRIERS_BOOLEAN_FIELDS.add(USER_EDITABLE);
     }
 
     @VisibleForTesting
@@ -267,6 +290,7 @@
                 NUMERIC + " TEXT DEFAULT ''," +
                 MCC + " TEXT DEFAULT ''," +
                 MNC + " TEXT DEFAULT ''," +
+                CARRIER_ID + " INTEGER DEFAULT " + TelephonyManager.UNKNOWN_CARRIER_ID  + "," +
                 APN + " TEXT DEFAULT ''," +
                 USER + " TEXT DEFAULT ''," +
                 SERVER + " TEXT DEFAULT ''," +
@@ -281,25 +305,25 @@
                 CURRENT + " INTEGER," +
                 PROTOCOL + " TEXT DEFAULT " + DEFAULT_PROTOCOL + "," +
                 ROAMING_PROTOCOL + " TEXT DEFAULT " + DEFAULT_ROAMING_PROTOCOL + "," +
-                CARRIER_ENABLED + " BOOLEAN DEFAULT 1," +
+                CARRIER_ENABLED + " BOOLEAN DEFAULT 1," + // SQLite databases store bools as ints
                 BEARER + " INTEGER DEFAULT 0," +
                 BEARER_BITMASK + " INTEGER DEFAULT 0," +
                 NETWORK_TYPE_BITMASK + " INTEGER DEFAULT 0," +
                 MVNO_TYPE + " TEXT DEFAULT ''," +
                 MVNO_MATCH_DATA + " TEXT DEFAULT ''," +
-                SUBSCRIPTION_ID + " INTEGER DEFAULT "
-                + SubscriptionManager.INVALID_SUBSCRIPTION_ID + "," +
+                SUBSCRIPTION_ID + " INTEGER DEFAULT " +
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID + "," +
                 PROFILE_ID + " INTEGER DEFAULT 0," +
-                MODEM_COGNITIVE + " BOOLEAN DEFAULT 0," +
-                MAX_CONNS + " INTEGER DEFAULT 0," +
-                WAIT_TIME + " INTEGER DEFAULT 0," +
-                MAX_CONNS_TIME + " INTEGER DEFAULT 0," +
+                MODEM_PERSIST + " BOOLEAN DEFAULT 0," +
+                MAX_CONNECTIONS + " INTEGER DEFAULT 0," +
+                WAIT_TIME_RETRY + " INTEGER DEFAULT 0," +
+                TIME_LIMIT_FOR_MAX_CONNECTIONS + " INTEGER DEFAULT 0," +
                 MTU + " INTEGER DEFAULT 0," +
-                EDITED + " INTEGER DEFAULT " + UNEDITED + "," +
+                EDITED_STATUS + " INTEGER DEFAULT " + UNEDITED + "," +
                 USER_VISIBLE + " BOOLEAN DEFAULT 1," +
                 USER_EDITABLE + " BOOLEAN DEFAULT 1," +
                 OWNED_BY + " INTEGER DEFAULT " + OWNED_BY_OTHERS + "," +
-                APN_SET_ID + " INTEGER DEFAULT " + NO_SET_SET + "," +
+                APN_SET_ID + " INTEGER DEFAULT " + NO_APN_SET_ID + "," +
                 // Uniqueness collisions are used to trigger merge code so if a field is listed
                 // here it means we will accept both (user edited + new apn_conf definition)
                 // Columns not included in UNIQUE constraint: name, current, edited,
@@ -330,6 +354,8 @@
                 + " INTEGER DEFAULT " + SubscriptionManager.DATA_ROAMING_DEFAULT + ","
                 + SubscriptionManager.MCC + " INTEGER DEFAULT 0,"
                 + SubscriptionManager.MNC + " INTEGER DEFAULT 0,"
+                + SubscriptionManager.MCC_STRING + " TEXT,"
+                + SubscriptionManager.MNC_STRING + " TEXT,"
                 + SubscriptionManager.SIM_PROVISIONING_STATUS
                 + " INTEGER DEFAULT " + SubscriptionManager.SIM_PROVISIONED + ","
                 + SubscriptionManager.IS_EMBEDDED + " INTEGER DEFAULT 0,"
@@ -353,7 +379,11 @@
                 + SubscriptionManager.WFC_IMS_ENABLED + " INTEGER DEFAULT -1,"
                 + SubscriptionManager.WFC_IMS_MODE + " INTEGER DEFAULT -1,"
                 + SubscriptionManager.WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1,"
-                + SubscriptionManager.WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1"
+                + SubscriptionManager.WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1,"
+                + SubscriptionManager.IS_OPPORTUNISTIC + " INTEGER DEFAULT 0,"
+                + SubscriptionManager.GROUP_UUID + " TEXT,"
+                + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1,"
+                + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT"
                 + ");";
     }
 
@@ -367,6 +397,7 @@
         s_urlMatcher.addURI("telephony", "carriers/preferapnset", URL_PREFERAPNSET);
 
         s_urlMatcher.addURI("telephony", "siminfo", URL_SIMINFO);
+        s_urlMatcher.addURI("telephony", "siminfo/#", URL_SIMINFO_USING_SUBID);
 
         s_urlMatcher.addURI("telephony", "carriers/subId/*", URL_TELEPHONY_USING_SUBID);
         s_urlMatcher.addURI("telephony", "carriers/current/subId/*", URL_CURRENT_USING_SUBID);
@@ -390,8 +421,13 @@
         // Only called by Settings app, DcTracker and other telephony components to get a
         // single APN according to whether DPC records are enforced.
         s_urlMatcher.addURI("telephony", "carriers/filtered/#", URL_FILTERED_ID);
+        // Used by DcTracker to pass a subId.
+        s_urlMatcher.addURI("telephony", "carriers/filtered/subId/*", URL_FILTERED_USING_SUBID);
+
         // Only Called by DevicePolicyManager to enforce DPC records.
         s_urlMatcher.addURI("telephony", "carriers/enforce_managed", URL_ENFORCE_MANAGED);
+        s_urlMatcher.addURI("telephony", "carriers/sim_apn_list", URL_SIM_APN_LIST);
+        s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/#", URL_SIM_APN_LIST_ID);
 
         s_currentNullMap = new ContentValues(1);
         s_currentNullMap.put(CURRENT, "0");
@@ -419,7 +455,8 @@
         mInjector = injector;
     }
 
-    private static class DatabaseHelper extends SQLiteOpenHelper {
+    @VisibleForTesting
+    public static class DatabaseHelper extends SQLiteOpenHelper {
         // Context to access resources with
         private Context mContext;
 
@@ -435,10 +472,15 @@
             setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
         }
 
-        private static int getVersion(Context context) {
+        @VisibleForTesting
+        public static int getVersion(Context context) {
             if (VDBG) log("getVersion:+");
             // Get the database version, combining a static schema version and the XML version
             Resources r = context.getResources();
+            if (r == null) {
+                loge("resources=null, return version=" + Integer.toHexString(DATABASE_VERSION));
+                return DATABASE_VERSION;
+            }
             XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
             try {
                 XmlUtils.beginDocument(parser, "apns");
@@ -518,9 +560,32 @@
             } catch (IOException e) {
                 loge("IOException for " + file.getAbsolutePath() + ":" + e);
             }
+
+            // The RRO may have been updated in a firmware upgrade. Add checksum for the
+            // resources to the total checksum so that apns in an RRO update is not missed.
+            try (InputStream inputStream = mContext.getResources().
+                        openRawResource(com.android.internal.R.xml.apns)) {
+                byte[] array = toByteArray(inputStream);
+                CRC32 c = new CRC32();
+                c.update(array);
+                checksum += c.getValue();
+                if (DBG) log("Checksum after adding resource is " + checksum);
+            } catch (IOException | Resources.NotFoundException e) {
+                loge("Exception when calculating checksum for internal apn resources: " + e);
+            }
             return checksum;
         }
 
+        private static byte[] toByteArray(InputStream input) throws IOException {
+            byte[] buffer = new byte[128];
+            int bytesRead;
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
+            while ((bytesRead = input.read(buffer)) != -1) {
+                output.write(buffer, 0, bytesRead);
+            }
+            return output.toByteArray();
+        }
+
         private long getApnConfChecksum() {
             SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
             return sp.getLong(APN_CONF_CHECKSUM, -1);
@@ -538,8 +603,8 @@
             File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH);
             File oemConfFile =  new File(Environment.getOemDirectory(), OEM_APNS_PATH);
             File updatedConfFile = new File(Environment.getDataDirectory(), OTA_UPDATED_APNS_PATH);
-            confFile = getNewerFile(confFile, oemConfFile);
-            confFile = getNewerFile(confFile, updatedConfFile);
+            confFile = pickSecondIfExists(confFile, oemConfFile);
+            confFile = pickSecondIfExists(confFile, updatedConfFile);
             return confFile;
         }
 
@@ -570,16 +635,20 @@
             if (VDBG) log("dbh.initDatabase:+ db=" + db);
             // Read internal APNS data
             Resources r = mContext.getResources();
-            XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
             int publicversion = -1;
-            try {
-                XmlUtils.beginDocument(parser, "apns");
-                publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
-                loadApns(db, parser);
-            } catch (Exception e) {
-                loge("Got exception while loading APN database." + e);
-            } finally {
-                parser.close();
+            if (r != null) {
+                XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
+                try {
+                    XmlUtils.beginDocument(parser, "apns");
+                    publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
+                    loadApns(db, parser);
+                } catch (Exception e) {
+                    loge("Got exception while loading APN database." + e);
+                } finally {
+                    parser.close();
+                }
+            } else {
+                loge("initDatabase: resources=null");
             }
 
             // Read external APNS data (partner-provided)
@@ -622,12 +691,12 @@
 
                 // Change USER_DELETED_BUT_PRESENT_IN_XML to USER_DELETED
                 ContentValues cv = new ContentValues();
-                cv.put(EDITED, USER_DELETED);
+                cv.put(EDITED_STATUS, USER_DELETED);
                 db.update(CARRIERS_TABLE, cv, IS_USER_DELETED_BUT_PRESENT_IN_XML, null);
 
                 // Change CARRIER_DELETED_BUT_PRESENT_IN_XML to CARRIER_DELETED
                 cv = new ContentValues();
-                cv.put(EDITED, CARRIER_DELETED);
+                cv.put(EDITED_STATUS, CARRIER_DELETED);
                 db.update(CARRIERS_TABLE, cv, IS_CARRIER_DELETED_BUT_PRESENT_IN_XML, null);
 
                 if (confreader != null) {
@@ -645,26 +714,16 @@
 
         }
 
-        private File getNewerFile(File sysApnFile, File altApnFile) {
+        private File pickSecondIfExists(File sysApnFile, File altApnFile) {
             if (altApnFile.exists()) {
-                // Alternate file exists. Use the newer one.
-                long altFileTime = altApnFile.lastModified();
-                long currFileTime = sysApnFile.lastModified();
-                if (DBG) log("APNs Timestamp: altFileTime = " + altFileTime + " currFileTime = "
-                        + currFileTime);
-
-                // To get the latest version from OEM or System image
-                if (altFileTime > currFileTime) {
-                    if (DBG) log("APNs Timestamp: Alternate image " + altApnFile.getPath() +
-                            " is greater than System image");
-                    return altApnFile;
-                }
+                if (DBG) log("Load APNs from " + altApnFile.getPath() +
+                        " instead of " + sysApnFile.getPath());
+                return altApnFile;
             } else {
-                // No Apn in alternate image, so load it from system image.
-                if (DBG) log("No APNs in OEM image = " + altApnFile.getPath() +
-                        " Load APNs from system image");
+                if (DBG) log("Load APNs from " + sysApnFile.getPath() +
+                        " instead of " + altApnFile.getPath());
+                return sysApnFile;
             }
-            return sysApnFile;
         }
 
         @Override
@@ -984,7 +1043,7 @@
             if (oldVersion < (24 << 16 | 6)) {
                 Cursor c = null;
                 String[] proj = {"_id"};
-                recreateDB(c, db, proj, /* version */24);
+                recreateDB(db, proj, /* version */24);
                 if (VDBG) {
                     c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
                     log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount());
@@ -1024,7 +1083,7 @@
                 // Carriers.NO_SET_SET by default.
                 try {
                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " +
-                            APN_SET_ID + " INTEGER DEFAULT " + NO_SET_SET + ";");
+                            APN_SET_ID + " INTEGER DEFAULT " + NO_APN_SET_ID + ";");
                 } catch (SQLiteException e) {
                     if (DBG) {
                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
@@ -1033,9 +1092,110 @@
                 }
                 oldVersion = 26 << 16 | 6;
             }
+
+            if (oldVersion < (27 << 16 | 6)) {
+                // Add the new MCC_STRING and MNC_STRING columns into the subscription table,
+                // and attempt to populate them.
+                try {
+                    // Try to update the siminfo table. It might not be there.
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
+                            " ADD COLUMN " + SubscriptionManager.MCC_STRING + " TEXT;");
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
+                            " ADD COLUMN " + SubscriptionManager.MNC_STRING + " TEXT;");
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+                                " The table will get created in onOpen.");
+                    }
+                }
+                // Migrate the old integer values over to strings
+                String[] proj = {SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
+                        SubscriptionManager.MCC, SubscriptionManager.MNC};
+                try (Cursor c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null)) {
+                    while (c.moveToNext()) {
+                        fillInMccMncStringAtCursor(mContext, db, c);
+                    }
+                }
+                oldVersion = 27 << 16 | 6;
+            }
+
+            if (oldVersion < (28 << 16 | 6)) {
+                try {
+                    // Try to update the siminfo table. It might not be there.
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
+                            + SubscriptionManager.IS_OPPORTUNISTIC + " INTEGER DEFAULT 0;");
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+                                "The table will get created in onOpen.");
+                    }
+                }
+                oldVersion = 28 << 16 | 6;
+            }
+
+            if (oldVersion < (29 << 16 | 6)) {
+                try {
+                    // Add a new column Telephony.CARRIER_ID into the database and add UNIQUE
+                    // constraint into table. However, sqlite cannot add constraints to an existing
+                    // table, so recreate the table.
+                    String[] proj = {"_id"};
+                    recreateDB(db, proj,  /* version */29);
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
+                                "The table will get created in onOpen.");
+                    }
+                }
+                oldVersion = 29 << 16 | 6;
+            }
+
+            if (oldVersion < (30 << 16 | 6)) {
+                try {
+                    // Try to update the siminfo table. It might not be there.
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
+                        + SubscriptionManager.GROUP_UUID + " TEXT;");
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+                            "The table will get created in onOpen.");
+                    }
+                }
+                oldVersion = 30 << 16 | 6;
+            }
+            
+            if (oldVersion < (31 << 16 | 6)) {
+                try {
+                    // Try to update the siminfo table. It might not be there.
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
+                            + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1;");
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+                                "The table will get created in onOpen.");
+                    }
+                }
+                oldVersion = 31 << 16 | 6;
+            }
+
+            if (oldVersion < (32 << 16 | 6)) {
+                try {
+                    // Try to update the siminfo table. It might not be there.
+                    db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
+                            + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT;");
+                } catch (SQLiteException e) {
+                    if (DBG) {
+                        log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+                                "The table will get created in onOpen.");
+                    }
+                }
+                oldVersion = 32 << 16 | 6;
+            }
+
             if (DBG) {
                 log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
             }
+            // when adding fields to onUpgrade, also add a unit test to TelephonyDatabaseHelperTest
+            // and update the DATABASE_VERSION field and add a column in copyAllApnValues
         }
 
         private void recreateSimInfoDB(Cursor c, SQLiteDatabase db, String[] proj) {
@@ -1143,12 +1303,13 @@
             }
         }
 
-        private void recreateDB(Cursor c, SQLiteDatabase db, String[] proj, int version) {
+        private void recreateDB(SQLiteDatabase db, String[] proj, int version) {
             // Upgrade steps are:
             // 1. Create a temp table- done in createCarriersTable()
             // 2. copy over APNs from old table to new table - done in copyDataToTmpTable()
             // 3. Drop the existing table.
             // 4. Copy over the tmp table.
+            Cursor c;
             if (VDBG) {
                 c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
                 log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount());
@@ -1166,7 +1327,7 @@
 
             createCarriersTable(db, CARRIERS_TABLE_TMP);
 
-            copyDataToTmpTable(db, c);
+            copyDataToTmpTable(db, c, version);
             c.close();
 
             db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE);
@@ -1271,10 +1432,10 @@
                     queryValOrNull(MVNO_TYPE) +
                     queryValOrNull(MVNO_MATCH_DATA) +
                     queryValOrNull(PROFILE_ID) +
-                    queryVal2OrNull(MODEM_COGNITIVE) +
-                    queryValOrNull(MAX_CONNS) +
-                    queryValOrNull(WAIT_TIME) +
-                    queryValOrNull(MAX_CONNS_TIME) +
+                    queryVal2OrNull(MODEM_PERSIST) +
+                    queryValOrNull(MAX_CONNECTIONS) +
+                    queryValOrNull(WAIT_TIME_RETRY) +
+                    queryValOrNull(TIME_LIMIT_FOR_MAX_CONNECTIONS) +
                     queryValOrNull(MTU);
             String[] whereArgs = new String[29];
             int i = 0;
@@ -1309,15 +1470,13 @@
             whereArgs[i++] = values.containsKey(ROAMING_PROTOCOL) ?
                     values.getAsString(ROAMING_PROTOCOL) : DEFAULT_ROAMING_PROTOCOL;
 
-            if (values.containsKey(CARRIER_ENABLED) &&
-                    (values.getAsString(CARRIER_ENABLED).
-                            equalsIgnoreCase("false") ||
-                            values.getAsString(CARRIER_ENABLED).equals("0"))) {
-                whereArgs[i++] = "false";
-                whereArgs[i++] = "0";
+            if (values.containsKey(CARRIER_ENABLED)) {
+                whereArgs[i++] = convertStringToBoolString(values.getAsString(CARRIER_ENABLED));
+                whereArgs[i++] = convertStringToIntString(values.getAsString(CARRIER_ENABLED));
             } else {
-                whereArgs[i++] = "true";
-                whereArgs[i++] = "1";
+                String defaultIntString = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(CARRIER_ENABLED);
+                whereArgs[i++] = convertStringToBoolString(defaultIntString);
+                whereArgs[i++] = defaultIntString;
             }
 
             whereArgs[i++] = values.containsKey(BEARER) ?
@@ -1329,10 +1488,10 @@
             whereArgs[i++] = values.containsKey(PROFILE_ID) ?
                     values.getAsString(PROFILE_ID) : "0";
 
-            if (values.containsKey(MODEM_COGNITIVE) &&
-                    (values.getAsString(MODEM_COGNITIVE).
+            if (values.containsKey(MODEM_PERSIST) &&
+                    (values.getAsString(MODEM_PERSIST).
                             equalsIgnoreCase("true") ||
-                            values.getAsString(MODEM_COGNITIVE).equals("1"))) {
+                            values.getAsString(MODEM_PERSIST).equals("1"))) {
                 whereArgs[i++] = "true";
                 whereArgs[i++] = "1";
             } else {
@@ -1340,12 +1499,12 @@
                 whereArgs[i++] = "0";
             }
 
-            whereArgs[i++] = values.containsKey(MAX_CONNS) ?
-                    values.getAsString(MAX_CONNS) : "0";
-            whereArgs[i++] = values.containsKey(WAIT_TIME) ?
-                    values.getAsString(WAIT_TIME) : "0";
-            whereArgs[i++] = values.containsKey(MAX_CONNS_TIME) ?
-                    values.getAsString(MAX_CONNS_TIME) : "0";
+            whereArgs[i++] = values.containsKey(MAX_CONNECTIONS) ?
+                    values.getAsString(MAX_CONNECTIONS) : "0";
+            whereArgs[i++] = values.containsKey(WAIT_TIME_RETRY) ?
+                    values.getAsString(WAIT_TIME_RETRY) : "0";
+            whereArgs[i++] = values.containsKey(TIME_LIMIT_FOR_MAX_CONNECTIONS) ?
+                    values.getAsString(TIME_LIMIT_FOR_MAX_CONNECTIONS) : "0";
             whereArgs[i++] = values.containsKey(MTU) ?
                     values.getAsString(MTU) : "0";
 
@@ -1362,14 +1521,16 @@
             db.delete(CARRIERS_TABLE, where, whereArgs);
         }
 
-        private void copyDataToTmpTable(SQLiteDatabase db, Cursor c) {
+        private void copyDataToTmpTable(SQLiteDatabase db, Cursor c, int version) {
             // Move entries from CARRIERS_TABLE to CARRIERS_TABLE_TMP
             if (c != null) {
                 while (c.moveToNext()) {
                     ContentValues cv = new ContentValues();
-                    copyApnValuesV17(cv, c);
-                    // Sync bearer bitmask and network type bitmask
-                    getNetworkTypeBitmaskFromCursor(cv, c);
+                    copyAllApnValues(cv, c);
+                    if (version == 24) {
+                        // Sync bearer bitmask and network type bitmask
+                        getNetworkTypeBitmaskFromCursor(cv, c);
+                    }
                     try {
                         db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv,
                                 SQLiteDatabase.CONFLICT_ABORT);
@@ -1417,95 +1578,141 @@
             getIntValueFromCursor(cv, c, BEARER);
             getIntValueFromCursor(cv, c, SUBSCRIPTION_ID);
             getIntValueFromCursor(cv, c, PROFILE_ID);
-            getIntValueFromCursor(cv, c, MODEM_COGNITIVE);
-            getIntValueFromCursor(cv, c, MAX_CONNS);
-            getIntValueFromCursor(cv, c, WAIT_TIME);
-            getIntValueFromCursor(cv, c, MAX_CONNS_TIME);
+            getIntValueFromCursor(cv, c, MODEM_PERSIST);
+            getIntValueFromCursor(cv, c, MAX_CONNECTIONS);
+            getIntValueFromCursor(cv, c, WAIT_TIME_RETRY);
+            getIntValueFromCursor(cv, c, TIME_LIMIT_FOR_MAX_CONNECTIONS);
             getIntValueFromCursor(cv, c, MTU);
             getIntValueFromCursor(cv, c, BEARER_BITMASK);
-            getIntValueFromCursor(cv, c, EDITED);
+            getIntValueFromCursor(cv, c, EDITED_STATUS);
             getIntValueFromCursor(cv, c, USER_VISIBLE);
         }
 
+        private void copyAllApnValues(ContentValues cv, Cursor c) {
+            // String vals
+            getStringValueFromCursor(cv, c, NAME);
+            getStringValueFromCursor(cv, c, NUMERIC);
+            getStringValueFromCursor(cv, c, MCC);
+            getStringValueFromCursor(cv, c, MNC);
+            getStringValueFromCursor(cv, c, APN);
+            getStringValueFromCursor(cv, c, USER);
+            getStringValueFromCursor(cv, c, SERVER);
+            getStringValueFromCursor(cv, c, PASSWORD);
+            getStringValueFromCursor(cv, c, PROXY);
+            getStringValueFromCursor(cv, c, PORT);
+            getStringValueFromCursor(cv, c, MMSPROXY);
+            getStringValueFromCursor(cv, c, MMSPORT);
+            getStringValueFromCursor(cv, c, MMSC);
+            getStringValueFromCursor(cv, c, TYPE);
+            getStringValueFromCursor(cv, c, PROTOCOL);
+            getStringValueFromCursor(cv, c, ROAMING_PROTOCOL);
+            getStringValueFromCursor(cv, c, MVNO_TYPE);
+            getStringValueFromCursor(cv, c, MVNO_MATCH_DATA);
+
+            // bool/int vals
+            getIntValueFromCursor(cv, c, AUTH_TYPE);
+            getIntValueFromCursor(cv, c, CURRENT);
+            getIntValueFromCursor(cv, c, CARRIER_ENABLED);
+            getIntValueFromCursor(cv, c, BEARER);
+            getIntValueFromCursor(cv, c, SUBSCRIPTION_ID);
+            getIntValueFromCursor(cv, c, PROFILE_ID);
+            getIntValueFromCursor(cv, c, MODEM_PERSIST);
+            getIntValueFromCursor(cv, c, MAX_CONNECTIONS);
+            getIntValueFromCursor(cv, c, WAIT_TIME_RETRY);
+            getIntValueFromCursor(cv, c, TIME_LIMIT_FOR_MAX_CONNECTIONS);
+            getIntValueFromCursor(cv, c, MTU);
+            getIntValueFromCursor(cv, c, NETWORK_TYPE_BITMASK);
+            getIntValueFromCursor(cv, c, BEARER_BITMASK);
+            getIntValueFromCursor(cv, c, EDITED_STATUS);
+            getIntValueFromCursor(cv, c, USER_VISIBLE);
+            getIntValueFromCursor(cv, c, USER_EDITABLE);
+            getIntValueFromCursor(cv, c, OWNED_BY);
+            getIntValueFromCursor(cv, c, APN_SET_ID);
+        }
 
         private void copyPreservedApnsToNewTable(SQLiteDatabase db, Cursor c) {
             // Move entries from CARRIERS_TABLE to CARRIERS_TABLE_TMP
-            if (c != null) {
-                String[] persistApnsForPlmns = mContext.getResources().getStringArray(
-                        R.array.persist_apns_for_plmn);
-                while (c.moveToNext()) {
-                    ContentValues cv = new ContentValues();
-                    String val;
-                    // Using V17 copy function for V15 upgrade. This should be fine since it handles
-                    // columns that may not exist properly (getStringValueFromCursor() and
-                    // getIntValueFromCursor() handle column index -1)
-                    copyApnValuesV17(cv, c);
-                    // Change bearer to a bitmask
-                    String bearerStr = c.getString(c.getColumnIndex(BEARER));
-                    if (!TextUtils.isEmpty(bearerStr)) {
-                        int bearer_bitmask = ServiceState.getBitmaskForTech(
-                                Integer.parseInt(bearerStr));
-                        cv.put(BEARER_BITMASK, bearer_bitmask);
+            if (c != null && mContext.getResources() != null) {
+                try {
+                    String[] persistApnsForPlmns = mContext.getResources().getStringArray(
+                            R.array.persist_apns_for_plmn);
+                    while (c.moveToNext()) {
+                        ContentValues cv = new ContentValues();
+                        String val;
+                        // Using V17 copy function for V15 upgrade. This should be fine since it handles
+                        // columns that may not exist properly (getStringValueFromCursor() and
+                        // getIntValueFromCursor() handle column index -1)
+                        copyApnValuesV17(cv, c);
+                        // Change bearer to a bitmask
+                        String bearerStr = c.getString(c.getColumnIndex(BEARER));
+                        if (!TextUtils.isEmpty(bearerStr)) {
+                            int bearer_bitmask = ServiceState.getBitmaskForTech(
+                                    Integer.parseInt(bearerStr));
+                            cv.put(BEARER_BITMASK, bearer_bitmask);
 
-                        int networkTypeBitmask = ServiceState.getBitmaskForTech(
-                                ServiceState.rilRadioTechnologyToNetworkType(
-                                        Integer.parseInt(bearerStr)));
-                        cv.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
-                    }
-
-                    int userEditedColumnIdx = c.getColumnIndex("user_edited");
-                    if (userEditedColumnIdx != -1) {
-                        String user_edited = c.getString(userEditedColumnIdx);
-                        if (!TextUtils.isEmpty(user_edited)) {
-                            cv.put(EDITED, new Integer(user_edited));
+                            int networkTypeBitmask = ServiceState.getBitmaskForTech(
+                                    ServiceState.rilRadioTechnologyToNetworkType(
+                                            Integer.parseInt(bearerStr)));
+                            cv.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
                         }
-                    } else {
-                        cv.put(EDITED, CARRIER_EDITED);
-                    }
 
-                    // New EDITED column. Default value (UNEDITED) will
-                    // be used for all rows except for non-mvno entries for plmns indicated
-                    // by resource: those will be set to CARRIER_EDITED to preserve
-                    // their current values
-                    val = c.getString(c.getColumnIndex(NUMERIC));
-                    for (String s : persistApnsForPlmns) {
-                        if (!TextUtils.isEmpty(val) && val.equals(s) &&
-                                (!cv.containsKey(MVNO_TYPE) ||
-                                        TextUtils.isEmpty(cv.getAsString(MVNO_TYPE)))) {
-                            if (userEditedColumnIdx == -1) {
-                                cv.put(EDITED, CARRIER_EDITED);
-                            } else { // if (oldVersion == 14) -- if db had user_edited column
-                                if (cv.getAsInteger(EDITED) == USER_EDITED) {
-                                    cv.put(EDITED, CARRIER_EDITED);
-                                }
+                        int userEditedColumnIdx = c.getColumnIndex("user_edited");
+                        if (userEditedColumnIdx != -1) {
+                            String user_edited = c.getString(userEditedColumnIdx);
+                            if (!TextUtils.isEmpty(user_edited)) {
+                                cv.put(EDITED_STATUS, new Integer(user_edited));
                             }
+                        } else {
+                            cv.put(EDITED_STATUS, CARRIER_EDITED);
+                        }
 
-                            break;
+                        // New EDITED column. Default value (UNEDITED) will
+                        // be used for all rows except for non-mvno entries for plmns indicated
+                        // by resource: those will be set to CARRIER_EDITED to preserve
+                        // their current values
+                        val = c.getString(c.getColumnIndex(NUMERIC));
+                        for (String s : persistApnsForPlmns) {
+                            if (!TextUtils.isEmpty(val) && val.equals(s) &&
+                                    (!cv.containsKey(MVNO_TYPE) ||
+                                            TextUtils.isEmpty(cv.getAsString(MVNO_TYPE)))) {
+                                if (userEditedColumnIdx == -1) {
+                                    cv.put(EDITED_STATUS, CARRIER_EDITED);
+                                } else { // if (oldVersion == 14) -- if db had user_edited column
+                                    if (cv.getAsInteger(EDITED_STATUS) == USER_EDITED) {
+                                        cv.put(EDITED_STATUS, CARRIER_EDITED);
+                                    }
+                                }
+
+                                break;
+                            }
+                        }
+
+                        try {
+                            db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv,
+                                    SQLiteDatabase.CONFLICT_ABORT);
+                            if (VDBG) {
+                                log("dbh.copyPreservedApnsToNewTable: db.insert returned >= 0; " +
+                                        "insert successful for cv " + cv);
+                            }
+                        } catch (SQLException e) {
+                            if (VDBG)
+                                log("dbh.copyPreservedApnsToNewTable insertWithOnConflict exception " +
+                                        e + " for cv " + cv);
+                            // Insertion failed which could be due to a conflict. Check if that is
+                            // the case and merge the entries
+                            Cursor oldRow = DatabaseHelper.selectConflictingRow(db,
+                                    CARRIERS_TABLE_TMP, cv);
+                            if (oldRow != null) {
+                                ContentValues mergedValues = new ContentValues();
+                                mergeFieldsAndUpdateDb(db, CARRIERS_TABLE_TMP, oldRow, cv,
+                                        mergedValues, true, mContext);
+                                oldRow.close();
+                            }
                         }
                     }
-
-                    try {
-                        db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv,
-                                SQLiteDatabase.CONFLICT_ABORT);
-                        if (VDBG) {
-                            log("dbh.copyPreservedApnsToNewTable: db.insert returned >= 0; " +
-                                    "insert successful for cv " + cv);
-                        }
-                    } catch (SQLException e) {
-                        if (VDBG)
-                            log("dbh.copyPreservedApnsToNewTable insertWithOnConflict exception " +
-                                    e + " for cv " + cv);
-                        // Insertion failed which could be due to a conflict. Check if that is
-                        // the case and merge the entries
-                        Cursor oldRow = DatabaseHelper.selectConflictingRow(db,
-                                CARRIERS_TABLE_TMP, cv);
-                        if (oldRow != null) {
-                            ContentValues mergedValues = new ContentValues();
-                            mergeFieldsAndUpdateDb(db, CARRIERS_TABLE_TMP, oldRow, cv,
-                                    mergedValues, true, mContext);
-                            oldRow.close();
-                        }
-                    }
+                } catch (Resources.NotFoundException e) {
+                    loge("array.persist_apns_for_plmn is not found");
+                    return;
                 }
             }
         }
@@ -1621,15 +1828,15 @@
             addIntAttribute(parser, "authtype", map, AUTH_TYPE);
             addIntAttribute(parser, "bearer", map, BEARER);
             addIntAttribute(parser, "profile_id", map, PROFILE_ID);
-            addIntAttribute(parser, "max_conns", map, MAX_CONNS);
-            addIntAttribute(parser, "wait_time", map, WAIT_TIME);
-            addIntAttribute(parser, "max_conns_time", map, MAX_CONNS_TIME);
+            addIntAttribute(parser, "max_conns", map, MAX_CONNECTIONS);
+            addIntAttribute(parser, "wait_time", map, WAIT_TIME_RETRY);
+            addIntAttribute(parser, "max_conns_time", map, TIME_LIMIT_FOR_MAX_CONNECTIONS);
             addIntAttribute(parser, "mtu", map, MTU);
             addIntAttribute(parser, "apn_set_id", map, APN_SET_ID);
 
 
             addBoolAttribute(parser, "carrier_enabled", map, CARRIER_ENABLED);
-            addBoolAttribute(parser, "modem_cognitive", map, MODEM_COGNITIVE);
+            addBoolAttribute(parser, "modem_cognitive", map, MODEM_PERSIST);
             addBoolAttribute(parser, "user_visible", map, USER_VISIBLE);
             addBoolAttribute(parser, "user_editable", map, USER_EDITABLE);
 
@@ -1751,7 +1958,7 @@
                 if (oldRow != null) {
                     // Update the row
                     ContentValues mergedValues = new ContentValues();
-                    int edited = oldRow.getInt(oldRow.getColumnIndex(EDITED));
+                    int edited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS));
                     int old_edited = edited;
                     if (edited != UNEDITED) {
                         if (edited == USER_DELETED) {
@@ -1763,7 +1970,7 @@
                             // by user but present in apn xml file.
                             edited = CARRIER_DELETED_BUT_PRESENT_IN_XML;
                         }
-                        mergedValues.put(EDITED, edited);
+                        mergedValues.put(EDITED_STATUS, edited);
                     }
 
                     mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, row, mergedValues, false,
@@ -1860,16 +2067,16 @@
 
             if (!onUpgrade) {
                 // Do not overwrite a carrier or user edit with EDITED=UNEDITED
-                if (newRow.containsKey(EDITED)) {
-                    int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED));
-                    int newEdited = newRow.getAsInteger(EDITED);
+                if (newRow.containsKey(EDITED_STATUS)) {
+                    int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS));
+                    int newEdited = newRow.getAsInteger(EDITED_STATUS);
                     if (newEdited == UNEDITED && (oldEdited == CARRIER_EDITED
                                 || oldEdited == CARRIER_DELETED
                                 || oldEdited == CARRIER_DELETED_BUT_PRESENT_IN_XML
                                 || oldEdited == USER_EDITED
                                 || oldEdited == USER_DELETED
                                 || oldEdited == USER_DELETED_BUT_PRESENT_IN_XML)) {
-                        newRow.remove(EDITED);
+                        newRow.remove(EDITED_STATUS);
                     }
                 }
                 mergedValues.putAll(newRow);
@@ -1893,13 +2100,17 @@
             boolean match = false;
 
             // Check if APN falls under persist_apns_for_plmn
-            String[] persistApnsForPlmns = context.getResources().getStringArray(
-                    R.array.persist_apns_for_plmn);
-            for (String s : persistApnsForPlmns) {
-                if (s.equalsIgnoreCase(newRow.getAsString(NUMERIC))) {
-                    match = true;
-                    break;
+            if (context.getResources() != null) {
+                String[] persistApnsForPlmns = context.getResources().getStringArray(
+                        R.array.persist_apns_for_plmn);
+                for (String s : persistApnsForPlmns) {
+                    if (s.equalsIgnoreCase(newRow.getAsString(NUMERIC))) {
+                        match = true;
+                        break;
+                    }
                 }
+            } else {
+                loge("separateRowsNeeded: resources=null");
             }
 
             if (!match) return false;
@@ -1986,7 +2197,7 @@
 
             String[] columns = { "_id",
                     TYPE,
-                    EDITED,
+                    EDITED_STATUS,
                     BEARER_BITMASK,
                     NETWORK_TYPE_BITMASK,
                     PROFILE_ID };
@@ -1994,15 +2205,16 @@
             int i = 0;
             String[] selectionArgs = new String[CARRIERS_UNIQUE_FIELDS.size()];
             for (String field : CARRIERS_UNIQUE_FIELDS) {
-                if (CARRIER_ENABLED.equals(field)) {
-                    // for CARRIER_ENABLED we overwrite the value "false" with "0"
-                    selectionArgs[i++] = row.containsKey(CARRIER_ENABLED) &&
-                            (row.getAsString(CARRIER_ENABLED).equals("0") ||
-                                    row.getAsString(CARRIER_ENABLED).equals("false")) ?
-                            "0" : CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(CARRIER_ENABLED);
+                if (!row.containsKey(field)) {
+                    selectionArgs[i++] = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(field);
                 } else {
-                    selectionArgs[i++] = row.containsKey(field) ?
-                            row.getAsString(field) : CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(field);
+                    if (CARRIERS_BOOLEAN_FIELDS.contains(field)) {
+                        // for boolean fields we overwrite the strings "true" and "false" with "1"
+                        // and "0"
+                        selectionArgs[i++] = convertStringToIntString(row.getAsString(field));
+                    } else {
+                        selectionArgs[i++] = row.getAsString(field);
+                    }
                 }
             }
 
@@ -2032,6 +2244,24 @@
     }
 
     /**
+     * Convert "true" and "false" to "1" and "0".
+     * If the passed in string is already "1" or "0" returns the passed in string.
+     */
+    private static String convertStringToIntString(String boolString) {
+        if ("0".equals(boolString) || "false".equalsIgnoreCase(boolString)) return "0";
+        return "1";
+    }
+
+    /**
+     * Convert "1" and "0" to "true" and "false".
+     * If the passed in string is already "true" or "false" returns the passed in string.
+     */
+    private static String convertStringToBoolString(String intString) {
+        if ("0".equals(intString) || "false".equalsIgnoreCase(intString)) return "false";
+        return "true";
+    }
+
+    /**
      * These methods can be overridden in a subclass for testing TelephonyProvider using an
      * in-memory database.
      */
@@ -2067,7 +2297,7 @@
         return s_apnSourceServiceExists;
     }
 
-    private void restoreApnsWithService() {
+    private void restoreApnsWithService(int subId) {
         Context context = getContext();
         Resources r = context.getResources();
         ServiceConnection connection = new ServiceConnection() {
@@ -2095,7 +2325,8 @@
                 r.getString(R.string.apn_source_service)));
         log("binding to service to restore apns, intent=" + intent);
         try {
-            if (context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
+            if (context.bindService(intent, connection, Context.BIND_IMPORTANT |
+                        Context.BIND_AUTO_CREATE)) {
                 synchronized (mLock) {
                     while (mIApnSourceService == null) {
                         try {
@@ -2105,7 +2336,7 @@
                         }
                     }
                     try {
-                        ContentValues[] values = mIApnSourceService.getApns();
+                        ContentValues[] values = mIApnSourceService.getApns(subId);
                         if (values != null) {
                             // we use the unsynchronized insert because this function is called
                             // within the syncrhonized function delete()
@@ -2241,7 +2472,7 @@
         try {
             return Integer.parseInt(sp.getString(APN_SET_ID + subId, null));
         } catch (NumberFormatException e) {
-            return NO_SET_SET;
+            return NO_APN_SET_ID;
         }
     }
 
@@ -2304,7 +2535,7 @@
 
     private long getPreferredApnIdFromApn(int subId) {
         log("getPreferredApnIdFromApn: for subId " + subId);
-        SQLiteDatabase db = getWritableDatabase();
+        SQLiteDatabase db = getReadableDatabase();
         String where = TextUtils.join("=? and ", CARRIERS_UNIQUE_FIELDS) + "=?";
         String[] whereArgs = new String[CARRIERS_UNIQUE_FIELDS.size()];
         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
@@ -2365,7 +2596,7 @@
     public synchronized Cursor query(Uri url, String[] projectionIn, String selection,
             String[] selectionArgs, String sort) {
         if (VDBG) log("query: url=" + url + ", projectionIn=" + projectionIn + ", selection="
-            + selection + "selectionArgs=" + selectionArgs + ", sort=" + sort);
+                + selection + "selectionArgs=" + selectionArgs + ", sort=" + sort);
         TelephonyManager mTelephonyManager =
                 (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
         int subId = SubscriptionManager.getDefaultSubscriptionId();
@@ -2377,6 +2608,7 @@
         List<String> constraints = new ArrayList<String>();
 
         int match = s_urlMatcher.match(url);
+        checkQueryPermission(match, projectionIn);
         switch (match) {
             case URL_TELEPHONY_USING_SUBID: {
                 subIdString = url.getLastPathSegment();
@@ -2459,7 +2691,7 @@
             // intentional fall through from above case
             case URL_PREFERAPNSET: {
                 final int set = getPreferredApnSetId(subId);
-                if (set != NO_SET_SET) {
+                if (set != NO_APN_SET_ID) {
                     constraints.add(APN_SET_ID + "=" + set);
                 }
                 break;
@@ -2472,19 +2704,31 @@
                 break;
             }
 
-            case URL_FILTERED_ID: {
-                constraints.add("_id = " + url.getLastPathSegment());
+            case URL_FILTERED_ID:
+            case URL_FILTERED_USING_SUBID: {
+                String idString = url.getLastPathSegment();
+                if (match == URL_FILTERED_ID) {
+                    qb.appendWhere("_id = " + idString);
+                } else {
+                    try {
+                        subId = Integer.parseInt(idString);
+                    } catch (NumberFormatException e) {
+                        loge("NumberFormatException" + e);
+                        return null;
+                    }
+                }
             }
             //intentional fall through from above case
             case URL_FILTERED: {
-                if(isManagedApnEnforced()) {
+                if (isManagedApnEnforced()) {
                     // If enforced, return DPC records only.
-                    constraints.add(IS_OWNED_BY_DPC);
+                    qb.appendWhereStandalone(IS_OWNED_BY_DPC);
                 } else {
                     // Otherwise return non-DPC records only.
-                    constraints.add(IS_NOT_OWNED_BY_DPC);
+                    qb.appendWhereStandalone(IS_NOT_OWNED_BY_DPC);
                 }
-                break;
+                return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
+                        sort, subId);
             }
 
             case URL_ENFORCE_MANAGED: {
@@ -2499,6 +2743,21 @@
                 qb.setTables(SIMINFO_TABLE);
                 break;
             }
+            case URL_SIM_APN_LIST_ID: {
+                subIdString = url.getLastPathSegment();
+                try {
+                    subId = Integer.parseInt(subIdString);
+                } catch (NumberFormatException e) {
+                    loge("NumberFormatException" + e);
+                    return null;
+                }
+            }
+            //intentional fall through from above case
+            case URL_SIM_APN_LIST: {
+                qb.appendWhere(IS_NOT_OWNED_BY_DPC);
+                return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
+                        sort, subId);
+            }
 
             default: {
                 return null;
@@ -2510,26 +2769,6 @@
             qb.appendWhere(TextUtils.join(" AND ", constraints));
         }
 
-        if (match != URL_SIMINFO) {
-            if (projectionIn != null) {
-                for (String column : projectionIn) {
-                    if (TYPE.equals(column) ||
-                            MMSC.equals(column) ||
-                            MMSPROXY.equals(column) ||
-                            MMSPORT.equals(column) ||
-                            APN.equals(column)) {
-                        // noop
-                    } else {
-                        checkPermission();
-                        break;
-                    }
-                }
-            } else {
-                // null returns all columns, so need permission check
-                checkPermission();
-            }
-        }
-
         SQLiteDatabase db = getReadableDatabase();
         Cursor ret = null;
         try {
@@ -2555,6 +2794,105 @@
         return ret;
     }
 
+    private void checkQueryPermission(int match, String[] projectionIn) {
+        if (match != URL_SIMINFO) {
+            if (projectionIn != null) {
+                for (String column : projectionIn) {
+                    if (TYPE.equals(column) ||
+                            MMSC.equals(column) ||
+                            MMSPROXY.equals(column) ||
+                            MMSPORT.equals(column) ||
+                            MVNO_TYPE.equals(column) ||
+                            MVNO_MATCH_DATA.equals(column) ||
+                            APN.equals(column)) {
+                        // noop
+                    } else {
+                        checkPermission();
+                        break;
+                    }
+                }
+            } else {
+                // null returns all columns, so need permission check
+                checkPermission();
+            }
+        }
+    }
+
+    /**
+     * To find the current sim APN. Query APN based on {MCC, MNC, MVNO} to support backward
+     * compatibility but will move to carrier id in the future.
+     *
+     * There has three steps:
+     * 1. Query the APN based on { MCC, MNC, MVNO }.
+     * 2. If can't find the current APN, then query the parent APN. Query based on { MCC, MNC }.
+     * 3. else return empty cursor
+     *
+     */
+    private Cursor getSubscriptionMatchingAPNList(SQLiteQueryBuilder qb, String[] projectionIn,
+            String selection, String[] selectionArgs, String sort, int subId) {
+        Cursor ret;
+        final TelephonyManager tm = ((TelephonyManager)
+                getContext().getSystemService(Context.TELEPHONY_SERVICE))
+                .createForSubscriptionId(subId);
+        SQLiteDatabase db = getReadableDatabase();
+        String mccmnc = tm.getSimOperator();
+
+        // For query db one time, append step 1 and step 2 condition in one selection and
+        // separate results after the query is completed. Because IMSI has special match rule,
+        // so just query the MCC / MNC and filter the MVNO by ourselves
+        qb.appendWhereStandalone(NUMERIC + " = '" + mccmnc + "' ");
+
+        ret = qb.query(db, null, selection, selectionArgs, null, null, sort);
+        if (ret == null) {
+            loge("query current APN but cursor is null.");
+            return null;
+        }
+
+        if (DBG) log("match current APN size:  " + ret.getCount());
+
+        String[] coulmnNames = projectionIn != null ? projectionIn : ret.getColumnNames();
+        MatrixCursor currentCursor = new MatrixCursor(coulmnNames);
+        MatrixCursor parentCursor = new MatrixCursor(coulmnNames);
+
+        int numericIndex = ret.getColumnIndex(NUMERIC);
+        int mvnoIndex = ret.getColumnIndex(MVNO_TYPE);
+        int mvnoDataIndex = ret.getColumnIndex(MVNO_MATCH_DATA);
+
+        IccRecords iccRecords = getIccRecords(subId);
+
+        //Separate the result into MatrixCursor
+        while (ret.moveToNext()) {
+            List<String> data = new ArrayList<>();
+            for (String column : coulmnNames) {
+                data.add(ret.getString(ret.getColumnIndex(column)));
+            }
+
+            if (!TextUtils.isEmpty(ret.getString(numericIndex)) &&
+                    ApnSettingUtils.mvnoMatches(iccRecords,
+                            ApnSetting.getMvnoTypeIntFromString(ret.getString(mvnoIndex)),
+                            ret.getString(mvnoDataIndex))) {
+                // 1. APN query result based on legacy SIM MCC/MCC and MVNO
+                currentCursor.addRow(data);
+            } else if (!TextUtils.isEmpty(ret.getString(numericIndex)) &&
+                    TextUtils.isEmpty(ret.getString(mvnoIndex))) {
+                // 2. APN query result based on SIM MCC/MNC
+                parentCursor.addRow(data);
+            }
+        }
+        ret.close();
+
+        if (currentCursor.getCount() > 0) {
+            if (DBG) log("match Carrier Id APN: " + currentCursor.getCount());
+            return currentCursor;
+        } else if (parentCursor.getCount() > 0) {
+            if (DBG) log("match MNO Carrier ID APN: " + parentCursor.getCount());
+            return parentCursor;
+        } else {
+            if (DBG) log("APN no match");
+            return new MatrixCursor(coulmnNames);
+        }
+    }
+
     @Override
     public String getType(Uri url)
     {
@@ -2565,6 +2903,7 @@
 
         case URL_ID:
         case URL_FILTERED_ID:
+        case URL_FILTERED_USING_SUBID:
             return "vnd.android.cursor.item/telephony-carrier";
 
         case URL_PREFERAPN_USING_SUBID:
@@ -2693,8 +3032,8 @@
                 }
 
                 values = DatabaseHelper.setDefaultValue(values);
-                if (!values.containsKey(EDITED)) {
-                    values.put(EDITED, CARRIER_EDITED);
+                if (!values.containsKey(EDITED_STATUS)) {
+                    values.put(EDITED_STATUS, CARRIER_EDITED);
                 }
                 // Owned_by should be others if inserted via general uri.
                 values.put(OWNED_BY, OWNED_BY_OTHERS);
@@ -2812,7 +3151,7 @@
                 IS_NOT_CARRIER_EDITED + ")";
         String unedited = ") and " + IS_UNEDITED;
         ContentValues cv = new ContentValues();
-        cv.put(EDITED, USER_DELETED);
+        cv.put(EDITED_STATUS, USER_DELETED);
 
         checkPermission();
 
@@ -2999,8 +3338,8 @@
 
             case URL_TELEPHONY:
             {
-                if (!values.containsKey(EDITED)) {
-                    values.put(EDITED, CARRIER_EDITED);
+                if (!values.containsKey(EDITED_STATUS)) {
+                    values.put(EDITED_STATUS, CARRIER_EDITED);
                 }
 
                 // Replace on conflict so that if same APN is present in db with edited
@@ -3028,8 +3367,8 @@
 
             case URL_CURRENT:
             {
-                if (!values.containsKey(EDITED)) {
-                    values.put(EDITED, CARRIER_EDITED);
+                if (!values.containsKey(EDITED_STATUS)) {
+                    values.put(EDITED_STATUS, CARRIER_EDITED);
                 }
                 // Replace on conflict so that if same APN is present in db with edited
                 // as UNEDITED or USER/CARRIER_DELETED, it is replaced with
@@ -3047,8 +3386,8 @@
                     throw new UnsupportedOperationException(
                             "Cannot update URL " + url + " with a where clause");
                 }
-                if (!values.containsKey(EDITED)) {
-                    values.put(EDITED, CARRIER_EDITED);
+                if (!values.containsKey(EDITED_STATUS)) {
+                    values.put(EDITED_STATUS, CARRIER_EDITED);
                 }
 
                 try {
@@ -3126,6 +3465,24 @@
                 break;
             }
 
+            case URL_SIMINFO_USING_SUBID:
+                String subIdString = url.getLastPathSegment();
+                try {
+                    subId = Integer.parseInt(subIdString);
+                } catch (NumberFormatException e) {
+                    loge("NumberFormatException" + e);
+                    throw new IllegalArgumentException("Invalid subId " + url);
+                }
+                if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
+                if (where != null || whereArgs != null) {
+                    throw new UnsupportedOperationException(
+                            "Cannot update URL " + url + " with a where clause");
+                }
+                count = db.update(SIMINFO_TABLE, values, _ID + "=?",
+                        new String[] { subIdString});
+                uriType = URL_SIMINFO_USING_SUBID;
+                break;
+
             case URL_SIMINFO: {
                 count = db.update(SIMINFO_TABLE, values, where, whereArgs);
                 uriType = URL_SIMINFO;
@@ -3138,10 +3495,52 @@
         }
 
         if (count > 0) {
+            boolean usingSubId = false;
             switch (uriType) {
+                case URL_SIMINFO_USING_SUBID:
+                    usingSubId = true;
+                    // intentional fall through from above case
                 case URL_SIMINFO:
+                    // skip notifying descendant URLs to avoid unneccessary wake up.
+                    // If not set, any change to SIMINFO will notify observers which listens to
+                    // specific field of SIMINFO.
                     getContext().getContentResolver().notifyChange(
-                            SubscriptionManager.CONTENT_URI, null, true, UserHandle.USER_ALL);
+                            SubscriptionManager.CONTENT_URI, null,
+                            ContentResolver.NOTIFY_SYNC_TO_NETWORK
+                                    | ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS,
+                            UserHandle.USER_ALL);
+                    // notify observers on specific user settings changes.
+                    if (values.containsKey(SubscriptionManager.WFC_IMS_ENABLED)) {
+                        getContext().getContentResolver().notifyChange(
+                                getNotifyContentUri(SubscriptionManager.WFC_ENABLED_CONTENT_URI,
+                                        usingSubId, subId), null, true, UserHandle.USER_ALL);
+                    }
+                    if (values.containsKey(SubscriptionManager.ENHANCED_4G_MODE_ENABLED)) {
+                        getContext().getContentResolver().notifyChange(
+                                getNotifyContentUri(SubscriptionManager
+                                                .ADVANCED_CALLING_ENABLED_CONTENT_URI,
+                                        usingSubId, subId), null, true, UserHandle.USER_ALL);
+                    }
+                    if (values.containsKey(SubscriptionManager.VT_IMS_ENABLED)) {
+                        getContext().getContentResolver().notifyChange(
+                                getNotifyContentUri(SubscriptionManager.VT_ENABLED_CONTENT_URI,
+                                        usingSubId, subId), null, true, UserHandle.USER_ALL);
+                    }
+                    if (values.containsKey(SubscriptionManager.WFC_IMS_MODE)) {
+                        getContext().getContentResolver().notifyChange(
+                                getNotifyContentUri(SubscriptionManager.WFC_MODE_CONTENT_URI,
+                                        usingSubId, subId), null, true, UserHandle.USER_ALL);
+                    }
+                    if (values.containsKey(SubscriptionManager.WFC_IMS_ROAMING_MODE)) {
+                        getContext().getContentResolver().notifyChange(getNotifyContentUri(
+                                SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI,
+                                usingSubId, subId), null, true, UserHandle.USER_ALL);
+                    }
+                    if (values.containsKey(SubscriptionManager.WFC_IMS_ROAMING_ENABLED)) {
+                        getContext().getContentResolver().notifyChange(getNotifyContentUri(
+                                SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI,
+                                usingSubId, subId), null, true, UserHandle.USER_ALL);
+                    }
                     break;
                 default:
                     getContext().getContentResolver().notifyChange(
@@ -3152,6 +3551,10 @@
         return count;
     }
 
+    private static Uri getNotifyContentUri(Uri uri, boolean usingSubId, int subId) {
+        return (usingSubId) ? Uri.withAppendedPath(uri, "" + subId) : uri;
+    }
+
     private void checkPermission() {
         int status = getContext().checkCallingOrSelfPermission(
                 "android.permission.WRITE_APN_SETTINGS");
@@ -3165,7 +3568,7 @@
         TelephonyManager telephonyManager =
                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
         for (String pkg : packages) {
-            if (telephonyManager.checkCarrierPrivilegesForPackage(pkg) ==
+            if (telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(pkg) ==
                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                 return;
             }
@@ -3209,7 +3612,7 @@
         editorApn.apply();
 
         if (apnSourceServiceExists(getContext())) {
-            restoreApnsWithService();
+            restoreApnsWithService(subId);
         } else {
             initDatabaseWithDatabaseHelper(db);
         }
@@ -3233,7 +3636,8 @@
                 String mvnoType = cursor.getString(0 /* MVNO_TYPE index */);
                 String mvnoMatchData = cursor.getString(1 /* MVNO_MATCH_DATA index */);
                 if (!TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)
-                        && ApnSetting.mvnoMatches(iccRecords, mvnoType, mvnoMatchData)) {
+                        && ApnSettingUtils.mvnoMatches(iccRecords,
+                        ApnSetting.getMvnoTypeIntFromString(mvnoType), mvnoMatchData)) {
                     where = NUMERIC + "='" + simOperator + "'"
                             + " AND " + MVNO_TYPE + "='" + mvnoType + "'"
                             + " AND " + MVNO_MATCH_DATA + "='" + mvnoMatchData + "'"
@@ -3289,12 +3693,60 @@
 
         initDatabaseWithDatabaseHelper(db);
 
-        // Notify listereners of DB change since DB has been updated
+        // Notify listeners of DB change since DB has been updated
         getContext().getContentResolver().notifyChange(
                 CONTENT_URI, null, true, UserHandle.USER_ALL);
 
     }
 
+    public static void fillInMccMncStringAtCursor(Context context, SQLiteDatabase db, Cursor c) {
+        int mcc, mnc;
+        String subId;
+        try {
+            mcc = c.getInt(c.getColumnIndexOrThrow(SubscriptionManager.MCC));
+            mnc = c.getInt(c.getColumnIndexOrThrow(SubscriptionManager.MNC));
+            subId = c.getString(c.getColumnIndexOrThrow(
+                    SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID));
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Possible database corruption -- some columns not found.");
+            return;
+        }
+
+        String mccString = String.format(Locale.getDefault(), "%03d", mcc);
+        String mncString = getBestStringMnc(context, mccString, mnc);
+        ContentValues cv = new ContentValues(2);
+        cv.put(SubscriptionManager.MCC_STRING, mccString);
+        cv.put(SubscriptionManager.MNC_STRING, mncString);
+        db.update(SIMINFO_TABLE, cv,
+                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
+                new String[]{subId});
+    }
+
+    /*
+     * Find the best string-form mnc by looking up possibilities in the carrier id db.
+     * Default to the three-digit version if neither/both are valid.
+     */
+    private static String getBestStringMnc(Context context, String mcc, int mnc) {
+        if (mnc >= 100 && mnc <= 999) {
+            return String.valueOf(mnc);
+        }
+        String twoDigitMnc = String.format(Locale.getDefault(), "%02d", mnc);
+        String threeDigitMnc = "0" + twoDigitMnc;
+
+        try (
+                Cursor twoDigitMncCursor = context.getContentResolver().query(
+                        Telephony.CarrierId.All.CONTENT_URI,
+                        /* projection */ null,
+                        /* selection */ Telephony.CarrierId.All.MCCMNC + "=?",
+                        /* selectionArgs */ new String[]{mcc + twoDigitMnc}, null)
+        ) {
+            if (twoDigitMncCursor.getCount() > 0) {
+                return twoDigitMnc;
+            }
+            return threeDigitMnc;
+        }
+    }
+
     /**
      * Sync the bearer bitmask and network type bitmask when inserting and updating.
      * Since bearerBitmask is deprecating, map the networkTypeBitmask to bearerBitmask if
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index 129f4d9..ad703de 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-tag" value="TelephonyProviderTests" />
     <test class="com.android.tradefed.testtype.InstrumentationTest" >
         <option name="package" value="com.android.providers.telephony.tests" />
-        <option name="runner" value="android.test.InstrumentationTestRunner" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java b/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
index 4adcf43..e5dd6e6 100644
--- a/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
+++ b/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
@@ -68,6 +68,8 @@
     private static final String dummy_apn = "APN_DUMMY";
     private static final String dummy_iccid_prefix = "ICCID_PREFIX_DUMMY";
     private static final String dummy_name = "NAME_DUMMY";
+    private static final String dummy_access_rule =
+            "B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB51465350";
     private static final int dummy_cid = 0;
 
     private MockContextWithProvider mContext;
@@ -104,14 +106,10 @@
     private class MockContextWithProvider extends MockContext {
         private final MockContentResolver mResolver;
 
-        public MockContextWithProvider(CarrierIdProvider carrierIdProvider) {
+        public MockContextWithProvider(CarrierIdProviderTestable carrierIdProvider) {
             mResolver = new FakeContentResolver();
 
-            ProviderInfo providerInfo = new ProviderInfo();
-            providerInfo.authority = CarrierIdProvider.AUTHORITY;
-
-            // Add context to given carrierIdProvider
-            carrierIdProvider.attachInfoForTesting(this, providerInfo);
+            carrierIdProvider.initializeForTesting(this);
             Log.d(TAG, "MockContextWithProvider: carrierIdProvider.getContext(): "
                     + carrierIdProvider.getContext());
 
@@ -437,6 +435,7 @@
         contentValues.put(CarrierId.All.ICCID_PREFIX, dummy_iccid_prefix);
         contentValues.put(CarrierId.CARRIER_NAME, dummy_name);
         contentValues.put(CarrierId.CARRIER_ID, dummy_cid);
+        contentValues.put(CarrierId.All.PRIVILEGE_ACCESS_RULE, dummy_access_rule);
         return contentValues;
     }
 }
diff --git a/tests/src/com/android/providers/telephony/CarrierIdProviderTestable.java b/tests/src/com/android/providers/telephony/CarrierIdProviderTestable.java
index 8468801..9ecd93a 100644
--- a/tests/src/com/android/providers/telephony/CarrierIdProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/CarrierIdProviderTestable.java
@@ -15,6 +15,8 @@
  */
 package com.android.providers.telephony;
 
+import android.content.Context;
+import android.content.pm.ProviderInfo;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.util.Log;
@@ -51,6 +53,14 @@
         return mDbHelper.getWritableDatabase();
     }
 
+    void initializeForTesting(Context context) {
+        ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.authority = CarrierIdProvider.AUTHORITY;
+
+        // Add context to given carrierIdProvider
+        attachInfoForTesting(context, providerInfo);
+    }
+
     /**
      * An in memory DB for CarrierIdProviderTestable to use
      */
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTest.java b/tests/src/com/android/providers/telephony/RcsProviderTest.java
new file mode 100644
index 0000000..708078f
--- /dev/null
+++ b/tests/src/com/android/providers/telephony/RcsProviderTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.providers.telephony;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.app.AppOpsManager;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.net.Uri;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class RcsProviderTest {
+    private MockContentResolver mContentResolver;
+
+    @Before
+    public void setUp() {
+        RcsProvider rcsProvider = new RcsProviderTestable();
+        MockContextWithProvider context = new MockContextWithProvider(rcsProvider);
+        mContentResolver = context.getContentResolver();
+    }
+
+    // TODO(sahinc): This test isn't that useful for now as it only checks the return value. Revisit
+    // once we have more of the implementation in place.
+    @Test
+    public void testInsertThread() {
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 5);
+
+        Uri uri = mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
+        assertNull(uri);
+    }
+
+    @Test
+    public void testUpdateThread() {
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 5);
+        mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
+
+        contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 12);
+        int updateCount = mContentResolver.update(Uri.parse("content://rcs/thread"),
+                contentValues, "owner_participant=5", null);
+
+        assertEquals(1, updateCount);
+    }
+
+    class MockContextWithProvider extends MockContext {
+        private final MockContentResolver mResolver;
+
+        MockContextWithProvider(RcsProvider rcsProvider) {
+            mResolver = new MockContentResolver();
+
+            // Add authority="rcs" to given smsProvider
+            ProviderInfo providerInfo = new ProviderInfo();
+            providerInfo.authority = RcsProvider.AUTHORITY;
+            rcsProvider.attachInfoForTesting(this, providerInfo);
+            mResolver.addProvider(RcsProvider.AUTHORITY, rcsProvider);
+        }
+
+        @Override
+        public MockContentResolver getContentResolver() {
+            return mResolver;
+        }
+
+        @Override
+        public Object getSystemService(String name) {
+            switch (name) {
+                case Context.APP_OPS_SERVICE:
+                    return Mockito.mock(AppOpsManager.class);
+                case Context.TELEPHONY_SERVICE:
+                    return Mockito.mock(TelephonyManager.class);
+                default:
+                    return null;
+            }
+        }
+    }
+
+}
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTestable.java b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
new file mode 100644
index 0000000..1e4da11
--- /dev/null
+++ b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.telephony;
+
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * A subclass of RcsProvider used for testing on an in-memory database
+ */
+public class RcsProviderTestable extends RcsProvider {
+
+    @Override
+    public boolean onCreate() {
+        mDbOpenHelper = new InMemoryRcsDatabase();
+        return true;
+    }
+
+    static class InMemoryRcsDatabase extends SQLiteOpenHelper {
+        InMemoryRcsDatabase() {
+            super(null,      // no context is needed for in-memory db
+                    null,      // db file name is null for in-memory db
+                    null,      // CursorFactory is null by default
+                    1);        // db version is no-op for tests
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            RcsProviderHelper.createRcsTables(db);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            // no-op
+        }
+    }
+}
diff --git a/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java b/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java
index fd15d01..c5ad5a0 100644
--- a/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java
+++ b/tests/src/com/android/providers/telephony/ServiceStateProviderTest.java
@@ -87,7 +87,6 @@
         ServiceStateTable.CDMA_ERI_ICON_INDEX,
         ServiceStateTable.CDMA_ERI_ICON_MODE,
         ServiceStateTable.IS_EMERGENCY_ONLY,
-        ServiceStateTable.IS_DATA_ROAMING_FROM_REGISTRATION,
         ServiceStateTable.IS_USING_CARRIER_AGGREGATION,
     };
 
@@ -188,7 +187,6 @@
         final int cdmaEriIconIndex = ss.getCdmaEriIconIndex();
         final int cdmaEriIconMode = ss.getCdmaEriIconMode();
         final int isEmergencyOnly = (ss.isEmergencyOnly()) ? 1 : 0;
-        final int isDataRoamingFromRegistration = (ss.getDataRoamingFromRegistration()) ? 1 : 0;
         final int isUsingCarrierAggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
 
         assertEquals(voiceRegState, cursor.getInt(0));
@@ -210,8 +208,7 @@
         assertEquals(cdmaEriIconIndex, cursor.getInt(16));
         assertEquals(cdmaEriIconMode, cursor.getInt(17));
         assertEquals(isEmergencyOnly, cursor.getInt(18));
-        assertEquals(isDataRoamingFromRegistration, cursor.getInt(19));
-        assertEquals(isUsingCarrierAggregation, cursor.getInt(20));
+        assertEquals(isUsingCarrierAggregation, cursor.getInt(19));
     }
 
     /**
diff --git a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
new file mode 100644
index 0000000..6892673
--- /dev/null
+++ b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.telephony;
+
+import static android.provider.Telephony.Carriers;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.support.test.InstrumentationRegistry;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public final class TelephonyDatabaseHelperTest {
+
+    private final static String TAG = TelephonyDatabaseHelperTest.class.getSimpleName();
+
+    private Context mContext;
+    private TelephonyProvider.DatabaseHelper mHelper; // the actual class being tested
+    private SQLiteOpenHelper mInMemoryDbHelper; // used to give us an in-memory db
+
+    @Before
+    public void setUp() {
+        Log.d(TAG, "setUp() +");
+        mContext = InstrumentationRegistry.getContext();
+        mHelper = new TelephonyProvider.DatabaseHelper(mContext);
+        mInMemoryDbHelper = new InMemoryTelephonyProviderV5DbHelper();
+        Log.d(TAG, "setUp() -");
+    }
+
+    @Test
+    public void databaseHelperOnUpgrade_hasApnSetIdField() {
+        Log.d(TAG, "databaseHelperOnUpgrade_hasApnSetIdField");
+        // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
+        SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
+
+        // the upgraded db must have the APN_SET_ID field
+        Cursor cursor = db.query("carriers", null, null, null, null, null, null);
+        String[] upgradedColumns = cursor.getColumnNames();
+        Log.d(TAG, "carriers columns: " + Arrays.toString(upgradedColumns));
+
+        assertTrue(Arrays.asList(upgradedColumns).contains(Carriers.APN_SET_ID));
+    }
+
+    @Test
+    public void databaseHelperOnUpgrade_hasCarrierIdField() {
+        Log.d(TAG, "databaseHelperOnUpgrade_hasSubscriptionTypeField");
+        // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
+        SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
+
+        // the upgraded db must have the Telephony.Carriers.CARRIER_ID field
+        Cursor cursor = db.query("carriers", null, null, null, null, null, null);
+        String[] upgradedColumns = cursor.getColumnNames();
+        Log.d(TAG, "carriers columns: " + Arrays.toString(upgradedColumns));
+        assertTrue(Arrays.asList(upgradedColumns).contains(Carriers.CARRIER_ID));
+    }
+
+    @Test
+    public void databaseHelperOnUpgrade_hasCountryIsoField() {
+        Log.d(TAG, "databaseHelperOnUpgrade_hasCountryIsoField");
+        SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
+
+        // the upgraded db must have the Telephony.Carriers.CARRIER_ID field
+        Cursor cursor = db.query("simInfo", null, null, null, null, null, null);
+        String[] upgradedColumns = cursor.getColumnNames();
+        Log.d(TAG, "iso columns: " + Arrays.toString(upgradedColumns));
+        assertTrue(Arrays.asList(upgradedColumns).contains(SubscriptionManager.ISO_COUNTRY_CODE));
+    }
+
+    @Test
+    public void databaseHelperOnUpgrade_columnsMatchNewlyCreatedDb() {
+        Log.d(TAG, "databaseHelperOnUpgrade_columnsMatchNewlyCreatedDb");
+        // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
+        SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
+
+        // compare upgraded carriers table to a carriers table created from scratch
+        db.execSQL(TelephonyProvider.getStringForCarrierTableCreation("carriers_full"));
+
+        Cursor cursor = db.query("carriers", null, null, null, null, null, null);
+        String[] upgradedColumns = cursor.getColumnNames();
+        Log.d(TAG, "carriers columns: " + Arrays.toString(upgradedColumns));
+
+        cursor = db.query("carriers_full", null, null, null, null, null, null);
+        String[] fullColumns = cursor.getColumnNames();
+        Log.d(TAG, "carriers_full colunmns: " + Arrays.toString(fullColumns));
+
+        assertArrayEquals("Carriers table from onUpgrade doesn't match full table",
+                fullColumns, upgradedColumns);
+
+        // compare upgraded siminfo table to siminfo table created from scratch
+        db.execSQL(TelephonyProvider.getStringForSimInfoTableCreation("siminfo_full"));
+
+        cursor = db.query("siminfo", null, null, null, null, null, null);
+        upgradedColumns = cursor.getColumnNames();
+        Log.d(TAG, "siminfo columns: " + Arrays.toString(upgradedColumns));
+
+        cursor = db.query("siminfo_full", null, null, null, null, null, null);
+        fullColumns = cursor.getColumnNames();
+        Log.d(TAG, "siminfo_full colunmns: " + Arrays.toString(fullColumns));
+
+        assertArrayEquals("Siminfo table from onUpgrade doesn't match full table",
+                fullColumns, upgradedColumns);
+    }
+
+    /**
+     * Helper for an in memory DB used to test the TelephonyProvider#DatabaseHelper.
+     *
+     * We pass this in-memory db to DatabaseHelper#onUpgrade so we can use the actual function
+     * without using the actual telephony db.
+     */
+    private static class InMemoryTelephonyProviderV5DbHelper extends SQLiteOpenHelper {
+
+        public InMemoryTelephonyProviderV5DbHelper() {
+            super(InstrumentationRegistry.getContext(),
+                    null,    // db file name is null for in-memory db
+                    null,    // CursorFactory is null by default
+                    1);      // in-memory db version doesn't seem to matter
+            Log.d(TAG, "InMemoryTelephonyProviderV5DbHelper creating in-memory database");
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            // Set up the carriers table without any fields added in onUpgrade
+            // since these are the initial fields, there is no need to update this test fixture in
+            // the future
+            List<String> originalUniqueFields = new ArrayList<String>();
+            originalUniqueFields.add(Carriers.NUMERIC);
+            originalUniqueFields.add(Carriers.MCC);
+            originalUniqueFields.add(Carriers.MNC);
+            originalUniqueFields.add(Carriers.APN);
+            originalUniqueFields.add(Carriers.PROXY);
+            originalUniqueFields.add(Carriers.PORT);
+            originalUniqueFields.add(Carriers.MMSPROXY);
+            originalUniqueFields.add(Carriers.MMSPORT);
+            originalUniqueFields.add(Carriers.MMSC);
+            Log.d(TAG, "InMemoryTelephonyProviderV5DbHelper onCreate creating the carriers table");
+            db.execSQL(
+                    "CREATE TABLE carriers" +
+                    "(_id INTEGER PRIMARY KEY," +
+                    Carriers.NAME + " TEXT DEFAULT ''," +
+                    Carriers.NUMERIC + " TEXT DEFAULT ''," +
+                    Carriers.MCC + " TEXT DEFAULT ''," +
+                    Carriers.MNC + " TEXT DEFAULT ''," +
+                    Carriers.APN + " TEXT DEFAULT ''," +
+                    Carriers.USER + " TEXT DEFAULT ''," +
+                    Carriers.SERVER + " TEXT DEFAULT ''," +
+                    Carriers.PASSWORD + " TEXT DEFAULT ''," +
+                    Carriers.PROXY + " TEXT DEFAULT ''," +
+                    Carriers.PORT + " TEXT DEFAULT ''," +
+                    Carriers.MMSPROXY + " TEXT DEFAULT ''," +
+                    Carriers.MMSPORT + " TEXT DEFAULT ''," +
+                    Carriers.MMSC + " TEXT DEFAULT ''," +
+                    Carriers.TYPE + " TEXT DEFAULT ''," +
+                    Carriers.CURRENT + " INTEGER," +
+                    "UNIQUE (" + TextUtils.join(", ", originalUniqueFields) + "));");
+
+            // set up the siminfo table without any fields added in onUpgrade
+            // since these are the initial fields, there is no need to update this test fixture in
+            // the future
+            Log.d(TAG, "InMemoryTelephonyProviderV5DbHelper onCreate creating the siminfo table");
+            db.execSQL(
+                    "CREATE TABLE siminfo ("
+                    + SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
+                    + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+                    + SubscriptionManager.ICC_ID + " TEXT NOT NULL,"
+                    + SubscriptionManager.SIM_SLOT_INDEX
+                        + " INTEGER DEFAULT " + SubscriptionManager.SIM_NOT_INSERTED + ","
+                    + SubscriptionManager.DISPLAY_NAME + " TEXT,"
+                    + SubscriptionManager.NAME_SOURCE
+                        + " INTEGER DEFAULT " + SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE + ","
+                    + SubscriptionManager.COLOR
+                        + " INTEGER DEFAULT " + SubscriptionManager.COLOR_DEFAULT + ","
+                    + SubscriptionManager.NUMBER + " TEXT,"
+                    + SubscriptionManager.DISPLAY_NUMBER_FORMAT + " INTEGER NOT NULL"
+                        + " DEFAULT " + SubscriptionManager.DISPLAY_NUMBER_DEFAULT + ","
+                    + SubscriptionManager.DATA_ROAMING
+                        + " INTEGER DEFAULT " + SubscriptionManager.DATA_ROAMING_DEFAULT + ","
+                    + SubscriptionManager.CARD_ID + " TEXT NOT NULL"
+                    + ");");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.d(TAG, "InMemoryTelephonyProviderV5DbHelper onUpgrade doing nothing");
+            return;
+        }
+    }
+}
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index dde9e5c..b77e5cf 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -16,59 +16,39 @@
 
 package com.android.providers.telephony;
 
-import android.annotation.TargetApi;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.Manifest;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
 import android.content.res.Resources;
-import android.content.SharedPreferences;
-import android.database.Cursor;
 import android.database.ContentObserver;
-import android.database.DatabaseErrorHandler;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.Cursor;
 import android.net.Uri;
-import android.os.Build;
-import android.os.FileUtils;
 import android.os.Process;
+import android.provider.Telephony;
 import android.provider.Telephony.Carriers;
 import android.support.test.InstrumentationRegistry;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 import android.test.mock.MockContext;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.providers.telephony.TelephonyProvider;
-
 import junit.framework.TestCase;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Map;
-import java.util.Set;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
 
 
 /**
@@ -92,11 +72,14 @@
 
     private int notifyChangeCount;
     private int notifyChangeRestoreCount;
+    private int notifyWfcCount;
+    private int notifyWfcCountWithTestSubId;
 
     private static final String TEST_SUBID = "1";
     private static final String TEST_OPERATOR = "123456";
     private static final String TEST_MCC = "123";
     private static final String TEST_MNC = "456";
+
     // Used to test the path for URL_TELEPHONY_USING_SUBID with subid 1
     private static final Uri CONTENT_URI_WITH_SUBID = Uri.parse(
             "content://telephony/carriers/subId/" + TEST_SUBID);
@@ -107,6 +90,10 @@
     // Used to test the preferred apn
     private static final Uri URL_PREFERAPN_USING_SUBID = Uri.parse(
             "content://telephony/carriers/preferapn/subId/" + TEST_SUBID);
+    private static final Uri URL_WFC_ENABLED_USING_SUBID = Uri.parse(
+            "content://telephony/siminfo/" + TEST_SUBID);
+    private static final Uri URL_SIM_APN_LIST = Uri.parse(
+        "content://telephony/carriers/sim_apn_list");
 
     private static final String COLUMN_APN_ID = "apn_id";
 
@@ -126,6 +113,10 @@
         private final MockContentResolver mResolver;
         private TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
 
+        private final List<String> GRANTED_PERMISSIONS = Arrays.asList(
+                Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.WRITE_APN_SETTINGS,
+                Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+
         public MockContextWithProvider(TelephonyProvider telephonyProvider) {
             mResolver = new MockContentResolver() {
                 @Override
@@ -134,6 +125,10 @@
                     notifyChangeCount++;
                     if (URL_RESTOREAPN_USING_SUBID.equals(uri)) {
                         notifyChangeRestoreCount++;
+                    } else if (SubscriptionManager.WFC_ENABLED_CONTENT_URI.equals(uri)) {
+                        notifyWfcCount++;
+                    } else if (URL_WFC_ENABLED_USING_SUBID.equals(uri)) {
+                        notifyWfcCountWithTestSubId++;
                     }
                 }
             };
@@ -141,6 +136,9 @@
             // return test subId 0 for all operators
             doReturn(TEST_OPERATOR).when(mTelephonyManager).getSimOperator(anyInt());
 
+            doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+            doReturn(TEST_OPERATOR).when(mTelephonyManager).getSimOperator();
+
             // Add authority="telephony" to given telephonyProvider
             ProviderInfo providerInfo = new ProviderInfo();
             providerInfo.authority = "telephony";
@@ -186,7 +184,7 @@
         // Gives permission to write to the APN table within the MockContext
         @Override
         public int checkCallingOrSelfPermission(String permission) {
-            if (TextUtils.equals(permission, "android.permission.WRITE_APN_SETTINGS")) {
+            if (GRANTED_PERMISSIONS.contains(permission)) {
                 Log.d(TAG, "checkCallingOrSelfPermission: permission=" + permission
                         + ", returning PackageManager.PERMISSION_GRANTED");
                 return PackageManager.PERMISSION_GRANTED;
@@ -287,6 +285,64 @@
     }
 
     /**
+     * Test migrating int-based MCC/MNCs over to Strings in the sim info table
+     */
+    @Test
+    @SmallTest
+    public void testMccMncMigration() {
+        CarrierIdProviderTestable carrierIdProvider = new CarrierIdProviderTestable();
+        carrierIdProvider.initializeForTesting(mContext);
+        mContentResolver.addProvider(Telephony.CarrierId.All.CONTENT_URI.getAuthority(),
+                carrierIdProvider);
+        // Insert a few values into the carrier ID db
+        List<String> mccMncs = Arrays.asList("99910", "999110", "999060", "99905");
+        ContentValues[] carrierIdMccMncs = mccMncs.stream()
+                .map((mccMnc) -> {
+                    ContentValues cv = new ContentValues(1);
+                    cv.put(Telephony.CarrierId.All.MCCMNC, mccMnc);
+                    return cv;
+                }).toArray(ContentValues[]::new);
+        mContentResolver.bulkInsert(Telephony.CarrierId.All.CONTENT_URI, carrierIdMccMncs);
+
+        // Populate the sim info db with int-format entries
+        ContentValues[] existingSimInfoEntries = IntStream.range(0, mccMncs.size())
+                .mapToObj((idx) -> {
+                    int mcc = Integer.valueOf(mccMncs.get(idx).substring(0, 3));
+                    int mnc = Integer.valueOf(mccMncs.get(idx).substring(3));
+                    ContentValues cv = new ContentValues(4);
+                    cv.put(SubscriptionManager.MCC, mcc);
+                    cv.put(SubscriptionManager.MNC, mnc);
+                    cv.put(SubscriptionManager.ICC_ID, String.valueOf(idx));
+                    cv.put(SubscriptionManager.CARD_ID, String.valueOf(idx));
+                    return cv;
+        }).toArray(ContentValues[]::new);
+
+        mContentResolver.bulkInsert(SubscriptionManager.CONTENT_URI, existingSimInfoEntries);
+
+        // Run the upgrade helper on all the sim info entries.
+        String[] proj = {SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
+                SubscriptionManager.MCC, SubscriptionManager.MNC,
+                SubscriptionManager.MCC_STRING, SubscriptionManager.MNC_STRING};
+        try (Cursor c = mContentResolver.query(SubscriptionManager.CONTENT_URI, proj,
+                null, null, null)) {
+            while (c.moveToNext()) {
+                TelephonyProvider.fillInMccMncStringAtCursor(mContext,
+                        mTelephonyProviderTestable.getWritableDatabase(), c);
+            }
+        }
+
+        // Loop through and make sure that everything got filled in correctly.
+        try (Cursor c = mContentResolver.query(SubscriptionManager.CONTENT_URI, proj,
+                null, null, null)) {
+            while (c.moveToNext()) {
+                String mcc = c.getString(c.getColumnIndexOrThrow(SubscriptionManager.MCC_STRING));
+                String mnc = c.getString(c.getColumnIndexOrThrow(SubscriptionManager.MNC_STRING));
+                assertTrue(mccMncs.contains(mcc + mnc));
+            }
+        }
+    }
+
+    /**
      * Test updating values in carriers table. Verify that when update hits a conflict using URL_ID
      * we merge the rows.
      */
@@ -546,7 +602,7 @@
         mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID);
 
         final int current = 1;
-        final String numeric = "123456789";
+        final String numeric = TEST_OPERATOR;
 
         // Insert DPC record.
         final String dpcRecordApn = "exampleApnNameDPC";
@@ -1017,7 +1073,7 @@
         editedValue.put(Carriers.NUMERIC, numeric1);
         editedValue.put(Carriers.MCC, mcc1);
         editedValue.put(Carriers.MNC, mnc1);
-        editedValue.put(Carriers.EDITED, value);
+        editedValue.put(Carriers.EDITED_STATUS, value);
         assertNotNull(mContentResolver.insert(URI_TELEPHONY, editedValue));
 
         Cursor cur = mContentResolver.query(URI_TELEPHONY, null, null, null, null);
@@ -1030,13 +1086,13 @@
         values.put(Carriers.NUMERIC, numeric1);
         values.put(Carriers.MCC, mcc1);
         values.put(Carriers.MNC, mnc1);
-        values.put(Carriers.EDITED, Carriers.UNEDITED);
+        values.put(Carriers.EDITED_STATUS, Carriers.UNEDITED);
         mContentResolver.insert(URI_TELEPHONY, values);
 
         String[] testProjection = {
             Carriers.NAME,
             Carriers.APN,
-            Carriers.EDITED,
+            Carriers.EDITED_STATUS,
             Carriers.TYPE,
             Carriers.PROTOCOL,
             Carriers.BEARER_BITMASK,
@@ -1064,7 +1120,7 @@
         editedValue.put(Carriers.NUMERIC, numeric1);
         editedValue.put(Carriers.MCC, mcc1);
         editedValue.put(Carriers.MNC, mnc1);
-        editedValue.put(Carriers.EDITED, value);
+        editedValue.put(Carriers.EDITED_STATUS, value);
         assertNotNull(mContentResolver.insert(URI_TELEPHONY, editedValue));
 
         // insert APN that conflicts with edited APN
@@ -1074,13 +1130,13 @@
         values.put(Carriers.NUMERIC, numeric1);
         values.put(Carriers.MCC, mcc1);
         values.put(Carriers.MNC, mnc1);
-        values.put(Carriers.EDITED, Carriers.UNEDITED);
+        values.put(Carriers.EDITED_STATUS, Carriers.UNEDITED);
         mContentResolver.insert(URI_TELEPHONY, values);
 
         String[] testProjection = {
             Carriers.NAME,
             Carriers.APN,
-            Carriers.EDITED,
+            Carriers.EDITED_STATUS,
             Carriers.TYPE,
             Carriers.PROTOCOL,
             Carriers.BEARER_BITMASK,
@@ -1339,4 +1395,140 @@
         assertEquals(0, cursor.getCount());
         assertEquals(3, notifyChangeRestoreCount);
     }
+
+    /**
+     * Test changes to siminfo/WFC_IMS_ENABLED and simInfo/ENHANCED_4G
+     */
+    @Test
+    @SmallTest
+    public void testUpdateWfcEnabled() {
+        // insert test contentValues
+        ContentValues contentValues = new ContentValues();
+        final int insertSubId = 1;
+        final String insertDisplayName = "exampleDisplayName";
+        final String insertCarrierName = "exampleCarrierName";
+        final String insertIccId = "exampleIccId";
+        final String insertCardId = "exampleCardId";
+        contentValues.put(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID, insertSubId);
+        contentValues.put(SubscriptionManager.DISPLAY_NAME, insertDisplayName);
+        contentValues.put(SubscriptionManager.CARRIER_NAME, insertCarrierName);
+        contentValues.put(SubscriptionManager.ICC_ID, insertIccId);
+        contentValues.put(SubscriptionManager.CARD_ID, insertCardId);
+
+        Log.d(TAG, "testSimTable Inserting wfc contentValues: " + contentValues);
+        mContentResolver.insert(SubscriptionManager.CONTENT_URI, contentValues);
+        assertEquals(0, notifyWfcCount);
+
+        // update wfc_enabled
+        ContentValues values = new ContentValues();
+        values.put(SubscriptionManager.WFC_IMS_ENABLED, true);
+        final String selection = SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=?";
+        final String[] selectionArgs = { "" + insertSubId };
+        mContentResolver.update(SubscriptionManager.CONTENT_URI, values, selection, selectionArgs);
+        assertEquals(1, notifyWfcCount);
+        assertEquals(0, notifyWfcCountWithTestSubId);
+
+        // update other fields
+        values = new ContentValues();
+        values.put(SubscriptionManager.DISPLAY_NAME, "exampleDisplayNameNew");
+        mContentResolver.update(SubscriptionManager.CONTENT_URI, values, selection, selectionArgs);
+        // expect no change on wfc count
+        assertEquals(1, notifyWfcCount);
+        assertEquals(0, notifyWfcCountWithTestSubId);
+
+        // update WFC using subId
+        values = new ContentValues();
+        values.put(SubscriptionManager.WFC_IMS_ENABLED, false);
+        mContentResolver.update(SubscriptionManager.getUriForSubscriptionId(insertSubId),
+                values, null, null);
+        assertEquals(1, notifyWfcCount);
+        assertEquals(0, notifyWfcCountWithTestSubId);
+    }
+
+    @Test
+    @SmallTest
+    public void testSIMAPNLIST_APNMatchTheMCCMNCAndMVNO() {
+        // Test on getCurrentAPNList() step 1
+        TelephonyManager telephonyManager =
+                ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE));
+        doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
+
+        final String apnName = "apnName";
+        final String carrierName = "name";
+        final String numeric = TEST_OPERATOR;
+        final String mvnoType = "spn";
+        final String mvnoData = TelephonyProviderTestable.TEST_SPN;
+        final int carrierId = 100;
+        doReturn(carrierId).when(telephonyManager).getSimCarrierId();
+        doReturn(numeric).when(telephonyManager).getSimOperator();
+
+        // Insert the APN and DB only have the MCC/MNC and MVNO APN
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(Carriers.APN, apnName);
+        contentValues.put(Carriers.NAME, carrierName);
+        contentValues.put(Carriers.NUMERIC, numeric);
+        contentValues.put(Carriers.MVNO_TYPE, mvnoType);
+        contentValues.put(Carriers.MVNO_MATCH_DATA, mvnoData);
+        mContentResolver.insert(Carriers.CONTENT_URI, contentValues);
+
+        // Query DB
+        final String[] testProjection =
+            {
+                Carriers.APN,
+                Carriers.NAME,
+                Carriers.NUMERIC,
+                Carriers.MVNO_MATCH_DATA
+            };
+        Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
+                testProjection, null, null, null);
+
+        cursor.moveToFirst();
+        assertEquals(apnName, cursor.getString(0));
+        assertEquals(carrierName, cursor.getString(1));
+        assertEquals(numeric, cursor.getString(2));
+        assertEquals(mvnoData, cursor.getString(3));
+    }
+
+    @Test
+    @SmallTest
+    public void testSIMAPNLIST_APNMatchTheParentMCCMNC() {
+        // Test on getCurrentAPNList() step 2
+        TelephonyManager telephonyManager =
+                ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE));
+        doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
+
+        final String apnName = "apnName";
+        final String carrierName = "name";
+        final String numeric = TEST_OPERATOR;
+        final String mvnoData = TelephonyProviderTestable.TEST_SPN;
+        final int carrierId = 100;
+        final int mnoCarrierId = 101;
+
+        doReturn(carrierId).when(telephonyManager).getSimCarrierId();
+        doReturn(numeric).when(telephonyManager).getSimOperator();
+        doReturn(mvnoData).when(telephonyManager).getSimOperatorName();
+        doReturn(mnoCarrierId).when(telephonyManager).getSimMNOCarrierId();
+
+        // Insert the APN and DB only have the MNO APN
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(Carriers.APN, apnName);
+        contentValues.put(Carriers.NAME, carrierName);
+        contentValues.put(Carriers.NUMERIC, numeric);
+        mContentResolver.insert(Carriers.CONTENT_URI, contentValues);
+
+        // Query DB
+        final String[] testProjection =
+            {
+                Carriers.APN,
+                Carriers.NAME,
+                Carriers.NUMERIC,
+            };
+        Cursor cursor = mContentResolver.query(URL_SIM_APN_LIST,
+                testProjection, null, null, null);
+
+        cursor.moveToFirst();
+        assertEquals(apnName, cursor.getString(0));
+        assertEquals(carrierName, cursor.getString(1));
+        assertEquals(numeric, cursor.getString(2));
+    }
 }