Introduce Emergency Number Tracker

- Introduce EmergencyNumberTracker that handles the radio indication
of emergency number updates and the update of ECC database based on
the country ISO
- Configure ecc-protos-lite library to be ready to use Eccdata
- Introduce RIL commands for the indication and PhoneStateListener
- Add dumpy system for EmergencyNumberTracker
- Deploy some implementation in TelephonyRegistry,
 TelephonyComponentFactory, and Phone classes, to be ready to further
 connect with the API implementation
- Implement EmergencyNumberTrackerTest

Test: Treehugger; atest EmergencyNumberTrackerTest
Bug: 112657134
Change-Id: I13d41044dc431e26ae0ca3b1cd7bba234a86364e
Merged-In: I13d41044dc431e26ae0ca3b1cd7bba234a86364e
(cherry picked from commit 4d489c6f74b39de43a3bae4fdcfb5bfb7c20aac9)
diff --git a/Android.bp b/Android.bp
index 9f5459b..80070b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,6 +47,7 @@
     ],
     static_libs: [
         "telephony-protos",
+        "ecc-protos-lite",
         "android.hardware.radio-V1.0-java",
         "android.hardware.radio-V1.1-java",
         "android.hardware.radio-V1.2-java",
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index d5e7e0c..2695951 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -78,6 +78,7 @@
     protected RegistrantList mNattKeepaliveStatusRegistrants = new RegistrantList();
     protected RegistrantList mPhysicalChannelConfigurationRegistrants = new RegistrantList();
     protected RegistrantList mLceInfoRegistrants = new RegistrantList();
+    protected RegistrantList mEmergencyNumberListRegistrants = new RegistrantList();
 
     protected Registrant mGsmSmsRegistrant;
     protected Registrant mCdmaSmsRegistrant;
@@ -783,6 +784,17 @@
         mSubscriptionStatusRegistrants.remove(h);
     }
 
+    @Override
+    public void registerForEmergencyNumberList(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+        mEmergencyNumberListRegistrants.add(r);
+    }
+
+    @Override
+    public void unregisterForEmergencyNumberList(Handler h) {
+        mEmergencyNumberListRegistrants.remove(h);
+    }
+
     //***** Protected Methods
     /**
      * Store new RadioState and send notification based on the changes
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 8b39e8b..cda5cd7 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -2221,6 +2221,22 @@
     void unregisterForNattKeepaliveStatus(Handler h);
 
     /**
+     * Register for unsolicited Emergency Number List Indications
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForEmergencyNumberList(Handler h, int what, Object obj);
+
+    /**
+     * Deregister for unsolicited Emergency Number List Indications
+     *
+     * @param h Handler for notification message.
+     */
+    void unregisterForEmergencyNumberList(Handler h);
+
+    /**
      * Start sending NATT Keepalive packets on a specified data connection
      *
      * @param contextId cid that identifies the data connection for this keepalive
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index c4701f7..ee2a9bb 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -31,6 +31,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
+import android.telephony.emergency.EmergencyNumber;
 
 import java.util.List;
 
@@ -362,6 +363,19 @@
         }
     }
 
+    @Override
+    public void notifyEmergencyNumberList(Phone sender,
+                                          List<EmergencyNumber> emergencyNumberList) {
+        int subId = sender.getSubId();
+        try {
+            if (mRegistry != null) {
+                mRegistry.notifyEmergencyNumberList(emergencyNumberList);
+            }
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
     /**
      * Convert the {@link Phone.DataActivityState} enum into the TelephonyManager.DATA_* constants
      * for the public API.
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 3e7e4db..3e7f5a7 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -78,6 +78,7 @@
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.GsmMmiCode;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.test.SimulatedRadioControl;
@@ -169,6 +170,7 @@
     private IsimUiccRecords mIsimUiccRecords;
     public GsmCdmaCallTracker mCT;
     public ServiceStateTracker mSST;
+    public EmergencyNumberTracker mEmergencyNumberTracker;
     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
     // Used for identify the carrier of current subscription
@@ -228,6 +230,8 @@
         mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this);
         mTransportManager = mTelephonyComponentFactory.makeTransportManager(this);
         mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
+        mEmergencyNumberTracker = mTelephonyComponentFactory.makeEmergencyNumberTracker(
+                this, this.mCi);
         // DcTracker uses SST so needs to be created after it is instantiated
         for (int transport : mTransportManager.getAvailableTransports()) {
             mDcTrackers.put(transport, mTelephonyComponentFactory.makeDcTracker(this,
@@ -476,6 +480,11 @@
     }
 
     @Override
+    public EmergencyNumberTracker getEmergencyNumberTracker() {
+        return mEmergencyNumberTracker;
+    }
+
+    @Override
     public CallTracker getCallTracker() {
         return mCT;
     }
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 1738b59..b232b48 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -57,6 +57,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.ApnSetting.ApnType;
+import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.text.TextUtils;
 import android.util.SparseArray;
@@ -68,6 +69,7 @@
 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -1629,6 +1631,13 @@
     }
 
     /**
+     * Retrieves the EmergencyNumberTracker of the phone instance.
+     */
+    public EmergencyNumberTracker getEmergencyNumberTracker() {
+        return null;
+    }
+
+    /**
     * Get call tracker
     */
     public CallTracker getCallTracker() {
@@ -2246,6 +2255,11 @@
         mNotifier.notifySrvccStateChanged(this, state);
     }
 
