Merge "Create new API for MNO carrier id"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 30760dc..c2f88c5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -214,7 +214,8 @@
         <activity android:name="EmergencyDialer"
             android:label="@string/emergencyDialerIconLabel"
             android:theme="@style/EmergencyDialerTheme"
-            android:screenOrientation="portrait">
+            android:screenOrientation="portrait"
+            android:resizeableActivity="false">
             <intent-filter>
                 <action android:name="com.android.phone.EmergencyDialer.DIAL" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
index 54be16b..403cad7 100644
--- a/ecc/input/eccdata.txt
+++ b/ecc/input/eccdata.txt
@@ -808,7 +808,7 @@
 countries {
   iso_code: "GB"
   eccs {
-    phone_number: "112"
+    phone_number: "999"
     types: POLICE
     types: AMBULANCE
     types: FIRE
diff --git a/ecc/output/eccdata b/ecc/output/eccdata
index 2d0165a..679bc36 100644
--- a/ecc/output/eccdata
+++ b/ecc/output/eccdata
Binary files differ
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 1619aa1..cb12cbb 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -357,10 +357,14 @@
                 CarrierConfigManager.KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL);
         Log.d(LOG_TAG, "Is the carrier supported: " + isSupport);
         TelephonyManager tm = getSystemService(TelephonyManager.class);
-        if (isSupport && !TextUtils.isEmpty(tm.getNetworkCountryIso())) {
-            mAreEmergencyDialerShortcutsEnabled = true;
-        } else {
-            mAreEmergencyDialerShortcutsEnabled = false;
+        String countryIso = tm.getNetworkCountryIso();
+        mAreEmergencyDialerShortcutsEnabled = false;
+        if (isSupport && !TextUtils.isEmpty(countryIso)) {
+            if (EccInfoHelper.isCountryEccInfoAvailable(this, countryIso)) {
+                mAreEmergencyDialerShortcutsEnabled = true;
+            } else {
+                Log.d(LOG_TAG, "ECC info is unavailable. Disable emergency dialer shortcut.");
+            }
         }
         Log.d(LOG_TAG, "Enable emergency dialer shortcut: "
                 + mAreEmergencyDialerShortcutsEnabled);
@@ -458,7 +462,7 @@
         mEmergencyInfoGroup = (EmergencyInfoGroup) findViewById(R.id.emergency_info_button);
 
         if (mAreEmergencyDialerShortcutsEnabled) {
-            mEccInfoHelper = new EccInfoHelper(new IsoToEccProtobufRepository());
+            mEccInfoHelper = new EccInfoHelper(IsoToEccProtobufRepository.getInstance());
             setupEmergencyShortcutsView();
         }
     }
@@ -928,7 +932,7 @@
         AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
         int ringerMode = audioManager.getRingerMode();
         if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
-            || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
+                || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
             return;
         }
 
@@ -1054,8 +1058,8 @@
                 boolean isCellAvailable =
                         ss.getRilVoiceRadioTechnology() != RIL_RADIO_TECHNOLOGY_UNKNOWN;
                 Log.i(LOG_TAG, "showWfcWarningTask: isWfcAvailable=" + isWfcAvailable
-                                + " isCellAvailable=" + isCellAvailable
-                                + "(rat=" + ss.getRilVoiceRadioTechnology() + ")");
+                        + " isCellAvailable=" + isCellAvailable
+                        + "(rat=" + ss.getRilVoiceRadioTechnology() + ")");
                 return isWfcAvailable && !isCellAvailable;
             }
 
diff --git a/src/com/android/phone/PhoneApp.java b/src/com/android/phone/PhoneApp.java
index df151bf..333e0ec 100644
--- a/src/com/android/phone/PhoneApp.java
+++ b/src/com/android/phone/PhoneApp.java
@@ -19,6 +19,7 @@
 import android.app.Application;
 import android.os.UserHandle;
 
+import com.android.phone.ecc.IsoToEccProtobufRepository;
 import com.android.services.telephony.TelecomAccountRegistry;
 
 /**
@@ -40,5 +41,10 @@
 
             TelecomAccountRegistry.getInstance(this).setupOnBoot();
         }
+
+        new Thread(() -> {
+            // Preload ECC table in background.
+            IsoToEccProtobufRepository.getInstance().loadMappingTable(PhoneApp.this);
+        }).start();
     }
 }
diff --git a/src/com/android/phone/ecc/EccInfoHelper.java b/src/com/android/phone/ecc/EccInfoHelper.java
index cd47dde..c471c4b 100644
--- a/src/com/android/phone/ecc/EccInfoHelper.java
+++ b/src/com/android/phone/ecc/EccInfoHelper.java
@@ -50,6 +50,32 @@
     private static final boolean DBG = false;
     private static final String LOG_TAG = "EccInfoHelper";
 
+    /**
+     * Check if current CountryEccInfo is available for current environment.
+     */
+    public static boolean isCountryEccInfoAvailable(Context context, String countryIso) {
+        CountryEccInfo countryEccInfo;
+        try {
+            countryEccInfo = IsoToEccProtobufRepository.getInstance()
+                    .getCountryEccInfo(context, countryIso);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Failed to retrieve ECC: ", e);
+            return false;
+        }
+
+        if (countryEccInfo == null) {
+            return false;
+        }
+        for (EccInfo entry : countryEccInfo.getEccInfoList()) {
+            if (!PhoneNumberUtils.isEmergencyNumber(entry.getNumber())) {
+                // The CountryEccInfo is unavailable if any ecc number in the local table was
+                // declined.
+                return false;
+            }
+        }
+        return true;
+    }
+
     // country ISO to ECC list data source
     private IsoToEccRepository mEccRepo;
 
