Add faster emergency dialer UI

If flag "faster_emergency_phone_call_enabled" is true, EmergencyDialer
will display emergency dialer shortcuts UI. Otherwise, EmergencyDialer
display original dialer UI.
Faster emergency dialer implement the part of user's Emergency
Infomation, and a button which is used to show dialpad.

Test: Manually

Bug: 112168722
Bug: 80406570

Change-Id: I3637dab0059d6fa87417bb282163ebff04eae71d
Merged-In: I3637dab0059d6fa87417bb282163ebff04eae71d
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_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-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_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-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_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-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_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/btn_emergency_shortcuts.xml b/res/drawable/btn_emergency_shortcuts.xml
new file mode 100644
index 0000000..8198a57
--- /dev/null
+++ b/res/drawable/btn_emergency_shortcuts.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">
+    <solid android:color="?attr/emergencyButtonBackgroundColor"/>
+    <corners android:radius="10dp"/>
+</shape>
\ No newline at end of file
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/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index 2a45433..41da3b1 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -16,51 +16,107 @@
 
 <!-- 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:paddingLeft="18dp"
+        android:paddingRight="18dp"
+        android:paddingBottom="@dimen/dialpad_bottom_padding"
+        android:visibility="gone">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+            <include layout="@layout/emergency_information"/>
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/dialpad_button_container"
+            android:layout_width="@dimen/floating_action_button_width"
+            android:layout_height="@dimen/floating_action_button_height"
+            android:layout_gravity="bottom|end">
+            <ImageButton
+                android:id="@+id/floating_action_button_dialpad"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                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 +124,7 @@
                     android:focusable="true"
                     android:clickable="true">
 
-                <View
+                    <View
                         android:layout_width="match_parent"
                         android:layout_height="match_parent"
                         android:backgroundTint="#ffe53935"
@@ -76,7 +132,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 +142,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 +150,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 +158,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 +167,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..c9e9f8b
--- /dev/null
+++ b/res/layout/emergency_information.xml
@@ -0,0 +1,50 @@
+<?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_group"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:layout_marginTop="48dp"
+    android:orientation="vertical">
+    <TextView
+        android:id="@+id/emergency_info_title"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="start"
+        android:paddingBottom="12dp"
+        android:textStyle="bold"
+        android:text="@string/emergency_information_title"/>
+    <LinearLayout
+        android:id="@+id/emergency_info_button"
+        android:layout_height="64dp"
+        android:layout_width="match_parent"
+        android:layout_marginTop="2dp"
+        android:orientation="horizontal"
+        android:gravity="center_vertical"
+        android:background="@drawable/btn_emergency_shortcuts">
+        <ImageView
+            android:id="@+id/emergency_info_image"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_marginLeft="16dp"
+            android:layout_marginRight="16dp"/>
+        <TextView
+            android:id="@+id/emergency_info_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceButton"/>
+    </LinearLayout>
+</com.android.phone.EmergencyInfoGroup>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e91b79e..d5c9720 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1127,8 +1127,12 @@
     <!-- 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>
 
+    <!-- Title for the button of emergency information -->
+    <string name="emergency_information_title">Emergency information</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>
     <!-- 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 -->
@@ -1372,6 +1376,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/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 31e1958..2c8a40b 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;
@@ -81,6 +83,13 @@
  * 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 click a number to
+ *  make an emergency phone call without entering numbers from dialpad.
+ *  TODO item:
+ *     1.implement emergency shortcut list UI.
+ *     2.integrate emergency phone number table.
  */
 public class EmergencyDialer extends Activity implements View.OnClickListener,
         View.OnLongClickListener, View.OnKeyListener, TextWatcher,
@@ -119,6 +128,8 @@
     ResizingTextEditText mDigits;
     private View mDialButton;
     private View mDelete;
+    private View mEmergencyShortcutView;
+    private View mDialpadView;
 
     private ToneGenerator mToneGenerator;
     private Object mToneGeneratorLock = new Object();
@@ -148,6 +159,8 @@
     private boolean mIsWfcEmergencyCallingWarningEnabled;
     private float mDefaultDigitsTextSize;
 
+    private boolean mAreEmergencyDialerShortcutsEnabled;
+
     @Override
     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
         // Do nothing
@@ -278,6 +291,13 @@
         registerReceiver(mBroadcastReceiver, intentFilter);
 
         mEmergencyActionGroup = (EmergencyActionGroup) findViewById(R.id.emergency_action_group);
+
+        mAreEmergencyDialerShortcutsEnabled = Settings.Global.getInt(getContentResolver(),
+                Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0;
+
+        if (mAreEmergencyDialerShortcutsEnabled) {
+            setupEmergencyShortcutsView();
+        }
     }
 
     @Override
@@ -333,6 +353,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 FasterEmergencyDialer 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
      */
@@ -404,6 +437,17 @@
                 }
                 return;
             }
+            case R.id.floating_action_button_dialpad: {
+                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;
+            }
         }
     }
 
@@ -797,4 +841,77 @@
             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);
+
+        switchView(mEmergencyShortcutView, mDialpadView, false);
+    }
+
+    /**
+     * 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..f63cb26
--- /dev/null
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -0,0 +1,125 @@
+/*
+ * 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.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+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 LinearLayout {
+
+    private ImageView mEmergencyInfoImage;
+    private TextView mEmergencyInfoName;
+    private View mEmergencyInfoTitle;
+    private View mEmergencyInfoButton;
+
+    public EmergencyInfoGroup(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mEmergencyInfoTitle = findViewById(R.id.emergency_info_title);
+        mEmergencyInfoButton = findViewById(R.id.emergency_info_button);
+        mEmergencyInfoImage = (ImageView) findViewById(R.id.emergency_info_image);
+        mEmergencyInfoName = (TextView) findViewById(R.id.emergency_info_name);
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        if (visibility == View.VISIBLE) {
+            setupButtonInfo();
+        }
+    }
+
+    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());
+
+            /* TODO: Get user name.
+                if user name exist:
+                    1. mEmergencyInfoTitle show title.
+                    2. mEmergencyInfoName show user name.
+                if user name does not exist:
+                    1. mEmergencyInfoTitle hide.
+                    2. mEmergencyInfoName show app label. */
+            mEmergencyInfoTitle.setVisibility(View.INVISIBLE);
+            mEmergencyInfoName.setText(getContext().getResources().getString(
+                    R.string.emergency_information_title));
+
+            visible = true;
+        }
+
+        setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    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.getCallingUserId(), false);
+            bitmapUserIcon = UserIcons.convertToBitmap(defaultUserIcon);
+        }
+
+        RoundedBitmapDrawable drawableUserIcon = RoundedBitmapDrawableFactory.create(
+                getContext().getResources(), bitmapUserIcon);
+        drawableUserIcon.setCircular(true);
+
+        return drawableUserIcon;
+    }
+}