+    /** Notify the list of {@link EmergencyNumber} changes. */
+    public void notifyEmergencyNumberList(List<EmergencyNumber> emergencyNumberList) {
+        mNotifier.notifyEmergencyNumberList(this, emergencyNumberList);
+    }
+
     /**
      * @return true if a mobile originating emergency call is active
      */
@@ -3922,6 +3936,17 @@
             pw.println("++++++++++++++++++++++++++++++++");
         }
 
+        if (getEmergencyNumberTracker() != null) {
+            try {
+                getEmergencyNumberTracker().dump(fd, pw, args);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            pw.flush();
+            pw.println("++++++++++++++++++++++++++++++++");
+        }
+
         if (mCarrierActionAgent != null) {
             try {
                 mCarrierActionAgent.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 0568187..30b53d7 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -21,6 +21,7 @@
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 
 import java.util.List;
 
@@ -78,4 +79,7 @@
     public void notifyPhoneCapabilityChanged(PhoneCapability capability);
 
     void notifyRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state);
+
+    /** Notify of change to EmergencyNumberList. */
+    void notifyEmergencyNumberList(Phone sender, List<EmergencyNumber> emergencyNumberList);
 }
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 4522d8a..588e8db 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -27,6 +27,7 @@
 import com.android.internal.telephony.cdma.EriManager;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -66,6 +67,13 @@
     }
 
     /**
+     * Create a new EmergencyNumberTracker.
+     */
+    public EmergencyNumberTracker makeEmergencyNumberTracker(Phone phone, CommandsInterface ci) {
+        return new EmergencyNumberTracker(phone, ci);
+    }
+
+    /**
      * Sets the NitzStateMachine implementation to use during implementation. This boolean
      * should be removed once the new implementation is stable.
      */
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
new file mode 100644
index 0000000..5425f2b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -0,0 +1,180 @@
+/*
+ * 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.internal.telephony.emergency;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.telephony.Rlog;
+import android.telephony.emergency.EmergencyNumber;
+import android.util.LocalLog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.phone.ecc.nano.ProtobufEccData;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Emergency Number Tracker that handles update of emergency number list from RIL and emergency
+ * number database. This is multi-sim based and each Phone has a EmergencyNumberTracker.
+ */
+public class EmergencyNumberTracker extends Handler {
+    private static final String TAG = EmergencyNumberTracker.class.getSimpleName();
+
+    /** @hide */
+    public static boolean DBG = false;
+
+    private final CommandsInterface mCi;
+    private final Phone mPhone;
+    private List<EmergencyNumber> mEmergencyNumberListFromDatabase = new ArrayList<>();
+    private List<EmergencyNumber> mEmergencyNumberListFromRadio = new ArrayList<>();
+    private List<EmergencyNumber> mEmergencyNumberList = new ArrayList<>();
+
+    private final LocalLog mEmergencyNumberListDatabaseLocalLog = new LocalLog(20);
+    private final LocalLog mEmergencyNumberListRadioLocalLog = new LocalLog(20);
+    private final LocalLog mEmergencyNumberListLocalLog = new LocalLog(20);
+
+    /** Event indicating the update for the emergency number list from the radio. */
+    private static final int EVENT_UNSOL_EMERGENCY_NUMBER_LIST = 1;
+
+    // TODO EVENT_UPDATE_NETWORK_COUNTRY_ISO
+
+    public EmergencyNumberTracker(Phone phone, CommandsInterface ci) {
+        mPhone = phone;
+        mCi = ci;
+        // TODO cache Emergency Number List Database per country ISO;
+        // TODO register for Locale Tracker Country ISO Change
+        mCi.registerForEmergencyNumberList(this, EVENT_UNSOL_EMERGENCY_NUMBER_LIST, null);
+    }
+
+    /**
+     * Message handler for updating emergency number list from RIL, updating emergency number list
+     * from database if the country ISO is changed, and notifying the change of emergency number
+     * list.
+     *
+     * @param msg The message
+     */
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case EVENT_UNSOL_EMERGENCY_NUMBER_LIST:
+                AsyncResult ar = (AsyncResult) msg.obj;
+                if (ar.result == null) {
+                    loge("EVENT_UNSOL_EMERGENCY_NUMBER_LIST: Result from RIL is null.");
+                } else if ((ar.result != null) && (ar.exception == null)) {
+                    updateAndNotifyEmergencyNumberList((List<EmergencyNumber>) ar.result);
+                } else {
+                    loge("EVENT_UNSOL_EMERGENCY_NUMBER_LIST: Exception from RIL : "
+                            + ar.exception);
+                }
+                break;
+        }
+    }
+
+    private void updateAndNotifyEmergencyNumberList(
+            List<EmergencyNumber> emergencyNumberListRadio) {
+        Collections.sort(emergencyNumberListRadio);
+        logd("updateAndNotifyEmergencyNumberList(): receiving " + emergencyNumberListRadio);
+
+        if (!emergencyNumberListRadio.equals(mEmergencyNumberListFromRadio)) {
+            try {
+                mEmergencyNumberListFromRadio = emergencyNumberListRadio;
+                if (!DBG) {
+                    mEmergencyNumberListRadioLocalLog.log("updateRadioEmergencyNumberList:"
+                            + emergencyNumberListRadio);
+                }
+                List<EmergencyNumber> emergencyNumberListMergedWithDatabase =
+                        constructEmergencyNumberListWithDatabase();
+                mEmergencyNumberList = emergencyNumberListMergedWithDatabase;
+                if (!DBG) {
+                    mEmergencyNumberListLocalLog.log("updateEmergencyNumberList:"
+                            + emergencyNumberListMergedWithDatabase);
+                }
+                notifyEmergencyNumberList();
+            } catch (NullPointerException ex) {
+                loge("updateAndNotifyEmergencyNumberList() Phone already destroyed: " + ex
+                        + "EmergencyNumberList not notified");
+            }
+        }
+    }
+
+    private void notifyEmergencyNumberList() {
+        List<EmergencyNumber> emergencyNumberListToNotify = getEmergencyNumberList();
+        mPhone.notifyEmergencyNumberList(emergencyNumberListToNotify);
+        logd("notifyEmergencyNumberList():" + emergencyNumberListToNotify);
+    }
+
+    private List<EmergencyNumber> constructEmergencyNumberListWithDatabase() {
+        List<EmergencyNumber> emergencyNumberListRadioAndDatabase = mEmergencyNumberListFromRadio;
+        // TODO integrate with emergency number database
+        // TODO sorting
+        return emergencyNumberListRadioAndDatabase;
+    }
+
+    public List<EmergencyNumber> getEmergencyNumberList() {
+        return new ArrayList<>(mEmergencyNumberList);
+    }
+
+    @VisibleForTesting
+    public List<EmergencyNumber> getRadioEmergencyNumberList() {
+        return new ArrayList<>(mEmergencyNumberListFromRadio);
+    }
+
+    private static void logd(String str) {
+        Rlog.d(TAG, str);
+    }
+
+    private static void loge(String str) {
+        Rlog.e(TAG, str);
+    }
+
+    /**
+     * Dump Emergency Number List info in the tracking
+     *
+     * @param fd FileDescriptor
+     * @param pw PrintWriter
+     * @param args args
+     */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.println("mEmergencyNumberListDatabaseLocalLog:");
+        ipw.increaseIndent();
+        mEmergencyNumberListDatabaseLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+        ipw.println("   -   -   -   -   -   -   -   -");
+
+        ipw.println("mEmergencyNumberListRadioLocalLog:");
+        ipw.increaseIndent();
+        mEmergencyNumberListRadioLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+        ipw.println("   -   -   -   -   -   -   -   -");
+
+        ipw.println("mEmergencyNumberListLocalLog:");
+        ipw.increaseIndent();
+        mEmergencyNumberListLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+
+        ipw.flush();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index 4460489..5cb130b 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -1422,6 +1422,14 @@
     }
 
     @Override