@@ -136,7 +162,8 @@
         }.execute();
     }
 
-    private @NonNull CountryEccInfo getDialableCountryEccInfo(CountryEccInfo countryEccInfo) {
+    @NonNull
+    private CountryEccInfo getDialableCountryEccInfo(CountryEccInfo countryEccInfo) {
         ArrayList<EccInfo> dialableECCList = new ArrayList<>();
         String dialableFallback = null;
 
@@ -155,7 +182,8 @@
         return new CountryEccInfo(dialableFallback, dialableECCList);
     }
 
-    private @Nullable String getCurrentCountryIso(@NonNull Context context) {
+    @Nullable
+    private String getCurrentCountryIso(@NonNull Context context) {
         // Do not detect country ISO if airplane mode is on
         int airplaneMode = Settings.System.getInt(context.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0);
@@ -185,7 +213,8 @@
     // XXX: According to ServiceStateTracker implementation, to actually get current cell info,
     // this method must be called in a separate thread from ServiceStateTracker, which is the
     // main thread of Telephony service.
-    private @Nullable String getCurrentMccFromCellInfo(@NonNull Context context) {
+    @Nullable
+    private String getCurrentMccFromCellInfo(@NonNull Context context) {
         // retrieve mcc info from base station even no SIM present.
         TelephonyManager tm = (TelephonyManager) context.getSystemService(
                 Context.TELEPHONY_SERVICE);
diff --git a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
index 817ff1d..0cd3108 100644
--- a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
+++ b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
@@ -40,7 +40,22 @@
 public class IsoToEccProtobufRepository implements IsoToEccRepository {
     private static final String LOG_TAG = "EccRepository";
 
-    private Map<String, CountryEccInfo> mEccTable = null;
+    private static IsoToEccProtobufRepository sInstance;
+
+    /**
+     * Returns the singleton instance of IsoToEccProtobufRepository
+     */
+    public static synchronized IsoToEccProtobufRepository getInstance() {
+        if (sInstance == null) {
+            sInstance = new IsoToEccProtobufRepository();
+        }
+        return sInstance;
+    }
+
+    private final Map<String, CountryEccInfo> mEccTable = new HashMap<>();
+
+    private IsoToEccProtobufRepository() {
+    }
 
     @Override
     @Nullable
@@ -50,24 +65,28 @@
             return null;
         }
 
-        if (mEccTable == null) {
-            mEccTable = initMappingTable(context);
+        synchronized (mEccTable) {
+            return mEccTable.get(iso.toUpperCase());
         }
-        return mEccTable.get(iso.toUpperCase());
     }
 
-    private Map<String, CountryEccInfo> initMappingTable(@NonNull Context context)
-            throws IOException {
+    /**
+     * Loads the mapping table.
+     */
+    public void loadMappingTable(@NonNull Context context) {
         ProtobufEccData.AllInfo allEccData = null;
 
         long startTime = SystemClock.uptimeMillis();
-        allEccData = parseEccData(new BufferedInputStream(
-                context.getAssets().open("eccdata")));
+        try {
+            allEccData = parseEccData(new BufferedInputStream(
+                    context.getAssets().open("eccdata")));
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Failed to retrieve ECC: ", e);
+        }
         long endTime = SystemClock.uptimeMillis();
 
         if (allEccData == null) {
-            // Returns an empty table.
-            return new HashMap<>();
+            return;
         }
 
         if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
@@ -77,16 +96,17 @@
         }
 
         // 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);
+        synchronized (mEccTable) {
+            mEccTable.clear();
+            for (ProtobufEccData.CountryInfo countryData : allEccData.getCountriesList()) {
+                if (countryData.hasIsoCode()) {
+                    CountryEccInfo countryInfo = loadCountryEccInfo(countryData);
+                    if (countryInfo != null) {
+                        mEccTable.put(countryData.getIsoCode().toUpperCase(), countryInfo);
+                    }
                 }
             }
         }
-        return table;
     }
 
     private ProtobufEccData.AllInfo parseEccData(InputStream input) throws IOException {
diff --git a/testapps/TelephonyRegistryTestApp/AndroidManifest.xml b/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
index 5f19509..708ea66 100644
--- a/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
+++ b/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
@@ -18,6 +18,7 @@
           package="com.android.phone.testapps.telephonyregistry">
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
     <application android:label="TelephonyRegistryTestApp">
         <activity
             android:name=".TelephonyRegistryTestApp"
diff --git a/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java b/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java
index 8593245..74cafcd 100644
--- a/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java
+++ b/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java
@@ -54,7 +54,7 @@
         put(PhoneStateListener.LISTEN_PRECISE_CALL_STATE, "PRECISE_CALL_STATE");
         put(PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE,
                 "PRECISE_DATA_CONNECTION_STATE");
-        put(PhoneStateListener.LISTEN_VOLTE_STATE, "VOLTE_STATE");
+        put(PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED, "SRVCC_STATE");
         put(PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE, "CARRIER_NETWORK_CHANGE");
         put(PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE, "VOICE_ACTIVATION_STATE");
         put(PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE, "DATA_ACTIVATION_STATE");
@@ -71,6 +71,11 @@
             notify("onCellInfoChanged", cellInfo);
         }
 
+        @Override
+        public void onSrvccStateChanged(int srvccState) {
+            notify("onSrvccStateChanged", srvccState);
+        }
+
         private void notify(String method, Object data) {
             Notification.Builder builder = new Notification.Builder(TelephonyRegistryTestApp.this,
                     NOTIFICATION_CHANNEL);