Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3aa2e12a authored by Fan Zhang's avatar Fan Zhang Committed by Android (Google) Code Review
Browse files

Merge "Create a helper lib for emergency numbers."

parents 96bda51b 51ef7406
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ java_defaults {
        "SettingsLibRadioButtonPreference",
        "SettingsLibDisplayDensityUtils",
        "SettingsLibUtils",
        "SettingsLibEmergencyNumber",
        "SettingsLibTopIntroPreference",
    ],
}
+10 −0
Original line number Diff line number Diff line
android_library {
    name: "SettingsLibEmergencyNumber",

    srcs: ["src/**/*.java"],
    static_libs: [
        "androidx.annotation_annotation",
    ],
    sdk_version: "system_current",
    min_sdk_version: "21",
}
+23 −0
Original line number Diff line number Diff line
<?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>
+133 −0
Original line number Diff line number Diff line
/*
 * 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());
    }
}
+124 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}