Create a helper lib for emergency numbers.

This util class manages getting/setting default emergency numbers,
shared by settings, EmergencyInfo and other clients.

The logic is copied from Personal Safety app - http://shortn/_Z7qtV6RpJG

Bug: 172609395
Test: manual
Change-Id: I9062d84f49556d2b7e7866c43d64dac55d48f4f4
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 3af4b25..64dc2af 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -51,6 +51,7 @@
         "SettingsLibRadioButtonPreference",
         "SettingsLibDisplayDensityUtils",
         "SettingsLibUtils",
+        "SettingsLibEmergencyNumber",
         "SettingsLibTopIntroPreference",
     ],
 }
diff --git a/packages/SettingsLib/EmergencyNumber/Android.bp b/packages/SettingsLib/EmergencyNumber/Android.bp
new file mode 100644
index 0000000..3c41f78
--- /dev/null
+++ b/packages/SettingsLib/EmergencyNumber/Android.bp
@@ -0,0 +1,10 @@
+android_library {
+    name: "SettingsLibEmergencyNumber",
+
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.annotation_annotation",
+    ],
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/EmergencyNumber/AndroidManifest.xml b/packages/SettingsLib/EmergencyNumber/AndroidManifest.xml
new file mode 100644
index 0000000..b877fc4
--- /dev/null
+++ b/packages/SettingsLib/EmergencyNumber/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.emergencynumber">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
new file mode 100644
index 0000000..12d21ca
--- /dev/null
+++ b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 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.settingslib.emergencynumber;
+
+import static android.telephony.emergency.EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE;
+import static android.telephony.emergency.EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Util class to help manage emergency numbers
+ */
+public class EmergencyNumberUtils {
+    private static final String TAG = "EmergencyNumberUtils";
+    private static final String EMERGENCY_GESTURE_CALL_NUMBER = "emergency_gesture_call_number";
+    @VisibleForTesting
+    static final String FALL_BACK_NUMBER = "112";
+
+    private final Context mContext;
+    private final TelephonyManager mTelephonyManager;
+
+
+    public EmergencyNumberUtils(Context context) {
+        mContext = context;
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            mTelephonyManager = context.getSystemService(TelephonyManager.class);
+        } else {
+            mTelephonyManager = null;
+        }
+    }
+
+    /**
+     * Returns the most appropriate number for police.
+     */
+    public String getDefaultPoliceNumber() {
+        if (mTelephonyManager == null) {
+            return FALL_BACK_NUMBER;
+        }
+        final List<EmergencyNumber> promotedPoliceNumber = getPromotedEmergencyNumbers(
+                EMERGENCY_SERVICE_CATEGORY_POLICE);
+        if (promotedPoliceNumber == null || promotedPoliceNumber.isEmpty()) {
+            return FALL_BACK_NUMBER;
+        }
+        return promotedPoliceNumber.get(0).getNumber();
+    }
+
+    /**
+     * Returns the number chosen by user. If user has not provided any number, use default ({@link
+     * #getDefaultPoliceNumber()}).
+     */
+    public String getPoliceNumber() {
+        final String userProvidedNumber = Settings.Secure.getString(mContext.getContentResolver(),
+                EMERGENCY_GESTURE_CALL_NUMBER);
+        return TextUtils.isEmpty(userProvidedNumber)
+                ? getDefaultPoliceNumber() : userProvidedNumber;
+    }
+
+    private List<EmergencyNumber> getPromotedEmergencyNumbers(int categories) {
+        Map<Integer, List<EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList(
+                categories);
+        if (allLists == null || allLists.isEmpty()) {
+            Log.w(TAG, "Unable to retrieve emergency number lists!");
+            return new ArrayList<>();
+        }
+        Map<Integer, List<EmergencyNumber>> promotedEmergencyNumberLists = new ArrayMap<>();
+        for (Map.Entry<Integer, List<EmergencyNumber>> entry : allLists.entrySet()) {
+            if (entry.getKey() == null || entry.getValue() == null) {
+                continue;
+            }
+            List<EmergencyNumber> emergencyNumberList = entry.getValue();
+            Log.d(TAG, "Emergency numbers for subscription id " + entry.getKey());
+
+            // The list of promoted emergency numbers which will be visible on shortcut view.
+            List<EmergencyNumber> promotedList = new ArrayList<>();
+            // A temporary list for non-prioritized emergency numbers.
+            List<EmergencyNumber> tempList = new ArrayList<>();
+
+            for (EmergencyNumber emergencyNumber : emergencyNumberList) {
+                // Emergency numbers in DATABASE are prioritized since they were well-categorized.
+                boolean isFromPrioritizedSource =
+                        emergencyNumber.getEmergencyNumberSources().contains(
+                                EMERGENCY_NUMBER_SOURCE_DATABASE);
+
+                Log.d(TAG, String.format("Number %s, isFromPrioritizedSource %b",
+                        emergencyNumber, isFromPrioritizedSource));
+                if (isFromPrioritizedSource) {
+                    promotedList.add(emergencyNumber);
+                } else {
+                    tempList.add(emergencyNumber);
+                }
+            }
+            // Puts numbers in temp list after prioritized numbers.
+            promotedList.addAll(tempList);
+
+            if (!promotedList.isEmpty()) {
+                promotedEmergencyNumberLists.put(entry.getKey(), promotedList);
+            }
+        }
+
+        if (promotedEmergencyNumberLists.isEmpty()) {
+            Log.w(TAG, "No promoted emergency number found!");
+        }
+        return promotedEmergencyNumberLists.get(SubscriptionManager.getDefaultSubscriptionId());
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
new file mode 100644
index 0000000..1403631
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.settingslib.emergencynumber;
+
+import static android.telephony.emergency.EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
+import android.util.ArrayMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(RobolectricTestRunner.class)
+public class EmergencyNumberUtilsTest {
+    private static final String TELEPHONY_EMERGENCY_NUMBER = "1234";
+    private static final String USER_OVERRIDE_EMERGENCY_NUMBER = "5678";
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    private EmergencyNumberUtils mUtils;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+    }
+
+    @Test
+    public void getDefaultPoliceNumber_noTelephony_shouldReturnDefault() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+        mUtils = new EmergencyNumberUtils(mContext);
+
+        assertThat(mUtils.getDefaultPoliceNumber()).isEqualTo(
+                EmergencyNumberUtils.FALL_BACK_NUMBER);
+    }
+
+    @Test
+    public void getDefaultPoliceNumber_hasTelephony_shouldLoadFromTelephony() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+        addEmergencyNumberToTelephony();
+        mUtils = new EmergencyNumberUtils(mContext);
+
+
+        assertThat(mUtils.getDefaultPoliceNumber()).isEqualTo(TELEPHONY_EMERGENCY_NUMBER);
+    }
+
+    @Test
+    public void getPoliceNumber_hasUserOverride_shouldLoadFromUserOverride() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+        addEmergencyNumberToTelephony();
+
+        ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
+        when(mContext.getContentResolver()).thenReturn(resolver);
+        Settings.Secure.putString(resolver, Settings.Secure.EMERGENCY_GESTURE_CALL_NUMBER,
+                USER_OVERRIDE_EMERGENCY_NUMBER);
+
+        mUtils = new EmergencyNumberUtils(mContext);
+
+        assertThat(mUtils.getPoliceNumber()).isEqualTo(USER_OVERRIDE_EMERGENCY_NUMBER);
+    }
+
+    @Test
+    public void getPoliceNumber_noUserOverride_shouldLoadFromTelephony() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+        addEmergencyNumberToTelephony();
+
+        mUtils = new EmergencyNumberUtils(mContext);
+
+        assertThat(mUtils.getPoliceNumber()).isEqualTo(TELEPHONY_EMERGENCY_NUMBER);
+    }
+
+    private void addEmergencyNumberToTelephony() {
+        final int subId = SubscriptionManager.getDefaultSubscriptionId();
+        EmergencyNumber emergencyNumber = mock(EmergencyNumber.class);
+        Map<Integer, List<EmergencyNumber>> numbers = new ArrayMap<>();
+        List<EmergencyNumber> numbersForSubId = new ArrayList<>();
+        numbersForSubId.add(emergencyNumber);
+        numbers.put(subId, numbersForSubId);
+        when(mTelephonyManager.getEmergencyNumberList(
+                EMERGENCY_SERVICE_CATEGORY_POLICE)).thenReturn(numbers);
+        when(emergencyNumber.getNumber()).thenReturn(TELEPHONY_EMERGENCY_NUMBER);
+    }
+}