Use emergency phone number local database.

Load emergency phone number database from built-in assets.

Test: Manually
Bug: 111674784
Change-Id: Ic149e49cfb5d12b9415018df82bf854ca6168392
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index a89b52d..7e5b1ce 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -73,6 +73,7 @@
 import com.android.phone.common.widget.ResizingTextEditText;
 import com.android.phone.ecc.CountryEccInfo;
 import com.android.phone.ecc.EccInfoHelper;
+import com.android.phone.ecc.IsoToEccProtobufRepository;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -324,6 +325,7 @@
         mEmergencyActionGroup = (EmergencyActionGroup) findViewById(R.id.emergency_action_group);
 
         if (mAreEmergencyDialerShortcutsEnabled) {
+            mEccInfoHelper = new EccInfoHelper(new IsoToEccProtobufRepository());
             setupEmergencyShortcutsView();
         }
     }
diff --git a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
new file mode 100644
index 0000000..817ff1d
--- /dev/null
+++ b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
@@ -0,0 +1,157 @@
+/*
+ * 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.phone.ecc;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Provides a mapping table from country ISO to ECC info. The data is stored in Protocol Buffers
+ * binary format, compressed with GZIP.
+ */
+public class IsoToEccProtobufRepository implements IsoToEccRepository {
+    private static final String LOG_TAG = "EccRepository";
+
+    private Map<String, CountryEccInfo> mEccTable = null;
+
+    @Override
+    @Nullable
+    public CountryEccInfo getCountryEccInfo(@NonNull Context context, String iso)
+            throws IOException {
+        if (TextUtils.isEmpty(iso)) {
+            return null;
+        }
+
+        if (mEccTable == null) {
+            mEccTable = initMappingTable(context);
+        }
+        return mEccTable.get(iso.toUpperCase());
+    }
+
+    private Map<String, CountryEccInfo> initMappingTable(@NonNull Context context)
+            throws IOException {
+        ProtobufEccData.AllInfo allEccData = null;
+
+        long startTime = SystemClock.uptimeMillis();
+        allEccData = parseEccData(new BufferedInputStream(
+                context.getAssets().open("eccdata")));
+        long endTime = SystemClock.uptimeMillis();
+
+        if (allEccData == null) {
+            // Returns an empty table.
+            return new HashMap<>();
+        }
+
+        if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
+            Log.d(LOG_TAG, "Loading time = " + (endTime - startTime) + "ms"
+                    + ", Country Count = " + allEccData.getCountriesCount()
+                    + ", initialized = " + allEccData.isInitialized());
+        }
+
+        // Converts to run-time data from Protobuf data.
+        Map<String, CountryEccInfo> table = new HashMap<>();
+        for (ProtobufEccData.CountryInfo countryData : allEccData.getCountriesList()) {
+            if (countryData.hasIsoCode()) {
+                CountryEccInfo countryInfo = loadCountryEccInfo(countryData);
+                if (countryInfo != null) {
+                    table.put(countryData.getIsoCode().toUpperCase(), countryInfo);
+                }
+            }
+        }
+        return table;
+    }
+
+    private ProtobufEccData.AllInfo parseEccData(InputStream input) throws IOException {
+        return ProtobufEccData.AllInfo.parseFrom(new GZIPInputStream(input));
+    }
+
+    private EccInfo loadEccInfo(String isoCode, ProtobufEccData.EccInfo eccData) {
+        String phoneNumber = eccData.getPhoneNumber().trim();
+        if (phoneNumber.isEmpty()) {
+            Log.i(LOG_TAG, "Discard ecc " + phoneNumber
+                    + " for " + isoCode + " due to empty phone number");
+            return null;
+        }
+
+        ArraySet<EccInfo.Type> eccTypes = new ArraySet<>(eccData.getTypesCount());
+        for (ProtobufEccData.EccInfo.Type typeData : eccData.getTypesList()) {
+            switch (typeData) {
+                case POLICE:
+                    eccTypes.add(EccInfo.Type.POLICE);
+                    break;
+                case AMBULANCE:
+                    eccTypes.add(EccInfo.Type.AMBULANCE);
+                    break;
+                case FIRE:
+                    eccTypes.add(EccInfo.Type.FIRE);
+                    break;
+                default:
+                    // Ignores unknown types.
+            }
+        }
+
+        if (eccTypes.isEmpty()) {
+            Log.i(LOG_TAG, "Discard ecc " + phoneNumber
+                    + " for " + isoCode + " due to no valid type");
+            return null;
+        }
+        return new EccInfo(phoneNumber, eccTypes);
+    }
+
+    private CountryEccInfo loadCountryEccInfo(ProtobufEccData.CountryInfo countryData) {
+        ArrayMap<String, EccInfo> eccInfoMap = new ArrayMap<>(countryData.getEccsCount());
+        for (ProtobufEccData.EccInfo eccData : countryData.getEccsList()) {
+            EccInfo eccInfo = loadEccInfo(countryData.getIsoCode(), eccData);
+            String key = eccInfo.getNumber().trim();
+            EccInfo existentEccInfo = eccInfoMap.get(key);
+            if (existentEccInfo == null) {
+                eccInfoMap.put(key, eccInfo);
+            } else {
+                // Merges types of duplicated ECC info objects.
+                ArraySet<EccInfo.Type> eccTypes = new ArraySet<>(
+                        eccInfo.getTypesCount() + existentEccInfo.getTypesCount());
+                for (EccInfo.Type type : eccInfo.getTypes()) {
+                    eccTypes.add(type);
+                }
+                for (EccInfo.Type type : existentEccInfo.getTypes()) {
+                    eccTypes.add(type);
+                }
+                eccInfoMap.put(key, new EccInfo(eccInfo.getNumber(), eccTypes));
+            }
+        }
+
+        if (eccInfoMap.isEmpty() && !countryData.hasEccFallback()) {
+            Log.i(LOG_TAG, "Discard empty data for " + countryData.getIsoCode());
+            return null;
+        }
+        return new CountryEccInfo(countryData.getEccFallback(), eccInfoMap.values());
+    }
+}