Merge "Add new team member to OWNERS file."
diff --git a/Android.mk b/Android.mk
index c6b0c7d..775d795 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,12 +8,14 @@
src_dirs := src $(phone_common_dir)/src sip/src
res_dirs := res $(phone_common_dir)/res sip/res
+asset_dirs := assets ecc/output
LOCAL_JAVA_LIBRARIES := \
telephony-common \
voip-common \
ims-common \
- org.apache.http.legacy
+ org.apache.http.legacy \
+ libprotobuf-java-lite
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.appcompat_appcompat \
@@ -26,11 +28,13 @@
volley
LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
+LOCAL_SRC_FILES += $(call all-proto-files-under, ecc/proto)
LOCAL_SRC_FILES += \
src/com/android/phone/EventLogTags.logtags \
src/com/android/phone/INetworkQueryService.aidl \
src/com/android/phone/INetworkQueryServiceCallback.aidl
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
+LOCAL_ASSET_DIR := $(addprefix $(LOCAL_PATH)/, $(asset_dirs))
LOCAL_USE_AAPT2 := true
LOCAL_AAPT_FLAGS := \
@@ -51,3 +55,4 @@
# Build the test package
include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/ecc/.gitignore b/ecc/.gitignore
new file mode 100644
index 0000000..fbf10af
--- /dev/null
+++ b/ecc/.gitignore
@@ -0,0 +1 @@
+.intermediate
diff --git a/ecc/README.md b/ecc/README.md
new file mode 100644
index 0000000..ef795d5
--- /dev/null
+++ b/ecc/README.md
@@ -0,0 +1,48 @@
+This directory contains tools and data related to ECC (Emergency Call Codes)
+data and updates.
+
+Directory structure
+===================
+
+gen_eccdata.sh
+ - A script to launch the newest conversion toolset to convert
+ input/eccdata.txt into output/eccdata, and invoke compatibility
+ verification tools of earlier versions of toolsets.
+
+input/eccdata.txt
+ - A text file in ProtoBuf text format which contains all known ECC data.
+ This file shall be compatible with the last version of format toolset,
+ but may not be compatible with all earlier versions.
+
+output/eccdata
+ - The binary file generated from input files, with the last version of
+ format toolset. This file shall be compatible with all earlier versions.
+
+conversion_toolset_v*
+ - Contains format definitions, converting tools and verification tools of
+ one version of ECC data format.
+
+proto
+ - A symbolic link references to protobuf folder of the newest version of
+ conversion toolsets. It's used in Android.mk.
+
+Conversion Toolset
+===================
+
+Every version of conversion toolset shall include at least:
+ - A script to generate eccdata from a known version of input/eccdata.txt.
+ - A script to verify compatibility of output/eccdata generated by any
+ newer version of format toolset.
+
+The output/eccdata generated by a version of conversion toolset shall be
+able to pass compatibility verifications of all previous versions of format
+toolset.
+
+Updating ECC database
+===================
+Steps to update the ECC database:
+1. Edit input/eccdata.txt
+2. Source and launch
+3. Run gen_eccdata.sh
+The database file "output/eccdata" should be updated.
+
diff --git a/ecc/conversion_toolset_v1/env.sh b/ecc/conversion_toolset_v1/env.sh
new file mode 100644
index 0000000..23d9f10
--- /dev/null
+++ b/ecc/conversion_toolset_v1/env.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+set -o errexit
+
+# Copyright 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.
+
+INPUT_DATA="${INPUT_DIR}/eccdata.txt"
+OUTPUT_DATA="${OUTPUT_DIR}/eccdata"
+PROTOBUF_DIR="${LOCAL_TOOLSET_DIR}/proto"
+PROTOBUF_FILE="${PROTOBUF_DIR}/protobuf_ecc_data.proto"
+RAW_DATA="${INTERMEDIATE_DIR}/eccdata.raw"
+
+read -d "" PYTHON_COMMAND << END || :
+${ANDROID_BUILD_TOP}/prebuilts/python/${KERNEL}-x86/2.7.5/bin/python
+END
+PYTHONPATH="${PYTHONPATH}:${INTERMEDIATE_DIR}"
+PYTHONPATH="${PYTHONPATH}:${ANDROID_BUILD_TOP}/external/nanopb-c/generator/"
+
+if ! [ -x "${PYTHON_COMMAND}" ] ; then
+ echo "Missing ${PYTHON_COMMAND}." 1>&2
+ exit 1
+fi
+
+"${PROTOC_COMMAND}" \
+ --python_out="${INTERMEDIATE_DIR}" \
+ --proto_path="${PROTOBUF_DIR}" \
+ "${PROTOBUF_FILE}"
diff --git a/ecc/conversion_toolset_v1/gen_eccdata.sh b/ecc/conversion_toolset_v1/gen_eccdata.sh
new file mode 100644
index 0000000..8dd751f
--- /dev/null
+++ b/ecc/conversion_toolset_v1/gen_eccdata.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+set -o errexit
+
+# Copyright 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.
+
+LOCAL_TOOLSET_DIR="${ECC_ROOT}/conversion_toolset_v1"
+source "${LOCAL_TOOLSET_DIR}/env.sh"
+
+${ANDROID_BUILD_TOP}/prebuilts/tools/linux-x86_64/protoc/bin/protoc \
+ --encode=ecc.AllInfo proto/protobuf_ecc_data.proto \
+ < "${INPUT_DATA}" > "${RAW_DATA}"
+
+echo
+echo "Starting strict verification"
+"${PYTHON_COMMAND}" -B \
+ "${LOCAL_TOOLSET_DIR}/verify_protobuf_compatibility.py" \
+ --input="${RAW_DATA}" --strict
+echo "Passed strict verification"
+
+echo
+echo "Compressing and encoding eccdata"
+gzip -c < "${RAW_DATA}" > "${OUTPUT_DATA}"
+echo "Done"
+
diff --git a/ecc/conversion_toolset_v1/proto/protobuf_ecc_data.proto b/ecc/conversion_toolset_v1/proto/protobuf_ecc_data.proto
new file mode 100644
index 0000000..5bd7bc3
--- /dev/null
+++ b/ecc/conversion_toolset_v1/proto/protobuf_ecc_data.proto
@@ -0,0 +1,56 @@
+syntax = "proto2";
+
+package ecc;
+
+option java_package = "com.android.phone.ecc";
+option java_outer_classname = "ProtobufEccData";
+
+// EccInfo represents an Emergency Call Code (i.e. an emergency phone
+// number such as 911, 112, ...)
+message EccInfo {
+ enum Type {
+ TYPE_UNSPECIFIED = 0;
+ POLICE = 1;
+ AMBULANCE = 2;
+ FIRE = 3;
+ }
+
+ // Required: Every EccInfo shall contain a phone number.
+ optional string phone_number = 1;
+
+ // Extra rules: Every Ecc should have at least 1 valid type.
+ repeated Type types = 2 [packed=true];
+}
+
+// CountryInfo represents available ECCs of a country/region, recognized
+// with ISO country code.
+message CountryInfo {
+ // Required: Every CountryInfo shall contain a ISO country code.
+ optional string iso_code = 1;
+
+ // Extra rules: There should be at least one EccInfo in this list.
+ repeated EccInfo eccs = 2;
+
+ // Required: Every CountryInfo shall contain a fallback number, shall
+ // be either 112 or 911.
+ //
+ // If an emergency number in EccInfo is declined by ril.ecclist, this
+ // fallback number may take the place.
+ //
+ // Per http://www.etsi.org/deliver/etsi_ts/122100_122199/122101/09.01.00_60/ts_122101v090100p.pdf,
+ // 112 and 911 shall always be available.
+ optional string ecc_fallback = 3;
+}
+
+message AllInfo {
+ // The revision value in ecc/input/eccdata.json should be increased
+ // before releasing a new content.
+ //
+ // This field is not used to compare data revision for online updating.
+ // It's reserved for identifying ecc info problems.
+ optional int32 revision = 1;
+
+ // Extra rules: There should be at least one CountryInfo in this list.
+ repeated CountryInfo countries = 2;
+}
+
diff --git a/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh b/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh
new file mode 100644
index 0000000..8686722
--- /dev/null
+++ b/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+set -o errexit
+
+# Copyright 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.
+
+LOCAL_TOOLSET_DIR="${ECC_ROOT}/conversion_toolset_v1"
+source "${LOCAL_TOOLSET_DIR}/env.sh"
+
+echo "Starting compatibility verification v1"
+echo "Decoding and decompressing eccdata"
+gunzip -c < "${OUTPUT_DATA}" > "${RAW_DATA}"
+${PYTHON_COMMAND} -B \
+ "${LOCAL_TOOLSET_DIR}/verify_protobuf_compatibility.py" \
+ --input="${RAW_DATA}"
+echo "Passed compatibility verification v1"
+
diff --git a/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py b/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py
new file mode 100644
index 0000000..bc707eb
--- /dev/null
+++ b/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py
@@ -0,0 +1,85 @@
+#!/usr/bin/python -B
+
+# Copyright 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.
+
+# Notice:
+# - verify_eccdata_strict.py: Verify data which is generated by this
+# version of this toolset.
+# - verify_eccdata_compatibility.py: Verify data which is generated by any
+# newer version of this tool set for ensuring backward compatibility.
+
+import sys
+import argparse
+import protobuf_ecc_data_pb2
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--input", required=True)
+parser.add_argument("--strict", action="store_true")
+args = parser.parse_args()
+
+all_ecc_info = protobuf_ecc_data_pb2.AllInfo()
+
+with open(args.input, "rb") as ecc_data_source_file:
+ all_ecc_info.ParseFromString(ecc_data_source_file.read())
+
+if (args.strict):
+ print("Verify in strict mode")
+
+assert all_ecc_info.HasField("revision")
+assert all_ecc_info.revision > 0
+assert len(all_ecc_info.countries) > 0
+
+loaded_iso = []
+for country_info in all_ecc_info.countries:
+ assert country_info.HasField("iso_code")
+ assert len(country_info.iso_code) > 0
+ assert country_info.iso_code == country_info.iso_code.strip().upper()
+ assert country_info.iso_code not in loaded_iso
+ loaded_iso.append(country_info.iso_code)
+ assert country_info.HasField("ecc_fallback")
+ assert len(country_info.ecc_fallback) > 0
+
+ if len(country_info.eccs) > 0:
+ loaded_phone_number = []
+ for ecc_info in country_info.eccs:
+ assert ecc_info.HasField("phone_number")
+ phone_number = ecc_info.phone_number.strip()
+ assert len(phone_number) > 0
+ assert phone_number not in loaded_phone_number
+ loaded_phone_number.append(phone_number)
+
+ if (args.strict):
+ assert len(ecc_info.types) > 0
+ loaded_types = []
+ for ecc_type in ecc_info.types:
+ assert ecc_type == protobuf_ecc_data_pb2.EccInfo.POLICE or \
+ ecc_type == protobuf_ecc_data_pb2.EccInfo.AMBULANCE or \
+ ecc_type == protobuf_ecc_data_pb2.EccInfo.FIRE
+ assert ecc_type not in loaded_types
+ loaded_types.append(ecc_type)
+ else:
+ # For forward compatibility, ecc_info.types could be null if a phone
+ # number contains only new types which is not defined now. Just leave
+ # a warning message for this case.
+ if len(ecc_info.types) == 0:
+ print("WARNING: No recognizable type for " + \
+ country_info.iso_code + " - " + ecc_info.phone_number)
+ else:
+ loaded_types = []
+ for ecc_type in ecc_info.types:
+ assert ecc_type not in loaded_types
+ loaded_types.append(ecc_type)
+ elif (args.strict):
+ print("Warning: Empty ecc list for country " + country_info.iso_code)
diff --git a/ecc/gen_eccdata.sh b/ecc/gen_eccdata.sh
new file mode 100755
index 0000000..5cf52de
--- /dev/null
+++ b/ecc/gen_eccdata.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+set -o errexit
+
+# Copyright 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.
+
+if [ -z "${ANDROID_BUILD_TOP}" ] ; then
+ echo "You need to source and lunch before you can use this script" 1>&2
+ exit 1
+fi
+
+case $(uname -s) in
+ Darwin)
+ KERNEL=darwin
+ ;;
+ Linux)
+ KERNEL=linux
+ ;;
+ *)
+ echo "Unknown kernel \"`uname -s`\"" 1>&2
+ exit 1
+ ;;
+esac
+
+read -d "" PROTOC_COMMAND << END || :
+${ANDROID_BUILD_TOP}/prebuilts/tools/${KERNEL}-x86_64/protoc/bin/protoc
+END
+if ! [ -x "${PROTOC_COMMAND}" ] ; then
+ echo "Missing ${PROTOC_COMMAND}." 1>&2
+ exit 1
+fi
+
+ECC_ROOT=`realpath \`dirname $0\``
+TOOLSET_DIR="${ECC_ROOT}/conversion_toolset_v1"
+INPUT_DIR="${ECC_ROOT}/input"
+OUTPUT_DIR="${ECC_ROOT}/output"
+INTERMEDIATE_DIR="${ECC_ROOT}/.intermediate"
+
+rm -rf "${INTERMEDIATE_DIR}" "${OUTPUT_DIR}/*"
+mkdir -p "${INTERMEDIATE_DIR}"
+
+source "${TOOLSET_DIR}/gen_eccdata.sh"
+echo
+
+# Check compatibility with every previous version
+rm -rf "${INTERMEDIATE_DIR}/*"
+source ${ECC_ROOT}/conversion_toolset_v1/verify_eccdata_compatibility.sh
+#rm -rf "${INTERMEDIATE_DIR}/*"
+#source ${ECC_ROOT}/conversion_toolset_v2/verify_eccdata_compatibility.sh
+#rm -rf "${INTERMEDIATE_DIR}/*"
+#source ${ECC_ROOT}/conversion_toolset_v3/verify_eccdata_compatibility.sh
+#...
+
+echo
+echo "Passed all compatibility verification!"
+
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
new file mode 100644
index 0000000..54be16b
--- /dev/null
+++ b/ecc/input/eccdata.txt
@@ -0,0 +1,2856 @@
+revision: 1
+countries {
+ iso_code: "AD"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "116"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AE"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "998"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "997"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AF"
+ eccs {
+ phone_number: "119"
+ types: POLICE
+ types: FIRE
+ }
+ eccs {
+ phone_number: "020112"
+ types: AMBULANCE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AG"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "AI"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "AL"
+ eccs {
+ phone_number: "129"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "127"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "128"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AM"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AO"
+ eccs {
+ phone_number: "113"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "112"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AR"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "AS"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "AT"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AU"
+ eccs {
+ phone_number: "000"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "AW"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "AZ"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BA"
+ eccs {
+ phone_number: "122"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "124"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "123"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BB"
+ eccs {
+ phone_number: "211"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "511"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "311"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "BD"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BE"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BF"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "18"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BG"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BH"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BI"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BJ"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BM"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "BN"
+ eccs {
+ phone_number: "993"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "991"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "995"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BO"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "119"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "BR"
+ eccs {
+ phone_number: "190"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "192"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "193"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "BS"
+ eccs {
+ phone_number: "919"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "BT"
+ eccs {
+ phone_number: "113"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "112"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "110"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BW"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "997"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "998"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BY"
+ eccs {
+ phone_number: "102"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "103"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "BZ"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "CA"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "CD"
+ eccs {
+ phone_number: "118"
+ types: POLICE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CF"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CG"
+ eccs {
+ phone_number: "118"
+ types: POLICE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CH"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "144"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CI"
+ eccs {
+ phone_number: "170"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "185"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "180"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CK"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CL"
+ eccs {
+ phone_number: "133"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "131"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "132"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CM"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "119"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CN"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "120"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "119"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CO"
+ eccs {
+ phone_number: "123"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CR"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "CU"
+ eccs {
+ phone_number: "106"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "104"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "105"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CV"
+ eccs {
+ phone_number: "132"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "130"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "131"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CY"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "CZ"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "DE"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "DJ"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "18"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "DK"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "DM"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "DO"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "DZ"
+ eccs {
+ phone_number: "1548"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "EC"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "EE"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "EG"
+ eccs {
+ phone_number: "122"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "123"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "180"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ER"
+ eccs {
+ phone_number: "127799"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "202914"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "202099"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ES"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ET"
+ eccs {
+ phone_number: "991"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "FI"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "FJ"
+ eccs {
+ phone_number: "917"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "911"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "FK"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "FM"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "FO"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "FR"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GA"
+ eccs {
+ phone_number: "177"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GB"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GD"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "GE"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GF"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GH"
+ eccs {
+ phone_number: "191"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "193"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "192"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GI"
+ eccs {
+ phone_number: "199"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "190"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GL"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GM"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "116"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GN"
+ eccs {
+ phone_number: "122"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "442020"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "1717"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GP"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GQ"
+ eccs {
+ phone_number: "113"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GR"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GT"
+ eccs {
+ phone_number: "120"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "123"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "GU"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "GW"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "113"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "GY"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "913"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "912"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "HK"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "HN"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "HR"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "HT"
+ eccs {
+ phone_number: "114"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "116"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "HU"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ID"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "113"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IE"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IL"
+ eccs {
+ phone_number: "100"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "101"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "102"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IN"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IO"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "IQ"
+ eccs {
+ phone_number: "130"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IR"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "115"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "125"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IS"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "IT"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "JM"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "JO"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "JP"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "119"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KE"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KG"
+ eccs {
+ phone_number: "102"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "103"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KH"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "119"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KI"
+ eccs {
+ phone_number: "192"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "194"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "193"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "KM"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KN"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "333"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "KP"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KR"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "119"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KW"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "KY"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "KZ"
+ eccs {
+ phone_number: "102"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "103"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LA"
+ eccs {
+ phone_number: "1191"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "1195"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "1190"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LB"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LC"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "911"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "LI"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LK"
+ eccs {
+ phone_number: "119"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "110"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LR"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "LS"
+ eccs {
+ phone_number: "123"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "121"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "122"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LT"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LU"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LV"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "LY"
+ eccs {
+ phone_number: "1515"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MA"
+ eccs {
+ phone_number: "190"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "150"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MC"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MD"
+ eccs {
+ phone_number: "902"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "903"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "901"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ME"
+ eccs {
+ phone_number: "122"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "124"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "123"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MG"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MH"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "MK"
+ eccs {
+ phone_number: "192"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "194"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "193"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ML"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MM"
+ eccs {
+ phone_number: "199"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "192"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "191"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MN"
+ eccs {
+ phone_number: "102"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "103"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MO"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MP"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "MR"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MS"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "6644912802"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "911"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "MT"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MU"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "114"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MV"
+ eccs {
+ phone_number: "119"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "102"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MW"
+ eccs {
+ phone_number: "997"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "998"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "999"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MX"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "MY"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "MZ"
+ eccs {
+ phone_number: "119"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "117"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "198"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NA"
+ eccs {
+ phone_number: "10111"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "211111"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NC"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NE"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NG"
+ eccs {
+ phone_number: "199"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NI"
+ eccs {
+ phone_number: "118"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "128"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NL"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NO"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NP"
+ eccs {
+ phone_number: "100"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "102"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NR"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "111"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "112"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NU"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "NZ"
+ eccs {
+ phone_number: "111"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "OM"
+ eccs {
+ phone_number: "9999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PA"
+ eccs {
+ phone_number: "104"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "911"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "PE"
+ eccs {
+ phone_number: "105"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "110"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "116"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "PF"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PG"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "111"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "110"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PH"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "PK"
+ eccs {
+ phone_number: "15"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "115"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "16"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PL"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PM"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PR"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "PS"
+ eccs {
+ phone_number: "100"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "101"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "102"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PT"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "PW"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "PY"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "QA"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "RE"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "RO"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "RS"
+ eccs {
+ phone_number: "192"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "194"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "193"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "RU"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "RW"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "111"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SA"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "997"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "998"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "SB"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "911"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "988"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "SC"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SD"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: FIRE
+ }
+ eccs {
+ phone_number: "333"
+ types: AMBULANCE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SE"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SG"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "995"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SH"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: FIRE
+ }
+ eccs {
+ phone_number: "911"
+ types: AMBULANCE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "SI"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SK"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SL"
+ eccs {
+ phone_number: "019"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "999"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SM"
+ eccs {
+ phone_number: "113"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SN"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SO"
+ eccs {
+ phone_number: "888"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SR"
+ eccs {
+ phone_number: "115"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SS"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ST"
+ eccs {
+ phone_number: "222222"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "221222"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "112"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SV"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "913"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "SY"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "110"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "113"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "SZ"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "911"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "933"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TC"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "TD"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TG"
+ eccs {
+ phone_number: "117"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TH"
+ eccs {
+ phone_number: "191"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "1669"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "199"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "TJ"
+ eccs {
+ phone_number: "102"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "103"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TK"
+ eccs {
+ phone_number: "111"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TL"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "110"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "3312210"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TM"
+ eccs {
+ phone_number: "002"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "003"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "001"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TN"
+ eccs {
+ phone_number: "197"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "190"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "198"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TO"
+ eccs {
+ phone_number: "922"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "933"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "999"
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "TR"
+ eccs {
+ phone_number: "155"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "112"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "110"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TT"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "990"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TV"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "TW"
+ eccs {
+ phone_number: "110"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "119"
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "TZ"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "UA"
+ eccs {
+ phone_number: "02"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "03"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "01"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "UG"
+ eccs {
+ phone_number: "999"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "US"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "UY"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "UZ"
+ eccs {
+ phone_number: "102"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "103"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "101"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "VA"
+ eccs {
+ phone_number: "113"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "118"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "115"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "VC"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "VE"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "VG"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "VI"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "VN"
+ eccs {
+ phone_number: "113"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "115"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "114"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "VU"
+ eccs {
+ phone_number: "111"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "112"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "113"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "WF"
+ eccs {
+ phone_number: "17"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "15"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "18"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "WS"
+ eccs {
+ phone_number: "911"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "911"
+}
+countries {
+ iso_code: "XK"
+ eccs {
+ phone_number: "192"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "194"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "193"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "YE"
+ eccs {
+ phone_number: "199"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ZA"
+ eccs {
+ phone_number: "112"
+ types: POLICE
+ types: AMBULANCE
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ZM"
+ eccs {
+ phone_number: "991"
+ types: POLICE
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "993"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
+countries {
+ iso_code: "ZW"
+ eccs {
+ phone_number: "995"
+ types: POLICE
+ }
+ eccs {
+ phone_number: "999"
+ types: AMBULANCE
+ }
+ eccs {
+ phone_number: "993"
+ types: FIRE
+ }
+ ecc_fallback: "112"
+}
diff --git a/ecc/output/eccdata b/ecc/output/eccdata
new file mode 100644
index 0000000..2d0165a
--- /dev/null
+++ b/ecc/output/eccdata
Binary files differ
diff --git a/ecc/proto b/ecc/proto
new file mode 120000
index 0000000..1faef70
--- /dev/null
+++ b/ecc/proto
@@ -0,0 +1 @@
+conversion_toolset_v1/proto/
\ No newline at end of file
diff --git a/res/drawable-hdpi/fab_red.png b/res/drawable-hdpi/fab_red.png
new file mode 100644
index 0000000..ce672f2
--- /dev/null
+++ b/res/drawable-hdpi/fab_red.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_arrow_go_next_18.png b/res/drawable-hdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..37cd6df
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_dialpad_white_24.png b/res/drawable-hdpi/ic_dialpad_white_24.png
new file mode 100644
index 0000000..9037f94
--- /dev/null
+++ b/res/drawable-hdpi/ic_dialpad_white_24.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_emergency_number_24.png b/res/drawable-hdpi/ic_emergency_number_24.png
new file mode 100644
index 0000000..d5c0b28
--- /dev/null
+++ b/res/drawable-hdpi/ic_emergency_number_24.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_location_on_white_18.png b/res/drawable-hdpi/ic_location_on_white_18.png
new file mode 100644
index 0000000..8f93ec9
--- /dev/null
+++ b/res/drawable-hdpi/ic_location_on_white_18.png
Binary files differ
diff --git a/res/drawable-hdpi/logo_avatar_anonymous_120.png b/res/drawable-hdpi/logo_avatar_anonymous_120.png
new file mode 100644
index 0000000..70d3011
--- /dev/null
+++ b/res/drawable-hdpi/logo_avatar_anonymous_120.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/ic_arrow_go_next_18.png b/res/drawable-ldrtl-hdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..b8cef90
--- /dev/null
+++ b/res/drawable-ldrtl-hdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/ic_arrow_go_next_18.png b/res/drawable-ldrtl-mdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..fc0a292
--- /dev/null
+++ b/res/drawable-ldrtl-mdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/ic_arrow_go_next_18.png b/res/drawable-ldrtl-xhdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..76c1e7f
--- /dev/null
+++ b/res/drawable-ldrtl-xhdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-ldrtl-xxhdpi/ic_arrow_go_next_18.png b/res/drawable-ldrtl-xxhdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..5914ace
--- /dev/null
+++ b/res/drawable-ldrtl-xxhdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-mdpi/fab_red.png b/res/drawable-mdpi/fab_red.png
new file mode 100644
index 0000000..094a606
--- /dev/null
+++ b/res/drawable-mdpi/fab_red.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_go_next_18.png b/res/drawable-mdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..d487ae0
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_dialpad_white_24.png b/res/drawable-mdpi/ic_dialpad_white_24.png
new file mode 100644
index 0000000..6c405f9
--- /dev/null
+++ b/res/drawable-mdpi/ic_dialpad_white_24.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_emergency_number_24.png b/res/drawable-mdpi/ic_emergency_number_24.png
new file mode 100644
index 0000000..3db2d19
--- /dev/null
+++ b/res/drawable-mdpi/ic_emergency_number_24.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_location_on_white_18.png b/res/drawable-mdpi/ic_location_on_white_18.png
new file mode 100644
index 0000000..5c5b0fb
--- /dev/null
+++ b/res/drawable-mdpi/ic_location_on_white_18.png
Binary files differ
diff --git a/res/drawable-mdpi/logo_avatar_anonymous_120.png b/res/drawable-mdpi/logo_avatar_anonymous_120.png
new file mode 100644
index 0000000..60d3c3a
--- /dev/null
+++ b/res/drawable-mdpi/logo_avatar_anonymous_120.png
Binary files differ
diff --git a/res/drawable-xhdpi/fab_red.png b/res/drawable-xhdpi/fab_red.png
new file mode 100644
index 0000000..ab1425e
--- /dev/null
+++ b/res/drawable-xhdpi/fab_red.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow_go_next_18.png b/res/drawable-xhdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..766a889
--- /dev/null
+++ b/res/drawable-xhdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dialpad_white_24.png b/res/drawable-xhdpi/ic_dialpad_white_24.png
new file mode 100644
index 0000000..0e89f6c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dialpad_white_24.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_emergency_number_24.png b/res/drawable-xhdpi/ic_emergency_number_24.png
new file mode 100644
index 0000000..b538c02
--- /dev/null
+++ b/res/drawable-xhdpi/ic_emergency_number_24.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_location_on_white_18.png b/res/drawable-xhdpi/ic_location_on_white_18.png
new file mode 100644
index 0000000..7c281c3
--- /dev/null
+++ b/res/drawable-xhdpi/ic_location_on_white_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/logo_avatar_anonymous_120.png b/res/drawable-xhdpi/logo_avatar_anonymous_120.png
new file mode 100644
index 0000000..ec99ca6
--- /dev/null
+++ b/res/drawable-xhdpi/logo_avatar_anonymous_120.png
Binary files differ
diff --git a/res/drawable-xxhdpi/fab_red.png b/res/drawable-xxhdpi/fab_red.png
new file mode 100644
index 0000000..899a578
--- /dev/null
+++ b/res/drawable-xxhdpi/fab_red.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_go_next_18.png b/res/drawable-xxhdpi/ic_arrow_go_next_18.png
new file mode 100644
index 0000000..bb4d45e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_arrow_go_next_18.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_dialpad_white_24.png b/res/drawable-xxhdpi/ic_dialpad_white_24.png
new file mode 100644
index 0000000..1750005
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_dialpad_white_24.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_emergency_number_24.png b/res/drawable-xxhdpi/ic_emergency_number_24.png
new file mode 100644
index 0000000..13f253b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_emergency_number_24.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_location_on_white_18.png b/res/drawable-xxhdpi/ic_location_on_white_18.png
new file mode 100644
index 0000000..b345cff
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_location_on_white_18.png
Binary files differ
diff --git a/res/drawable-xxhdpi/logo_avatar_anonymous_120.png b/res/drawable-xxhdpi/logo_avatar_anonymous_120.png
new file mode 100644
index 0000000..2b009a3
--- /dev/null
+++ b/res/drawable-xxhdpi/logo_avatar_anonymous_120.png
Binary files differ
diff --git a/res/drawable/btn_emergency_shortcuts.xml b/res/drawable/btn_emergency_shortcuts.xml
new file mode 100644
index 0000000..063a824
--- /dev/null
+++ b/res/drawable/btn_emergency_shortcuts.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="8dp"/>
+</shape>
\ No newline at end of file
diff --git a/res/drawable/emergency_shortcuts_divider.xml b/res/drawable/emergency_shortcuts_divider.xml
new file mode 100644
index 0000000..988ffc5
--- /dev/null
+++ b/res/drawable/emergency_shortcuts_divider.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <size android:height="1px"/>
+ <solid android:color="#33FFFFFF"/>
+</shape>
diff --git a/res/drawable/floating_action_button_red.xml b/res/drawable/floating_action_button_red.xml
new file mode 100644
index 0000000..5fe74a3
--- /dev/null
+++ b/res/drawable/floating_action_button_red.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/floating_action_button_touch_tint">
+ <item android:drawable="@drawable/fab_red" />
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/phone_type_icon_background.xml b/res/drawable/phone_type_icon_background.xml
new file mode 100644
index 0000000..b51c3b2
--- /dev/null
+++ b/res/drawable/phone_type_icon_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="@color/emergency_shortcut_confirm_button_background_color"/>
+</shape>
\ No newline at end of file
diff --git a/res/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index 2a45433..cdb9530 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -16,51 +16,105 @@
<!-- Layout for the emergency dialer; see EmergencyDialer.java. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/top"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- Emergency dialer shortcuts layout-->
+ <FrameLayout
+ android:id="@+id/emergency_dialer_shortcuts"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <include layout="@layout/emergency_information"/>
+ <include layout="@layout/emergency_shortcut_buttons_group"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/dialpad_button_container"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_margin="@dimen/emergency_dialer_dialpad_button_margin">
+ <ImageButton
+ android:id="@+id/floating_action_button_dialpad"
+ android:layout_width="@dimen/dialpad_button_width"
+ android:layout_height="@dimen/dialpad_button_height"
+ android:background="@drawable/floating_action_button_red"
+ android:contentDescription="@string/description_dialpad_button"
+ android:src="@drawable/ic_dialpad_white_24"/>
+ </FrameLayout>
+ </FrameLayout>
+
+ <!--Emergency Dialer Layout-->
+ <FrameLayout
+ android:id="@+id/emergency_dialer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="36dp"
android:paddingRight="36dp"
- android:paddingBottom="@dimen/dialpad_bottom_padding">
-
- <LinearLayout
+ android:paddingBottom="@dimen/dialpad_bottom_padding"
+ android:visibility="visible">
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:orientation="vertical">
- <!-- FrameLayout -->
- <com.android.phone.EmergencyActionGroup
+ <!--Emergency dialer shortcuts implement EmergencyInfoGroup to replace
+ EmergencyActionGroup. Using a title to indicate the dialpad is emergency calls only.-->
+ <FrameLayout
+ android:id="@+id/emergency_dialpad_title_container"
+ android:layout_height="64dp"
+ android:layout_width="match_parent"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="24dp"
+ android:visibility="gone">
+ <TextView
+ android:id="@+id/emergency_dialpad_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:textStyle="bold"
+ android:maxLines="1"
+ android:text="@string/emergency_dialpad_title"/>
+ </FrameLayout>
+
+ <!-- FrameLayout -->
+ <com.android.phone.EmergencyActionGroup
android:id="@+id/emergency_action_group"
android:layout_height="64dp"
android:layout_width="match_parent"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp">
- <!-- Button that says: Emergency Information -->
- <LinearLayout
+ <!-- Button that says: Emergency Information -->
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
- <Button android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="@drawable/btn_emergency"
- android:id="@+id/action1" />
- <Button android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="@drawable/btn_emergency"
- android:id="@+id/action2" />
- <Button android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="@drawable/btn_emergency"
- android:id="@+id/action3" />
- </LinearLayout>
+ <Button android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/btn_emergency"
+ android:id="@+id/action1" />
+ <Button android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/btn_emergency"
+ android:id="@+id/action2" />
+ <Button android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/btn_emergency"
+ android:id="@+id/action3" />
+ </LinearLayout>
- <!-- View that shows up on top of "emergency information" button
- and asks you to tap again to confirm the action -->
- <FrameLayout
+ <!-- View that shows up on top of "emergency information" button
+ and asks you to tap again to confirm the action -->
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/selected_container"
@@ -68,7 +122,7 @@
android:focusable="true"
android:clickable="true">
- <View
+ <View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="#ffe53935"
@@ -76,7 +130,7 @@
android:clickable="false"
style="?android:attr/buttonStyle"/>
- <View
+ <View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ripple_view"
@@ -86,7 +140,7 @@
android:clickable="false"
style="?android:attr/buttonStyle"/>
- <LinearLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@@ -94,7 +148,7 @@
android:clickable="false"
android:backgroundTint="#00000000"
style="?android:attr/buttonStyle">
- <TextView
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
@@ -102,7 +156,7 @@
android:id="@+id/selected_label"
android:textColor="@android:color/white"
android:textAppearance="?android:attr/textAppearanceButton" />
- <TextView
+ <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/launch_hint"
@@ -111,37 +165,39 @@
android:text="@string/emergency_action_launch_hint"
android:textColor="@android:color/white"
android:textStyle="italic" />
- </LinearLayout>
+ </LinearLayout>
- </FrameLayout>
+ </FrameLayout>
- </com.android.phone.EmergencyActionGroup>
+ </com.android.phone.EmergencyActionGroup>
- <include layout="@layout/dialpad_view_unthemed"
- android:theme="?attr/dialpadTheme" />
+ <include layout="@layout/dialpad_view_unthemed"
+ android:theme="?attr/dialpadTheme" />
- </LinearLayout>
+ </LinearLayout>
- <Space
- android:id="@+id/floating_action_button_margin_bottom"
- android:layout_width="match_parent"
- android:layout_height="@dimen/floating_action_button_margin_bottom"
- android:layout_alignParentBottom="true"/>
+ <Space
+ android:id="@+id/floating_action_button_margin_bottom"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/floating_action_button_margin_bottom"
+ android:layout_alignParentBottom="true"/>
- <FrameLayout
- android:id="@+id/floating_action_button_container"
- android:layout_width="@dimen/floating_action_button_width"
- android:layout_height="@dimen/floating_action_button_height"
- android:layout_gravity="center_horizontal|bottom" >
+ <FrameLayout
+ android:id="@+id/floating_action_button_container"
+ android:layout_width="@dimen/floating_action_button_width"
+ android:layout_height="@dimen/floating_action_button_height"
+ android:layout_gravity="center_horizontal|bottom" >
- <ImageButton
- android:id="@+id/floating_action_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@drawable/floating_action_button"
- android:contentDescription="@string/description_dial_button"
- android:src="@drawable/fab_ic_call"/>
+ <ImageButton
+ android:id="@+id/floating_action_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@drawable/floating_action_button"
+ android:contentDescription="@string/description_dial_button"
+ android:src="@drawable/fab_ic_call"/>
+ </FrameLayout>
+
</FrameLayout>
</FrameLayout>
diff --git a/res/layout/emergency_information.xml b/res/layout/emergency_information.xml
new file mode 100644
index 0000000..c4ab74b
--- /dev/null
+++ b/res/layout/emergency_information.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.phone.EmergencyInfoGroup
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/emergency_info_button"
+ android:layout_height="@dimen/emergency_info_button_singleline_height"
+ android:layout_width="match_parent"
+ android:layout_marginTop="@dimen/emergency_info_button_margin_top">
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:layout_marginEnd="56dp"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:id="@+id/emergency_info_image_container"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginHorizontal="@dimen/emergency_dialer_image_margin_horizontal">
+ <ImageView
+ android:id="@+id/emergency_info_image"
+ android:layout_height="@dimen/emergency_info_image_height"
+ android:layout_width="@dimen/emergency_info_image_width"
+ android:scaleType="centerCrop"/>
+ </FrameLayout>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_gravity="center_vertical">
+ <TextView
+ android:id="@+id/emergency_info_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:includeFontPadding="false"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@style/HeadlineTextAppearance"/>
+ <TextView
+ android:id="@+id/emergency_info_hint"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:lineHeight="@dimen/emergency_info_hint_line_height"
+ android:alpha="0.7"
+ android:textAppearance="@style/SubtitleTextAppearance"
+ android:text="@string/emergency_information_hint"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/arrow_go_next_container"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginHorizontal="@dimen/emergency_dialer_image_margin_horizontal">
+ <ImageView
+ android:id="@+id/arrow_go_next"
+ android:layout_height="@dimen/emergency_shortcuts_function_icon_height"
+ android:layout_width="@dimen/emergency_shortcuts_function_icon_width"
+ android:src="@drawable/ic_arrow_go_next_18"/>
+ </FrameLayout>
+</com.android.phone.EmergencyInfoGroup>
diff --git a/res/layout/emergency_shortcut_button.xml b/res/layout/emergency_shortcut_button.xml
new file mode 100644
index 0000000..6087dba
--- /dev/null
+++ b/res/layout/emergency_shortcut_button.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.phone.EmergencyShortcutButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="@dimen/emergency_shortcut_button_height"
+ android:layout_width="match_parent">
+ <!-- Normal emergency call button view -->
+ <FrameLayout
+ android:id="@+id/emergency_call_number_info_view"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="@color/emergency_shortcut_button_background_color"
+ android:focusable="true"
+ android:clickable="true">
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_marginEnd="@dimen/emergency_info_image_width"
+ android:layout_gravity="center_vertical|start"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:layout_height="@dimen/phone_number_type_circle_image_height"
+ android:layout_width="@dimen/phone_number_type_circle_image_width"
+ android:layout_gravity="center_vertical"
+ android:layout_marginHorizontal="@dimen/emergency_dialer_image_margin_horizontal"
+ android:background="@drawable/phone_type_icon_background">
+ <ImageView
+ android:id="@+id/phone_type_icon"
+ android:layout_width="@dimen/phone_number_type_image_height"
+ android:layout_height="@dimen/phone_number_type_image_width"
+ android:layout_gravity="center"/>
+ </FrameLayout>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/phone_number"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:includeFontPadding="false"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@style/HeadlineTextAppearance"/>
+ <TextView
+ android:id="@+id/phone_number_description"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:alpha="0.8"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@style/SubtitleTextAppearance"/>
+ </LinearLayout>
+ </LinearLayout>
+ <FrameLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginHorizontal="@dimen/emergency_dialer_image_margin_horizontal"
+ android:layout_gravity="center_vertical|end">
+ <ImageView
+ android:id="@+id/microphone_icon"
+ android:layout_height="@dimen/phone_icon_height"
+ android:layout_width="@dimen/phone_icon_width"
+ android:src="@drawable/ic_emergency_callback_mode"/>
+ </FrameLayout>
+ </FrameLayout>
+
+ <!-- "Tap again to call" view -->
+ <FrameLayout
+ android:id="@+id/emergency_call_confirm_view"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="@color/emergency_shortcut_confirm_button_background_color"
+ android:focusable="true"
+ android:clickable="true"
+ android:visibility="invisible">
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_marginEnd="@dimen/emergency_info_image_width"
+ android:layout_gravity="center_vertical|start"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:layout_height="@dimen/phone_number_type_circle_image_height"
+ android:layout_width="@dimen/phone_number_type_circle_image_width"
+ android:layout_marginHorizontal="@dimen/emergency_dialer_image_margin_horizontal"
+ android:background="@drawable/phone_type_icon_background"
+ android:backgroundTint="@android:color/white">
+ <ImageView
+ android:id="@+id/confirmed_phone_type_icon"
+ android:layout_width="@dimen/phone_number_type_image_height"
+ android:layout_height="@dimen/phone_number_type_image_width"
+ android:layout_gravity="center"
+ android:tint="@color/emergency_shortcut_confirm_button_background_color"/>
+ </FrameLayout>
+ <FrameLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:gravity="center_vertical">
+ <TextView
+ android:id="@+id/phone_call_hint"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:lineHeight="@dimen/phone_call_hint_line_height"
+ android:textAppearance="@style/ShortcutsHintTextAppearance"/>
+ </FrameLayout>
+ </LinearLayout>
+ <FrameLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginHorizontal="@dimen/emergency_dialer_image_margin_horizontal"
+ android:layout_gravity="center_vertical|end">
+ <ImageView
+ android:layout_height="@dimen/phone_icon_height"
+ android:layout_width="@dimen/phone_icon_width"
+ android:src="@drawable/ic_emergency_callback_mode"/>
+ </FrameLayout>
+ </FrameLayout>
+</com.android.phone.EmergencyShortcutButton>
\ No newline at end of file
diff --git a/res/layout/emergency_shortcut_buttons_group.xml b/res/layout/emergency_shortcut_buttons_group.xml
new file mode 100644
index 0000000..619eac6
--- /dev/null
+++ b/res/layout/emergency_shortcut_buttons_group.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/emergency_shortcut_buttons_group"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="@dimen/emergency_shortcuts_group_margin_top"
+ android:orientation="vertical">
+ <FrameLayout
+ android:id="@+id/emergency_number_title_group"
+ android:layout_height="@dimen/emergency_number_title_height"
+ android:layout_width="match_parent"
+ android:paddingHorizontal="@dimen/emergency_number_title_group_padding_horizontal">
+ <FrameLayout
+ android:id="@+id/emergency_number_title_container"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/emergency_number_title_container_width"
+ android:layout_gravity="center_vertical|start">
+ <TextView
+ android:id="@+id/emergency_number_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@style/SubtitleTextAppearance"
+ android:text="@string/single_emergency_number_title"/>
+ </FrameLayout>
+ <LinearLayout
+ android:id="@+id/location_info"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginStart="@dimen/emergency_number_title_container_width"
+ android:layout_gravity="center_vertical|end"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:alpha="0.7">
+ <ImageView
+ android:id="@+id/location_icon"
+ android:layout_width="@dimen/location_image_width"
+ android:layout_height="@dimen/location_image_height"
+ android:src="@drawable/ic_location_on_white_18"/>
+ <TextView
+ android:id="@+id/location_text"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingStart="4dp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:textAppearance="@style/SubtitleTextAppearance"/>
+ </LinearLayout>
+ </FrameLayout>
+ <LinearLayout
+ android:id="@+id/emergency_shortcut_buttons_container"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginHorizontal="@dimen/emergency_shortcut_buttons_margin_horizontal"
+ android:orientation="vertical"
+ android:divider="@drawable/emergency_shortcuts_divider"
+ android:showDividers="middle"
+ android:background="@drawable/btn_emergency_shortcuts">
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 870d692..7136819 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -54,4 +54,6 @@
<color name="dialer_dialpad_touch_tint">#330288d1</color>
<color name="floating_action_button_touch_tint">#80ffffff</color>
+ <color name="emergency_shortcut_button_background_color">#1FFFFFFF</color>
+ <color name="emergency_shortcut_confirm_button_background_color">#E25142</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 42f9563..97417bd 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -113,4 +113,66 @@
<!-- The size of the "emergency calling unavailable" message shown in the emergency dialer -->
<dimen name="emergency_call_warning_size">16sp</dimen>
+
+ <!-- Horizontal margin for the image on emergency dialer.-->
+ <dimen name="emergency_dialer_image_margin_horizontal">16dp</dimen>
+
+ <!-- Margin of dialpad button -->
+ <dimen name="emergency_dialer_dialpad_button_margin">16dp</dimen>
+
+ <!-- Horizontal margin for button of emergency shortcut. -->
+ <dimen name="emergency_shortcut_buttons_margin_horizontal">16dp</dimen>
+
+ <!-- Margin top of emergency shortcuts group -->
+ <dimen name="emergency_shortcuts_group_margin_top">48dp</dimen>
+
+ <!-- Horizontal padding for group of emergency number title-->
+ <dimen name="emergency_number_title_group_padding_horizontal">16dp</dimen>
+
+ <!-- Height and top margin for the emergency information button. -->
+ <dimen name="emergency_info_button_singleline_height">72dp</dimen>
+ <dimen name="emergency_info_button_margin_top">56dp</dimen>
+ <dimen name="emergency_info_button_multiline_height">90dp</dimen>
+
+ <!-- The height and width for the image of emergency information. -->
+ <dimen name="emergency_info_image_height">56dp</dimen>
+ <dimen name="emergency_info_image_width">56dp</dimen>
+
+ <!-- The height and width for the function icon of emergency shortcuts. -->
+ <dimen name="emergency_shortcuts_function_icon_height">24dp</dimen>
+ <dimen name="emergency_shortcuts_function_icon_width">24dp</dimen>
+
+ <!-- The height and width for the dialpad button -->
+ <dimen name="dialpad_button_height">56dp</dimen>
+ <dimen name="dialpad_button_width">56dp</dimen>
+
+ <!-- The height for title of emergency number and location info. -->
+ <dimen name="emergency_number_title_height">48dp</dimen>
+
+ <!-- The height and width for the image of location info.-->
+ <dimen name="location_image_height">15dp</dimen>
+ <dimen name="location_image_width">15dp</dimen>
+
+ <!-- The height for button of emergency shortcut. -->
+ <dimen name="emergency_shortcut_button_height">80dp</dimen>
+
+ <!-- The height and width for the circle image of phone number type.-->
+ <dimen name="phone_number_type_circle_image_height">40dp</dimen>
+ <dimen name="phone_number_type_circle_image_width">40dp</dimen>
+
+ <!-- The height and width for the image of phone number type.-->
+ <dimen name="phone_number_type_image_height">24dp</dimen>
+ <dimen name="phone_number_type_image_width">24dp</dimen>
+
+ <!-- The height and width of phone icon.-->
+ <dimen name="phone_icon_height">24dp</dimen>
+ <dimen name="phone_icon_width">24dp</dimen>
+
+ <!-- The line height for emergency info hint and phone call hint.-->
+ <dimen name="emergency_info_hint_line_height">17dp</dimen>
+ <dimen name="phone_call_hint_line_height">20dp</dimen>
+
+ <!-- The width for emergency number title container.-->
+ <dimen name="emergency_number_title_container_width">210dp</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f192ae..b60d85f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1122,8 +1122,20 @@
<!-- In-call screen: call failure message displayed in an error dialog when the user is connected to a wireless network, but wifi calling is turned off. [CHAR_LIMIT=NONE] -->
<string name="incall_error_promote_wfc">Enable Wi-Fi calling to make a call.</string>
+ <!-- Hint for the button of emergency information -->
+ <string name="emergency_information_hint">Emergency information</string>
+ <!-- Hint for the owner of emergency information -->
+ <string name="emergency_information_owner_hint">Owner</string>
<!-- Dialog title for the "radio enable" UI for emergency calls -->
<string name="emergency_enable_radio_dialog_title">Emergency call</string>
+ <!-- Title for the emergency dialpad UI -->
+ <string name="emergency_dialpad_title">Emergency calls only</string>
+ <!-- Emergency dialer: Title of single emergency shortcut button -->
+ <string name="single_emergency_number_title">Emergency number</string>
+ <!-- Emergency dialer: Title of numerous emergency shortcut buttons -->
+ <string name="numerous_emergency_numbers_title">Emergency numbers</string>
+ <!-- Emergency dialer: Hint of selected emergency shortcut button -->
+ <string name="emergency_call_shortcut_hint">Tap again to call <xliff:g id="emergency_number">%s</xliff:g></string>
<!-- Status message for the "radio enable" UI for emergency calls -->
<string name="emergency_enable_radio_dialog_message">Turning on radio\u2026</string>
<!-- Status message for the "radio enable" UI for emergency calls -->
@@ -1367,6 +1379,13 @@
-->
<string name="description_dial_button">dial</string>
+ <!-- String describing the Dialpad ImageButton
+
+ Used by AccessibilityService to announce the purpose of the button.
+ [CHAR LIMIT=NONE]
+ -->
+ <string name="description_dialpad_button">show dialpad</string>
+
<!-- Visual voicemail on/off title [CHAR LIMIT=40] -->
<string name="voicemail_visual_voicemail_switch_title">Visual Voicemail</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d003aec..73b5c40 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -313,4 +313,17 @@
<style name="CallSettingsWithoutDividerTheme" parent="SettingsLight">
<item name="android:listDivider">@null</item>
</style>
+
+ <style name="HeadlineTextAppearance">
+ <item name="android:textColor">@android:color/white</item>
+ <item name="android:textSize">24sp</item>
+ </style>
+
+ <style name="SubtitleTextAppearance" parent="@style/HeadlineTextAppearance">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="ShortcutsHintTextAppearance" parent="@style/HeadlineTextAppearance">
+ <item name="android:textSize">16sp</item>
+ </style>
</resources>
diff --git a/src/com/android/phone/EmergencyActionGroup.java b/src/com/android/phone/EmergencyActionGroup.java
index b647623..d72c265 100644
--- a/src/com/android/phone/EmergencyActionGroup.java
+++ b/src/com/android/phone/EmergencyActionGroup.java
@@ -22,11 +22,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.Layout;
import android.text.TextUtils;
@@ -125,15 +121,13 @@
mPendingTouchEvent = null;
}
-
-
private void setupAssistActions() {
int[] buttonIds = new int[] {R.id.action1, R.id.action2, R.id.action3};
List<ResolveInfo> infos;
if (TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED) {
- infos = resolveAssistPackageAndQueryActivites();
+ infos = EmergencyAssistanceHelper.resolveAssistPackageAndQueryActivities(getContext());
} else {
infos = null;
}
@@ -146,7 +140,7 @@
if (infos != null && infos.size() > i && infos.get(i) != null) {
ResolveInfo info = infos.get(i);
- ComponentName name = getComponentName(info);
+ ComponentName name = EmergencyAssistanceHelper.getComponentName(info);
button.setTag(R.id.tag_intent,
new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
@@ -159,69 +153,6 @@
}
}
- private List<ResolveInfo> resolveAssistPackageAndQueryActivites() {
- List<ResolveInfo> infos = queryAssistActivities();
-
- if (infos == null || infos.isEmpty()) {
- PackageManager packageManager = getContext().getPackageManager();
- Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
- infos = packageManager.queryIntentActivities(queryIntent, 0);
-
- PackageInfo bestMatch = null;
- for (int i = 0; i < infos.size(); i++) {
- if (infos.get(i).activityInfo == null) continue;
- String packageName = infos.get(i).activityInfo.packageName;
- PackageInfo packageInfo;
- try {
- packageInfo = packageManager.getPackageInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- continue;
- }
- // Get earliest installed system app.
- if (isSystemApp(packageInfo) && (bestMatch == null ||
- bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
- bestMatch = packageInfo;
- }
- }
-
- if (bestMatch != null) {
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
- bestMatch.packageName);
- return queryAssistActivities();
- } else {
- return null;
- }
- } else {
- return infos;
- }
- }
-
- private List<ResolveInfo> queryAssistActivities() {
- String assistPackage = Settings.Secure.getString(
- getContext().getContentResolver(),
- Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
- List<ResolveInfo> infos = null;
-
- if (!TextUtils.isEmpty(assistPackage)) {
- Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
- .setPackage(assistPackage);
- infos = getContext().getPackageManager().queryIntentActivities(queryIntent, 0);
- }
- return infos;
- }
-
- private boolean isSystemApp(PackageInfo info) {
- return info.applicationInfo != null
- && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- }
-
- private ComponentName getComponentName(ResolveInfo resolveInfo) {
- if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
- return new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name);
- }
-
@Override
public void onClick(View v) {
Intent intent = (Intent) v.getTag(R.id.tag_intent);
@@ -405,6 +336,4 @@
startRipple();
}
};
-
-
}
diff --git a/src/com/android/phone/EmergencyAssistanceHelper.java b/src/com/android/phone/EmergencyAssistanceHelper.java
new file mode 100644
index 0000000..3053125
--- /dev/null
+++ b/src/com/android/phone/EmergencyAssistanceHelper.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import java.util.List;
+
+/**
+ * A helper to query activities of emergency assistance.
+ */
+public class EmergencyAssistanceHelper {
+
+ /**
+ * Query activities of emergency assistance.
+ *
+ * @param context The context of the application.
+ * @return A list of {@link ResolveInfo} which is queried from default assistance package,
+ * or null if there is no installed system application of emergency assistance.
+ */
+ public static List<ResolveInfo> resolveAssistPackageAndQueryActivities(Context context) {
+ List<ResolveInfo> infos = queryAssistActivities(context);
+
+ if (infos == null || infos.isEmpty()) {
+ PackageManager packageManager = context.getPackageManager();
+ Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
+ infos = packageManager.queryIntentActivities(queryIntent, 0);
+
+ PackageInfo bestMatch = null;
+ for (int i = 0; i < infos.size(); i++) {
+ if (infos.get(i).activityInfo == null) continue;
+ String packageName = infos.get(i).activityInfo.packageName;
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ continue;
+ }
+ // Get earliest installed system app.
+ if (isSystemApp(packageInfo) && (bestMatch == null
+ || bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
+ bestMatch = packageInfo;
+ }
+ }
+
+ if (bestMatch != null) {
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, bestMatch.packageName);
+ return queryAssistActivities(context);
+ } else {
+ return null;
+ }
+ } else {
+ return infos;
+ }
+ }
+
+ /**
+ * Compose {@link ComponentName} from {@link ResolveInfo}.
+ */
+ public static ComponentName getComponentName(ResolveInfo resolveInfo) {
+ if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ }
+
+ private static List<ResolveInfo> queryAssistActivities(Context context) {
+ final String assistPackage = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
+ List<ResolveInfo> infos = null;
+
+ if (!TextUtils.isEmpty(assistPackage)) {
+ Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
+ .setPackage(assistPackage);
+ infos = context.getPackageManager().queryIntentActivities(queryIntent, 0);
+ }
+ return infos;
+ }
+
+ private static boolean isSystemApp(PackageInfo info) {
+ return info.applicationInfo != null
+ && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+}
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 157cf1d..fc4ef6a 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -18,6 +18,8 @@
import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -26,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Color;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.ToneGenerator;
@@ -38,6 +41,7 @@
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -56,7 +60,9 @@
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
+import android.widget.TextView;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
@@ -65,6 +71,9 @@
import com.android.phone.common.util.ViewUtil;
import com.android.phone.common.widget.ResizingTextEditText;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* EmergencyDialer is a special dialer that is used ONLY for dialing emergency calls.
*
@@ -81,10 +90,17 @@
* moved into a shared base class that would live in the framework?
* Or could we figure out some way to move *this* class into apps/Contacts
* also?
+ *
+ * TODO: Implement emergency dialer shortcut.
+ * Emergency dialer shortcut offer a local emergency number list. Directly clicking a call button
+ * to place an emergency phone call without entering numbers from dialpad.
+ * TODO item:
+ * 1.integrate emergency phone number table.
*/
public class EmergencyDialer extends Activity implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener, TextWatcher,
- DialpadKeyButton.OnPressedListener, ColorExtractor.OnColorsChangedListener {
+ DialpadKeyButton.OnPressedListener, ColorExtractor.OnColorsChangedListener,
+ EmergencyShortcutButton.OnConfirmClickListener {
// Keys used with onSaveInstanceState().
private static final String LAST_NUMBER = "lastNumber";
@@ -116,9 +132,16 @@
/** 90% opacity, different from other gradients **/
private static final int BACKGROUND_GRADIENT_ALPHA = 230;
+ /** 85% opacity for black background **/
+ private static final int BLACK_BACKGROUND_GRADIENT_ALPHA = 217;
+
ResizingTextEditText mDigits;
private View mDialButton;
private View mDelete;
+ private View mEmergencyShortcutView;
+ private View mDialpadView;
+
+ private List<EmergencyShortcutButton> mEmergencyShortcutButtonList;
private ToneGenerator mToneGenerator;
private Object mToneGeneratorLock = new Object();
@@ -148,6 +171,8 @@
private boolean mIsWfcEmergencyCallingWarningEnabled;
private float mDefaultDigitsTextSize;
+ private boolean mAreEmergencyDialerShortcutsEnabled;
+
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing
@@ -187,10 +212,20 @@
// Allow turning screen on
setTurnScreenOn(true);
+ mAreEmergencyDialerShortcutsEnabled = Settings.Global.getInt(getContentResolver(),
+ Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0;
+
mColorExtractor = new ColorExtractor(this);
- GradientColors lockScreenColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_EXTRA_DARK);
- updateTheme(lockScreenColors.supportsDarkText());
+
+ // It does not support dark text theme, when emergency dialer shortcuts are enabled.
+ // And the background color is black with 85% opacity.
+ if (mAreEmergencyDialerShortcutsEnabled) {
+ updateTheme(false);
+ } else {
+ GradientColors lockScreenColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+ ColorExtractor.TYPE_EXTRA_DARK);
+ updateTheme(lockScreenColors.supportsDarkText());
+ }
setContentView(R.layout.emergency_dialer);
@@ -208,7 +243,8 @@
((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getSize(displaySize);
mBackgroundGradient.setScreenSize(displaySize.x, displaySize.y);
- mBackgroundGradient.setAlpha(BACKGROUND_GRADIENT_ALPHA);
+ mBackgroundGradient.setAlpha(mAreEmergencyDialerShortcutsEnabled
+ ? BLACK_BACKGROUND_GRADIENT_ALPHA : BACKGROUND_GRADIENT_ALPHA);
getWindow().setBackgroundDrawable(mBackgroundGradient);
// Check for the presence of the keypad
@@ -273,6 +309,10 @@
registerReceiver(mBroadcastReceiver, intentFilter);
mEmergencyActionGroup = (EmergencyActionGroup) findViewById(R.id.emergency_action_group);
+
+ if (mAreEmergencyDialerShortcutsEnabled) {
+ setupEmergencyShortcutsView();
+ }
}
@Override
@@ -328,6 +368,19 @@
view.setOnLongClickListener(this);
}
+ @Override
+ public void onBackPressed() {
+ // If emergency dialer shortcut is enabled and Dialpad view is visible, pressing the
+ // back key will back to display EmergencyShortcutView view.
+ // Otherwise, it would finish the activity.
+ if (mAreEmergencyDialerShortcutsEnabled && mDialpadView != null
+ && mDialpadView.getVisibility() == View.VISIBLE) {
+ switchView(mEmergencyShortcutView, mDialpadView, true);
+ return;
+ }
+ super.onBackPressed();
+ }
+
/**
* handle key events
*/
@@ -375,13 +428,28 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- mEmergencyActionGroup.onPreTouchEvent(ev);
+ onPreTouchEvent(ev);
boolean handled = super.dispatchTouchEvent(ev);
- mEmergencyActionGroup.onPostTouchEvent(ev);
+ onPostTouchEvent(ev);
return handled;
}
@Override
+ public void onConfirmClick(EmergencyShortcutButton button) {
+ if (button == null) return;
+
+ String phoneNumber = button.getPhoneNumber();
+
+ if (!TextUtils.isEmpty(phoneNumber)) {
+ if (DBG) Log.d(LOG_TAG, "dial emergency number: " + Rlog.pii(LOG_TAG, phoneNumber));
+ TelecomManager tm = (TelecomManager) getSystemService(TELECOM_SERVICE);
+ tm.placeCall(Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null), null);
+ } else {
+ Log.d(LOG_TAG, "emergency number is empty");
+ }
+ }
+
+ @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.deleteButton: {
@@ -399,6 +467,18 @@
}
return;
}
+ case R.id.floating_action_button_dialpad: {
+ mDigits.getText().clear();
+ switchView(mDialpadView, mEmergencyShortcutView, true);
+ return;
+ }
+ case R.id.emergency_info_button: {
+ Intent intent = (Intent) view.getTag(R.id.tag_intent);
+ if (intent != null) {
+ startActivity(intent);
+ }
+ return;
+ }
}
}
@@ -494,13 +574,19 @@
@Override
protected void onStart() {
super.onStart();
-
- mColorExtractor.addOnColorsChangedListener(this);
- GradientColors lockScreenColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_EXTRA_DARK);
- // Do not animate when view isn't visible yet, just set an initial state.
- mBackgroundGradient.setColors(lockScreenColors, false);
- updateTheme(lockScreenColors.supportsDarkText());
+ // It does not support dark text theme, when emergency dialer shortcuts are enabled.
+ // And set background color to black.
+ if (mAreEmergencyDialerShortcutsEnabled) {
+ mBackgroundGradient.setColors(Color.BLACK, Color.BLACK, false);
+ updateTheme(false);
+ } else {
+ mColorExtractor.addOnColorsChangedListener(this);
+ GradientColors lockScreenColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+ ColorExtractor.TYPE_EXTRA_DARK);
+ // Do not animate when view isn't visible yet, just set an initial state.
+ mBackgroundGradient.setColors(lockScreenColors, false);
+ updateTheme(lockScreenColors.supportsDarkText());
+ }
}
@Override
@@ -536,7 +622,6 @@
@Override
protected void onStop() {
super.onStop();
-
mColorExtractor.removeOnColorsChangedListener(this);
}
@@ -792,4 +877,150 @@
Log.i(LOG_TAG, "hint - setting to " + mDigits.getScaledTextSize());
}
}
+
+ private void setupEmergencyShortcutsView() {
+ mEmergencyShortcutView = findViewById(R.id.emergency_dialer_shortcuts);
+ mDialpadView = findViewById(R.id.emergency_dialer);
+
+ final View dialpadButton = findViewById(R.id.floating_action_button_dialpad);
+ dialpadButton.setOnClickListener(this);
+
+ final View emergencyInfoButton = findViewById(R.id.emergency_info_button);
+ emergencyInfoButton.setOnClickListener(this);
+
+ // EmergencyActionGroup is replaced by EmergencyInfoGroup.
+ mEmergencyActionGroup.setVisibility(View.GONE);
+
+ // Setup dialpad title.
+ final View emergencyDialpadTitle = findViewById(R.id.emergency_dialpad_title_container);
+ emergencyDialpadTitle.setVisibility(View.VISIBLE);
+
+ // TODO: Integrating emergency phone number table will get location information.
+ // Using null to present no location status.
+ setLocationInfo(null);
+
+ mEmergencyShortcutButtonList = new ArrayList<>();
+ setupEmergencyCallShortcutButton();
+
+ switchView(mEmergencyShortcutView, mDialpadView, false);
+ }
+
+ private void setLocationInfo(String country) {
+ final View locationInfo = findViewById(R.id.location_info);
+
+ if (TextUtils.isEmpty(country)) {
+ locationInfo.setVisibility(View.INVISIBLE);
+ } else {
+ final TextView location = (TextView) locationInfo.findViewById(R.id.location_text);
+ location.setText(country);
+ locationInfo.setVisibility(View.VISIBLE);
+ }
+ }
+
+ // TODO: Integrate emergency phone number table.
+ // Using default layout(no location, phone number is 112, description is Emergency,
+ // and icon is cross shape) until integrating emergency phone number table.
+ private void setupEmergencyCallShortcutButton() {
+ final ViewGroup shortcutButtonContainer = findViewById(
+ R.id.emergency_shortcut_buttons_container);
+ shortcutButtonContainer.setClipToOutline(true);
+
+ final EmergencyShortcutButton button =
+ (EmergencyShortcutButton) getLayoutInflater().inflate(
+ R.layout.emergency_shortcut_button,
+ shortcutButtonContainer, false);
+
+ button.setPhoneNumber("112");
+ button.setPhoneDescription("Emergency");
+ button.setPhoneTypeIcon(R.drawable.ic_emergency_number_24);
+ button.setOnConfirmClickListener(this);
+
+ shortcutButtonContainer.addView(button);
+ mEmergencyShortcutButtonList.add(button);
+
+ //Set emergency number title for numerous buttons.
+ if (shortcutButtonContainer.getChildCount() > 1) {
+ final TextView emergencyNumberTitle = findViewById(R.id.emergency_number_title);
+ emergencyNumberTitle.setText(getString(R.string.numerous_emergency_numbers_title));
+ }
+ }
+
+ /**
+ * Called by the activity before a touch event is dispatched to the view hierarchy.
+ */
+ private void onPreTouchEvent(MotionEvent event) {
+ mEmergencyActionGroup.onPreTouchEvent(event);
+
+ if (mEmergencyShortcutButtonList != null) {
+ for (EmergencyShortcutButton button : mEmergencyShortcutButtonList) {
+ button.onPreTouchEvent(event);
+ }
+ }
+ }
+
+ /**
+ * Called by the activity after a touch event is dispatched to the view hierarchy.
+ */
+ private void onPostTouchEvent(MotionEvent event) {
+ mEmergencyActionGroup.onPostTouchEvent(event);
+
+ if (mEmergencyShortcutButtonList != null) {
+ for (EmergencyShortcutButton button : mEmergencyShortcutButtonList) {
+ button.onPostTouchEvent(event);
+ }
+ }
+ }
+
+ /**
+ * Switch two view.
+ *
+ * @param displayView the view would be displayed.
+ * @param hideView the view would be hidden.
+ * @param hasAnimation is {@code true} when the view should be displayed with animation.
+ */
+ private void switchView(View displayView, View hideView, boolean hasAnimation) {
+ if (displayView == null || hideView == null) {
+ return;
+ }
+
+ if (displayView.getVisibility() == View.VISIBLE) {
+ return;
+ }
+
+ if (hasAnimation) {
+ crossfade(hideView, displayView);
+ } else {
+ hideView.setVisibility(View.GONE);
+ displayView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Fade out and fade in animation between two view transition.
+ */
+ private void crossfade(View fadeOutView, View fadeInView) {
+ if (fadeOutView == null || fadeInView == null) {
+ return;
+ }
+ final int shortAnimationDuration = getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+
+ fadeInView.setAlpha(0f);
+ fadeInView.setVisibility(View.VISIBLE);
+
+ fadeInView.animate()
+ .alpha(1f)
+ .setDuration(shortAnimationDuration)
+ .setListener(null);
+
+ fadeOutView.animate()
+ .alpha(0f)
+ .setDuration(shortAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ fadeOutView.setVisibility(View.GONE);
+ }
+ });
+ }
}
diff --git a/src/com/android/phone/EmergencyInfoGroup.java b/src/com/android/phone/EmergencyInfoGroup.java
new file mode 100644
index 0000000..d0dc322
--- /dev/null
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -0,0 +1,148 @@
+/*
+ * 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;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.internal.util.UserIcons;
+
+import java.util.List;
+
+/**
+ * EmergencyInfoGroup display user icon and user name. And it is an entry point to
+ * Emergency Information.
+ */
+public class EmergencyInfoGroup extends FrameLayout {
+ private ImageView mEmergencyInfoImage;
+ private TextView mEmergencyInfoName;
+ private TextView mEmergencyInfoHint;
+ private View mEmergencyInfoButton;
+
+ public EmergencyInfoGroup(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mEmergencyInfoButton = findViewById(R.id.emergency_info_button);
+ mEmergencyInfoImage = (ImageView) findViewById(R.id.emergency_info_image);
+ mEmergencyInfoName = (TextView) findViewById(R.id.emergency_info_name);
+ mEmergencyInfoHint = (TextView) findViewById(R.id.emergency_info_hint);
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == View.VISIBLE) {
+ setupButtonInfo();
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ updateLayoutHeight();
+ }
+
+ private void setupButtonInfo() {
+ List<ResolveInfo> infos;
+
+ if (TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED) {
+ infos = EmergencyAssistanceHelper.resolveAssistPackageAndQueryActivities(getContext());
+ } else {
+ infos = null;
+ }
+
+ boolean visible = false;
+
+ if (infos != null && infos.size() > 0) {
+ final String packageName = infos.get(0).activityInfo.packageName;
+ final Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
+ .setPackage(packageName);
+ mEmergencyInfoButton.setTag(R.id.tag_intent, intent);
+ mEmergencyInfoImage.setImageDrawable(getCircularUserIcon());
+
+ visible = true;
+ }
+ mEmergencyInfoName.setText(getUserName());
+
+ setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Get user icon.
+ *
+ * @return user icon, or default user icon if user do not set photo.
+ */
+ private Drawable getCircularUserIcon() {
+ final UserManager userManager = (UserManager) getContext().getSystemService(
+ Context.USER_SERVICE);
+ Bitmap bitmapUserIcon = userManager.getUserIcon(UserHandle.getCallingUserId());
+
+ if (bitmapUserIcon == null) {
+ // get default user icon.
+ final Drawable defaultUserIcon = UserIcons.getDefaultUserIcon(
+ getContext().getResources(), UserHandle.myUserId(), false);
+ bitmapUserIcon = UserIcons.convertToBitmap(defaultUserIcon);
+ }
+ RoundedBitmapDrawable drawableUserIcon = RoundedBitmapDrawableFactory.create(
+ getContext().getResources(), bitmapUserIcon);
+ drawableUserIcon.setCircular(true);
+
+ return drawableUserIcon;
+ }
+
+ private CharSequence getUserName() {
+ final UserManager userManager = (UserManager) getContext().getSystemService(
+ Context.USER_SERVICE);
+ final String userName = userManager.getUserName();
+
+ return TextUtils.isEmpty(userName) ? getContext().getText(
+ R.string.emergency_information_owner_hint) : userName;
+ }
+
+ private void updateLayoutHeight() {
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();
+ // Update height if mEmergencyInfoHint text line more than 1.
+ // EmergencyInfoGroup max line is 2, eclipse type "end" will be adopt if string too long.
+ params.height =
+ mEmergencyInfoHint.getLineCount() > 1 ? getResources().getDimensionPixelSize(
+ R.dimen.emergency_info_button_multiline_height)
+ : getResources().getDimensionPixelSize(
+ R.dimen.emergency_info_button_singleline_height);
+ setLayoutParams(params);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/phone/EmergencyShortcutButton.java b/src/com/android/phone/EmergencyShortcutButton.java
new file mode 100644
index 0000000..92877c7
--- /dev/null
+++ b/src/com/android/phone/EmergencyShortcutButton.java
@@ -0,0 +1,257 @@
+/*
+ * 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;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Emergency shortcut button displays a local emergency phone number information(including phone
+ * number, and phone type). To decrease false clicking, it need to click twice to confirm to place
+ * an emergency phone call.
+ *
+ * <p> The button need to be set an {@link OnConfirmClickListener} from activity to handle dial
+ * function.
+ *
+ * <p> First clicking on the button, it would change the view of call number information to
+ * the view of confirmation. And then clicking on the view of confirmation, it will place an
+ * emergency call.
+ *
+ * <p> For screen reader, it changed to click twice on the view of call number information to
+ * place an emergency call. The view of confirmation will not display.
+ */
+public class EmergencyShortcutButton extends FrameLayout implements View.OnClickListener {
+ // Time to hide view of confirmation.
+ private static final long HIDE_DELAY = 3000;
+
+ private static final int[] ICON_VIEWS = {R.id.phone_type_icon, R.id.confirmed_phone_type_icon};
+ private View mCallNumberInfoView;
+ private View mConfirmView;
+
+ private TextView mPhoneNumber;
+ private TextView mPhoneTypeDescription;
+ private TextView mPhoneCallHint;
+ private MotionEvent mPendingTouchEvent;
+ private OnConfirmClickListener mOnConfirmClickListener;
+
+ private boolean mConfirmViewHiding;
+
+ public EmergencyShortcutButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the view of confirmation on shortcut
+ * button is clicked.
+ */
+ public interface OnConfirmClickListener {
+ /**
+ * Called when the view of confirmation on shortcut button has been clicked.
+ *
+ * @param button The shortcut button that was clicked.
+ */
+ void onConfirmClick(EmergencyShortcutButton button);
+ }
+
+ /**
+ * Register a callback {@link OnConfirmClickListener} to be invoked when view of confirmation
+ * is clicked.
+ *
+ * @param onConfirmClickListener The callback that will run.
+ */
+ public void setOnConfirmClickListener(OnConfirmClickListener onConfirmClickListener) {
+ mOnConfirmClickListener = onConfirmClickListener;
+ }
+
+ /**
+ * Set icon for different phone number type.
+ *
+ * @param resId The resource identifier of the drawable.
+ */
+ public void setPhoneTypeIcon(int resId) {
+ for (int iconView : ICON_VIEWS) {
+ ImageView phoneTypeIcon = findViewById(iconView);
+ phoneTypeIcon.setImageResource(resId);
+ }
+ }
+
+ /**
+ * Set emergency phone number description.
+ */
+ public void setPhoneDescription(@NonNull String description) {
+ mPhoneTypeDescription.setText(description);
+ }
+
+ /**
+ * Set emergency phone number.
+ */
+ public void setPhoneNumber(@NonNull String number) {
+ mPhoneNumber.setText(number);
+ mPhoneCallHint.setText(
+ getContext().getString(R.string.emergency_call_shortcut_hint, number));
+
+ // Set content description for phone number.
+ if (number.length() > 1) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (char c : number.toCharArray()) {
+ stringBuilder.append(c).append(" ");
+ }
+ mPhoneNumber.setContentDescription(stringBuilder.toString().trim());
+ }
+ }
+
+ /**
+ * Get emergency phone number.
+ *
+ * @return phone number, or {@code null} if {@code mPhoneNumber} does not be set.
+ */
+ public String getPhoneNumber() {
+ return mPhoneNumber != null ? mPhoneNumber.getText().toString() : null;
+ }
+
+ /**
+ * Called by the activity before a touch event is dispatched to the view hierarchy.
+ */
+ public void onPreTouchEvent(MotionEvent event) {
+ mPendingTouchEvent = event;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ boolean handled = super.dispatchTouchEvent(event);
+ if (mPendingTouchEvent == event && handled) {
+ mPendingTouchEvent = null;
+ }
+ return handled;
+ }
+
+ /**
+ * Called by the activity after a touch event is dispatched to the view hierarchy.
+ */
+ public void onPostTouchEvent(MotionEvent event) {
+ // Hide the confirmation button if a touch event was delivered to the activity but not to
+ // this view.
+ if (mPendingTouchEvent != null) {
+ hideSelectedButton();
+ }
+ mPendingTouchEvent = null;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mCallNumberInfoView = findViewById(R.id.emergency_call_number_info_view);
+ mConfirmView = findViewById(R.id.emergency_call_confirm_view);
+
+ mCallNumberInfoView.setOnClickListener(this);
+ mConfirmView.setOnClickListener(this);
+
+ mPhoneNumber = (TextView) mCallNumberInfoView.findViewById(R.id.phone_number);
+ mPhoneTypeDescription = (TextView) mCallNumberInfoView.findViewById(
+ R.id.phone_number_description);
+
+ mPhoneCallHint = (TextView) mConfirmView.findViewById(R.id.phone_call_hint);
+
+ mConfirmViewHiding = true;
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.emergency_call_number_info_view:
+ if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+ if (mOnConfirmClickListener != null) {
+ mOnConfirmClickListener.onConfirmClick(this);
+ }
+ } else {
+ revealSelectedButton();
+ }
+ break;
+ case R.id.emergency_call_confirm_view:
+ if (mOnConfirmClickListener != null) {
+ mOnConfirmClickListener.onConfirmClick(this);
+ }
+ break;
+ }
+ }
+
+ private void revealSelectedButton() {
+ mConfirmViewHiding = false;
+
+ mConfirmView.setVisibility(View.VISIBLE);
+ int centerX = mCallNumberInfoView.getLeft() + mCallNumberInfoView.getWidth() / 2;
+ int centerY = mCallNumberInfoView.getTop() + mCallNumberInfoView.getHeight() / 2;
+ Animator reveal = ViewAnimationUtils.createCircularReveal(
+ mConfirmView,
+ centerX,
+ centerY,
+ 0,
+ Math.max(centerX, mConfirmView.getWidth() - centerX)
+ + Math.max(centerY, mConfirmView.getHeight() - centerY));
+ reveal.start();
+
+ postDelayed(mCancelSelectedButtonRunnable, HIDE_DELAY);
+ mConfirmView.requestFocus();
+ }
+
+ private void hideSelectedButton() {
+ if (mConfirmViewHiding || mConfirmView.getVisibility() != VISIBLE) {
+ return;
+ }
+
+ mConfirmViewHiding = true;
+
+ removeCallbacks(mCancelSelectedButtonRunnable);
+ int centerX = mConfirmView.getLeft() + mConfirmView.getWidth() / 2;
+ int centerY = mConfirmView.getTop() + mConfirmView.getHeight() / 2;
+ Animator reveal = ViewAnimationUtils.createCircularReveal(
+ mConfirmView,
+ centerX,
+ centerY,
+ Math.max(centerX, mCallNumberInfoView.getWidth() - centerX)
+ + Math.max(centerY, mCallNumberInfoView.getHeight() - centerY),
+ 0);
+ reveal.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mConfirmView.setVisibility(INVISIBLE);
+ }
+ });
+ reveal.start();
+
+ mCallNumberInfoView.requestFocus();
+ }
+
+ private final Runnable mCancelSelectedButtonRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (!isAttachedToWindow()) return;
+ hideSelectedButton();
+ }
+ };
+}
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index c48f5cb..0c4cffc 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -788,6 +788,9 @@
int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
mActiveSubInfos = new ArrayList<SubscriptionInfo>(max);
+ int currentTab = mTabHost != null ? mTabHost.getCurrentTab() : 0;
+ updatePhone(currentTab);
+ updateEnabledNetworksEntries();
Log.i(LOG_TAG, "onCreate:-");
}
@@ -1025,95 +1028,7 @@
updateGsmUmtsOptions(this, prefSet, phoneSubId, mNetworkQueryService);
} else {
prefSet.removePreference(mButtonPreferredNetworkMode);
- final int phoneType = mPhone.getPhoneType();
- if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
- int lteForced = android.provider.Settings.Global.getInt(
- mPhone.getContext().getContentResolver(),
- android.provider.Settings.Global.LTE_SERVICE_FORCED + mPhone.getSubId(),
- 0);
-
- if (isLteOnCdma) {
- if (lteForced == 0) {
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_cdma_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_cdma_values);
- } else {
- switch (settingsNetworkMode) {
- case Phone.NT_MODE_CDMA:
- case Phone.NT_MODE_CDMA_NO_EVDO:
- case Phone.NT_MODE_EVDO_NO_CDMA:
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_cdma_no_lte_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_cdma_no_lte_values);
- break;
- case Phone.NT_MODE_GLOBAL:
- case Phone.NT_MODE_LTE_CDMA_AND_EVDO:
- case Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
- case Phone.NT_MODE_LTE_ONLY:
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_cdma_only_lte_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_cdma_only_lte_values);
- break;
- default:
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_cdma_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_cdma_values);
- break;
- }
- }
- }
- updateCdmaOptions(this, prefSet, mPhone);
-
- } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
- if (isSupportTdscdma()) {
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_tdscdma_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_tdscdma_values);
- } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)
- && !getResources().getBoolean(R.bool.config_enabled_lte)) {
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_except_gsm_lte_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_except_gsm_lte_values);
- } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)) {
- int select = (mShow4GForLTE == true) ?
- R.array.enabled_networks_except_gsm_4g_choices
- : R.array.enabled_networks_except_gsm_choices;
- mButtonEnabledNetworks.setEntries(select);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_except_gsm_values);
- } else if (!getResources().getBoolean(R.bool.config_enabled_lte)) {
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_except_lte_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_except_lte_values);
- } else if (mIsGlobalCdma) {
- mButtonEnabledNetworks.setEntries(
- R.array.enabled_networks_cdma_choices);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_cdma_values);
- } else {
- int select = (mShow4GForLTE == true) ? R.array.enabled_networks_4g_choices
- : R.array.enabled_networks_choices;
- mButtonEnabledNetworks.setEntries(select);
- mButtonEnabledNetworks.setEntryValues(
- R.array.enabled_networks_values);
- }
- updateGsmUmtsOptions(this, prefSet, phoneSubId, mNetworkQueryService);
- } else {
- throw new IllegalStateException("Unexpected phone type: " + phoneType);
- }
- if (isWorldMode()) {
- mButtonEnabledNetworks.setEntries(
- R.array.preferred_network_mode_choices_world_mode);
- mButtonEnabledNetworks.setEntryValues(
- R.array.preferred_network_mode_values_world_mode);
- }
+ updateEnabledNetworksEntries();
mButtonEnabledNetworks.setOnPreferenceChangeListener(this);
if (DBG) log("settingsNetworkMode: " + settingsNetworkMode);
}
@@ -1214,6 +1129,107 @@
}
}
+ // Requires that mPhone is up to date
+ void updateEnabledNetworksEntries() {
+ final int phoneType = mPhone.getPhoneType();
+ final PersistableBundle carrierConfig =
+ PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+ if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+ final int lteForced = android.provider.Settings.Global.getInt(
+ mPhone.getContext().getContentResolver(),
+ android.provider.Settings.Global.LTE_SERVICE_FORCED + mPhone.getSubId(),
+ 0);
+ final boolean isLteOnCdma = mPhone.getLteOnCdmaMode()
+ == PhoneConstants.LTE_ON_CDMA_TRUE;
+ final int settingsNetworkMode = android.provider.Settings.Global.getInt(
+ mPhone.getContext().getContentResolver(),
+ android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mPhone.getSubId(),
+ preferredNetworkMode);
+ if (isLteOnCdma) {
+ if (lteForced == 0) {
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_cdma_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_cdma_values);
+ } else {
+ switch (settingsNetworkMode) {
+ case Phone.NT_MODE_CDMA:
+ case Phone.NT_MODE_CDMA_NO_EVDO:
+ case Phone.NT_MODE_EVDO_NO_CDMA:
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_cdma_no_lte_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_cdma_no_lte_values);
+ break;
+ case Phone.NT_MODE_GLOBAL:
+ case Phone.NT_MODE_LTE_CDMA_AND_EVDO:
+ case Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
+ case Phone.NT_MODE_LTE_ONLY:
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_cdma_only_lte_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_cdma_only_lte_values);
+ break;
+ default:
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_cdma_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_cdma_values);
+ break;
+ }
+ }
+ }
+ updateCdmaOptions(this, getPreferenceScreen(), mPhone);
+
+ } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+ if (isSupportTdscdma()) {
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_tdscdma_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_tdscdma_values);
+ } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)
+ && !getResources().getBoolean(R.bool.config_enabled_lte)) {
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_except_gsm_lte_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_except_gsm_lte_values);
+ } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)) {
+ int select = mShow4GForLTE
+ ? R.array.enabled_networks_except_gsm_4g_choices
+ : R.array.enabled_networks_except_gsm_choices;
+ mButtonEnabledNetworks.setEntries(select);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_except_gsm_values);
+ } else if (!getResources().getBoolean(R.bool.config_enabled_lte)) {
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_except_lte_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_except_lte_values);
+ } else if (mIsGlobalCdma) {
+ mButtonEnabledNetworks.setEntries(
+ R.array.enabled_networks_cdma_choices);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_cdma_values);
+ } else {
+ int select = mShow4GForLTE ? R.array.enabled_networks_4g_choices
+ : R.array.enabled_networks_choices;
+ mButtonEnabledNetworks.setEntries(select);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.enabled_networks_values);
+ }
+ updateGsmUmtsOptions(this, getPreferenceScreen(), mPhone.getSubId(),
+ mNetworkQueryService);
+ } else {
+ throw new IllegalStateException("Unexpected phone type: " + phoneType);
+ }
+ if (isWorldMode()) {
+ mButtonEnabledNetworks.setEntries(
+ R.array.preferred_network_mode_choices_world_mode);
+ mButtonEnabledNetworks.setEntryValues(
+ R.array.preferred_network_mode_values_world_mode);
+ }
+ }
+
@Override
public void onPause() {
super.onPause();
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 2df3bbe..444eae0 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -102,6 +102,7 @@
import com.android.internal.telephony.NetworkScanRequestTracker;
import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConfigurationManager;
import com.android.internal.telephony.PhoneConstantConversions;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneFactory;
@@ -216,6 +217,7 @@
private MainThreadHandler mMainThreadHandler;
private SubscriptionController mSubscriptionController;
private SharedPreferences mTelephonySharedPreferences;
+ private PhoneConfigurationManager mPhoneConfigurationManager;
private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
@@ -1091,6 +1093,7 @@
PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
mSubscriptionController = SubscriptionController.getInstance();
mNetworkScanRequestTracker = new NetworkScanRequestTracker();
+ mPhoneConfigurationManager = PhoneConfigurationManager.getInstance();
publish();
}
@@ -5173,4 +5176,19 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+ mApp, subId, callingPackage, "getNumberOfModemsWithSimultaneousDataConnections")) {
+ return -1;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mPhoneConfigurationManager.getNumberOfModemsWithSimultaneousDataConnections();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
diff --git a/src/com/android/phone/ecc/CountryEccInfo.java b/src/com/android/phone/ecc/CountryEccInfo.java
new file mode 100644
index 0000000..6bef8d3
--- /dev/null
+++ b/src/com/android/phone/ecc/CountryEccInfo.java
@@ -0,0 +1,46 @@
+/*
+ * 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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * ECC info of a country.
+ */
+public class CountryEccInfo {
+ private final String mFallbackEcc;
+ private final EccInfo[] mEccInfoList;
+
+ public CountryEccInfo(String eccFallback, @NonNull List<EccInfo> eccInfoList) {
+ mFallbackEcc = eccFallback;
+ mEccInfoList = eccInfoList.toArray(new EccInfo[eccInfoList.size()]);
+ }
+
+ /**
+ * @return fallback ECC, null if not available.
+ */
+ public @Nullable String getFallbackEcc() {
+ return mFallbackEcc;
+ }
+
+ public @NonNull EccInfo[] getEccInfoList() {
+ return mEccInfoList.clone();
+ }
+}
diff --git a/src/com/android/phone/ecc/EccInfo.java b/src/com/android/phone/ecc/EccInfo.java
new file mode 100644
index 0000000..d047b9b
--- /dev/null
+++ b/src/com/android/phone/ecc/EccInfo.java
@@ -0,0 +1,88 @@
+/*
+ * 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 androidx.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Emergency call code info.
+ */
+public class EccInfo {
+ /**
+ * ECC Types.
+ */
+ public enum Type {
+ POLICE,
+ AMBULANCE,
+ FIRE,
+ }
+
+ private final String mNumber;
+ private final Type[] mTypes;
+
+ public EccInfo(@NonNull String number, @NonNull Type type) {
+ mNumber = number;
+ mTypes = new Type[]{ type };
+ }
+
+ public EccInfo(@NonNull String number, @NonNull List<Type> types) {
+ mNumber = number;
+ mTypes = types.toArray(new Type[types.size()]);
+ }
+
+ /**
+ * @return ECC number.
+ */
+ public @NonNull String getNumber() {
+ return mNumber;
+ }
+
+ /**
+ * Check whether the ECC number has any matches to the target type.
+ *
+ * @param target The target type to check.
+ * @return true if the target matches.
+ */
+ public boolean containsType(@NonNull Type target) {
+ for (Type type : mTypes) {
+ if (target.equals(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the types of the ECC number.
+ *
+ * @return Copied types array.
+ */
+ public Type[] getTypes() {
+ return mTypes.clone();
+ }
+
+ /**
+ * Get how many types the ECC number is.
+ *
+ * @return Count of types.
+ */
+ public int getTypesCount() {
+ return mTypes.length;
+ }
+}
diff --git a/src/com/android/phone/ecc/EccInfoHelper.java b/src/com/android/phone/ecc/EccInfoHelper.java
new file mode 100644
index 0000000..514f388
--- /dev/null
+++ b/src/com/android/phone/ecc/EccInfoHelper.java
@@ -0,0 +1,213 @@
+/*
+ * 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.AsyncTask;
+import android.provider.Settings;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityWcdma;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.telephony.MccTable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper for retrieve ECC info for current country.
+ */
+public class EccInfoHelper {
+ private static final String LOG_TAG = "EccInfoHelper";
+
+ // country ISO to ECC list data source
+ private IsoToEccRepository mEccRepo;
+
+ /**
+ * Callback for {@link #getCountryEccInfoAsync}.
+ */
+ public interface CountryEccInfoResultCallback {
+ /**
+ * Called if successfully get country ECC info.
+ *
+ * @param iso Detected current country ISO.
+ * @param countryEccInfo The EccInfo of current country.
+ */
+ void onSuccess(@NonNull String iso, @NonNull CountryEccInfo countryEccInfo);
+
+ /**
+ * Called if failed to get country ISO.
+ */
+ void onDetectCountryFailed();
+
+ /**
+ * Called if failed to get ECC info for given country ISO.
+ *
+ * @param iso Detected current country ISO.
+ */
+ void onRetrieveCountryEccInfoFailed(@NonNull String iso);
+ }
+
+ /**
+ * Constructor of EccInfoHelper
+ *
+ * @param eccRepository A repository for ECC info, indexed by country ISO.
+ */
+ public EccInfoHelper(@NonNull IsoToEccRepository eccRepository) {
+ mEccRepo = eccRepository;
+ }
+
+ /**
+ * Get ECC info for current location, base on detected country ISO.
+ * It's possible we cannot detect current country, ex. device is in airplane mode,
+ * or there's no available base station near by.
+ *
+ * @param context The context used to access resources.
+ * @param callback Callback for result.
+ */
+ public void getCountryEccInfoAsync(final @NonNull Context context,
+ final CountryEccInfoResultCallback callback) {
+ new AsyncTask<Void, Void, Pair<String, CountryEccInfo>>() {
+ @Override
+ protected Pair<String, CountryEccInfo> doInBackground(Void... voids) {
+ String iso = getCurrentCountryIso(context);
+ if (TextUtils.isEmpty(iso)) {
+ return null;
+ }
+
+ CountryEccInfo dialableCountryEccInfo;
+ try {
+ // access data source in background thread to avoid possible file IO caused ANR.
+ CountryEccInfo rawEccInfo = mEccRepo.getCountryEccInfo(context, iso);
+ dialableCountryEccInfo = getDialableCountryEccInfo(rawEccInfo);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Failed to retrieve ECC: " + e.getMessage());
+ dialableCountryEccInfo = null;
+ }
+ return new Pair<>(iso, dialableCountryEccInfo);
+ }
+
+ @Override
+ protected void onPostExecute(Pair<String, CountryEccInfo> result) {
+ if (callback != null) {
+ if (result == null) {
+ callback.onDetectCountryFailed();
+ } else {
+ String iso = result.first;
+ CountryEccInfo countryEccInfo = result.second;
+ if (countryEccInfo == null) {
+ callback.onRetrieveCountryEccInfoFailed(iso);
+ } else {
+ callback.onSuccess(iso, countryEccInfo);
+ }
+ }
+ }
+ }
+ }.execute();
+ }
+
+ private @NonNull CountryEccInfo getDialableCountryEccInfo(CountryEccInfo countryEccInfo) {
+ ArrayList<EccInfo> dialableECCList = new ArrayList<>();
+ String dialableFallback = null;
+
+ // filter out non-dialable ECC
+ if (countryEccInfo != null) {
+ for (EccInfo entry : countryEccInfo.getEccInfoList()) {
+ if (PhoneNumberUtils.isEmergencyNumber(entry.getNumber())) {
+ dialableECCList.add(entry);
+ }
+ }
+ String defaultFallback = countryEccInfo.getFallbackEcc();
+ if (PhoneNumberUtils.isEmergencyNumber(defaultFallback)) {
+ dialableFallback = defaultFallback;
+ }
+ }
+ return new CountryEccInfo(dialableFallback, dialableECCList);
+ }
+
+ private @Nullable 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);
+ if (airplaneMode != 0) {
+ Log.d(LOG_TAG, "Airplane mode is on, do not get country ISO.");
+ return null;
+ }
+
+ TelephonyManager tm = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ String iso = tm.getNetworkCountryIso();
+ Log.d(LOG_TAG, "Current country ISO is " + iso);
+
+ if (TextUtils.isEmpty(iso)) {
+ // XXX: according to ServiceStateTracker's implementation, retrieve cell info in a
+ // thread other than TelephonyManager's main thread.
+ String mcc = getCurrentMccFromCellInfo(context);
+ iso = MccTable.countryCodeForMcc(mcc);
+ Log.d(LOG_TAG, "Current mcc is " + mcc + ", mapping to ISO: " + iso);
+ }
+ return iso;
+ }
+
+ // 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) {
+ // retrieve mcc info from base station even no SIM present.
+ TelephonyManager tm = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ List<CellInfo> cellInfos = tm.getAllCellInfo();
+ String mcc = null;
+ if (cellInfos != null) {
+ for (CellInfo ci : cellInfos) {
+ if (ci instanceof CellInfoGsm) {
+ CellInfoGsm cellInfoGsm = (CellInfoGsm) ci;
+ CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
+ mcc = cellIdentityGsm.getMccString();
+ break;
+ } else if (ci instanceof CellInfoWcdma) {
+ CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) ci;
+ CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity();
+ mcc = cellIdentityWcdma.getMccString();
+ break;
+ } else if (ci instanceof CellInfoLte) {
+ CellInfoLte cellInfoLte = (CellInfoLte) ci;
+ CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
+ mcc = cellIdentityLte.getMccString();
+ break;
+ }
+ }
+ Log.d(LOG_TAG, "Retrieve MCC from cell info list: " + mcc);
+ } else {
+ Log.w(LOG_TAG, "Cannot get cell info list.");
+ }
+ return mcc;
+ }
+}
diff --git a/src/com/android/phone/ecc/IsoToEccRepository.java b/src/com/android/phone/ecc/IsoToEccRepository.java
new file mode 100644
index 0000000..6d95af4
--- /dev/null
+++ b/src/com/android/phone/ecc/IsoToEccRepository.java
@@ -0,0 +1,42 @@
+/*
+ * 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 androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.IOException;
+
+/**
+ * Data source for country ISO to ECC info list mapping.
+ */
+public interface IsoToEccRepository {
+ /**
+ * Get available emergency numbers for given country ISO. Because the possible of IO wait
+ * (depends on the implementation), this method should not be called in the main thread.
+ *
+ * @param context The context used to access resources.
+ * @param iso For which ECC info list is returned.
+ * @return The ECC info of given ISO. Null if no match.
+ * @throws IOException if an error occurs while initialize the repository or retrieving
+ * the {@link CountryEccInfo}.
+ */
+ @Nullable CountryEccInfo getCountryEccInfo(@NonNull Context context, @Nullable String iso)
+ throws IOException;
+}
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index 57b6d8e..0eb3845 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -57,10 +57,17 @@
if (DBG) Log.d(LOG_TAG, "PhoneStateListener.onCallStateChanged: state=" + state);
Preference pref = getPreferenceScreen().findPreference(BUTTON_TTY_KEY);
if (pref != null) {
- final boolean isVolteTtySupported = ImsManager.isVolteEnabledByPlatform(mContext)
- && getVolteTtySupported();
- pref.setEnabled((isVolteTtySupported && !isVideoCallOrConferenceInProgress()) ||
- (state == TelephonyManager.CALL_STATE_IDLE));
+ // Use TelephonyManager#getCallState instead of 'state' parameter because
+ // needs to check the current state of all phone calls to
+ // support multi sim configuration.
+ TelephonyManager telephonyManager =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ final boolean isVolteTtySupported = getVolteTtySupported();
+ final boolean isVolteCurrentlyEnabled =
+ ImsManager.isVolteEnabledByPlatform(mContext);
+ pref.setEnabled((isVolteTtySupported && isVolteCurrentlyEnabled &&
+ !isVideoCallOrConferenceInProgress()) ||
+ (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE));
}
}
};
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 6c8dcaa..642af85 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -107,9 +107,31 @@
}
/**
+ * Trigger re-registration of this account.
+ */
+ public void reRegisterPstnPhoneAccount() {
+ PhoneAccount newAccount = buildPstnPhoneAccount(mIsEmergency, mIsDummy);
+ if (!newAccount.equals(mAccount)) {
+ Log.i(this, "reRegisterPstnPhoneAccount: subId: " + getSubId()
+ + " - re-register due to account change.");
+ mTelecomManager.registerPhoneAccount(newAccount);
+ mAccount = newAccount;
+ } else {
+ Log.i(this, "reRegisterPstnPhoneAccount: subId: " + getSubId() + " - no change");
+ }
+ }
+
+ private PhoneAccount registerPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount) {
+ PhoneAccount account = buildPstnPhoneAccount(mIsEmergency, mIsDummy);
+ // Register with Telecom and put into the account entry.
+ mTelecomManager.registerPhoneAccount(account);
+ return account;
+ }
+
+ /**
* Registers the specified account with Telecom as a PhoneAccountHandle.
*/
- private PhoneAccount registerPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount) {
+ private PhoneAccount buildPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount) {
String dummyPrefix = isDummyAccount ? "Dummy " : "";
// Build the Phone account handle.
@@ -312,9 +334,6 @@
.setGroupId(groupId)
.build();
- // Register with Telecom and put into the account entry.
- mTelecomManager.registerPhoneAccount(account);
-
return account;
}
@@ -322,6 +341,10 @@
return mAccount != null ? mAccount.getAccountHandle() : null;
}
+ public int getSubId() {
+ return mPhone.getSubId();
+ }
+
/**
* Determines from carrier configuration whether pausing of IMS video calls is supported.
*
@@ -579,19 +602,27 @@
}
};
- private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- Log.i(this, "User changed, re-registering phone accounts.");
+ if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+ Log.i(this, "User changed, re-registering phone accounts.");
- int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- UserHandle currentUserHandle = new UserHandle(userHandleId);
- mIsPrimaryUser = UserManager.get(mContext).getPrimaryUser().getUserHandle()
- .equals(currentUserHandle);
+ int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ UserHandle currentUserHandle = new UserHandle(userHandleId);
+ mIsPrimaryUser = UserManager.get(mContext).getPrimaryUser().getUserHandle()
+ .equals(currentUserHandle);
- // Any time the user changes, re-register the accounts.
- tearDownAccounts();
- setupAccounts();
+ // Any time the user changes, re-register the accounts.
+ tearDownAccounts();
+ setupAccounts();
+ } else if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(
+ intent.getAction())) {
+ Log.i(this, "Carrier-config changed, checking for phone account updates.");
+ int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ handleCarrierConfigChange(subId);
+ }
}
};
@@ -814,8 +845,10 @@
// Listen for user switches. When the user switches, we need to ensure that if the current
// use is not the primary user we disable video calling.
- mContext.registerReceiver(mUserSwitchedReceiver,
- new IntentFilter(Intent.ACTION_USER_SWITCHED));
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
// Listen to the RTT system setting so that we update it when the user flips it.
ContentObserver rttUiSettingObserver = new ContentObserver(
@@ -951,4 +984,27 @@
mAccounts.clear();
}
}
+
+ /**
+ * Handles changes to the carrier configuration which may impact a phone account. There are
+ * some extras defined in the {@link PhoneAccount} which are based on carrier config options.
+ * Only checking for carrier config changes when the subscription is configured runs the risk of
+ * missing carrier config changes which happen later.
+ * @param subId The subid the carrier config changed for, if applicable. Will be
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if not specified.
+ */
+ private void handleCarrierConfigChange(int subId) {
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return;
+ }
+ synchronized (mAccountsLock) {
+ for (AccountEntry entry : mAccounts) {
+ if (entry.getSubId() == subId) {
+ Log.d(this, "handleCarrierConfigChange: subId=%d, accountSubId=%d", subId,
+ entry.getSubId());
+ entry.reRegisterPstnPhoneAccount();
+ }
+ }
+ }
+ }
}