+    public void registerForEmergencyNumberList(Handler h, int what, Object obj) {
+    }
+
+    @Override
+    public void unregisterForEmergencyNumberList(Handler h) {
+    }
+
+    @Override
     public void startNattKeepalive(
             int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 0642e31..e4aabb6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -61,6 +61,7 @@
 import com.android.internal.telephony.cdma.EriManager;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -104,6 +105,8 @@
     @Mock
     protected ServiceStateTracker mSST;
     @Mock
+    protected EmergencyNumberTracker mEmergencyNumberTracker;
+    @Mock
     protected GsmCdmaCallTracker mCT;
     @Mock
     protected ImsPhoneCallTracker mImsCT;
@@ -339,6 +342,9 @@
         doReturn(mSST).when(mTelephonyComponentFactory)
                 .makeServiceStateTracker(nullable(GsmCdmaPhone.class),
                         nullable(CommandsInterface.class));
+        doReturn(mEmergencyNumberTracker).when(mTelephonyComponentFactory)
+                .makeEmergencyNumberTracker(nullable(Phone.class),
+                        nullable(CommandsInterface.class));
         doReturn(mUiccProfile).when(mTelephonyComponentFactory)
                 .makeUiccProfile(nullable(Context.class), nullable(CommandsInterface.class),
                         nullable(IccCardStatus.class), anyInt(), nullable(UiccCard.class),
@@ -390,6 +396,7 @@
         doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mPhone).getPhoneType();
         doReturn(mCT).when(mPhone).getCallTracker();
         doReturn(mSST).when(mPhone).getServiceStateTracker();
+        doReturn(mEmergencyNumberTracker).when(mPhone).getEmergencyNumberTracker();
         doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent();
         doReturn(mCarrierActionAgent).when(mPhone).getCarrierActionAgent();
         doReturn(mAppSmsManager).when(mPhone).getAppSmsManager();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
new file mode 100644
index 0000000..11936f5
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.internal.telephony.emergency;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.AsyncResult;
+import android.os.HandlerThread;
+import android.telephony.emergency.EmergencyNumber;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for EmergencyNumberTracker.java
+ */
+public class EmergencyNumberTrackerTest extends TelephonyTest {
+
+    private EmergencyNumberTracker mEmergencyNumberTrackerMock;
+    private List<EmergencyNumber> mEmergencyNumberListTestSample = new ArrayList<>();
+    private static final long TIMEOUT_MS = 500;
+
+    private class EmergencyNumberTrackerTestHandler extends HandlerThread {
+        private EmergencyNumberTrackerTestHandler(String name) {
+            super(name);
+        }
+        @Override
+        public void onLooperPrepared() {
+            mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands);
+            mEmergencyNumberTrackerMock.DBG = true;
+            setReady(true);
+        }
+    }
+
+    private EmergencyNumberTrackerTestHandler mHandlerThread;
+
+    @Before
+    public void setUp() throws Exception {
+        logd("EmergencyNumberTrackerTest +Setup!");
+        super.setUp("EmergencyNumberTrackerTest");
+        initializeEmergencyNumberListTestSamples();
+        mHandlerThread = new EmergencyNumberTrackerTestHandler("EmergencyNumberTrackerTestHandler");
+        mHandlerThread.start();
+        waitUntilReady();
+        logd("EmergencyNumberTrackerTest -Setup!");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+        mHandlerThread.join();
+        super.tearDown();
+    }
+
+    private void initializeEmergencyNumberListTestSamples() {
+        EmergencyNumber emergencyNumberForTest = new EmergencyNumber("119", "jp",
+                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
+                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
+        mEmergencyNumberListTestSample.add(emergencyNumberForTest);
+    }
+
+    private void sendEmergencyNumberListFromRadio() {
+        mEmergencyNumberTrackerMock.sendMessage(
+                mEmergencyNumberTrackerMock.obtainMessage(
+                        1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */,
+                        new AsyncResult(null, mEmergencyNumberListTestSample, null)));
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+    }
+
+    @Test
+    public void testEmergencyNumberListFromRadio() throws Exception {
+        sendEmergencyNumberListFromRadio();
+        assertEquals(mEmergencyNumberListTestSample,
+                mEmergencyNumberTrackerMock.getRadioEmergencyNumberList());
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
index df5552a..19906bd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
@@ -28,6 +28,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
+import android.telephony.emergency.EmergencyNumber;
 
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.IPhoneStateListener;
@@ -361,6 +362,11 @@
     }
 
     @Override
+    public void notifyEmergencyNumberList(List<EmergencyNumber> emergencyNumberList) {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
     public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
             int backgroundCallState) {
         throw new RuntimeException("Not implemented");