Merge changes from topic "add_faster_emergency_dialer_flag"
am: 6055136b06
Change-Id: I539847baa85d65050863dc435ac10569c925e9b3
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-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-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-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-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-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-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-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/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/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..b98b5c4 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -16,51 +16,108 @@
<!-- 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"/>
+ <include layout="@layout/emergency_shortcut_buttons_group"/>
+ </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 +125,7 @@
android:focusable="true"
android:clickable="true">
- <View
+ <View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="#ffe53935"
@@ -76,7 +133,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 +143,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 +151,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 +159,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 +168,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/layout/emergency_shortcut_button.xml b/res/layout/emergency_shortcut_button.xml
new file mode 100644
index 0000000..5e30d4e5
--- /dev/null
+++ b/res/layout/emergency_shortcut_button.xml
@@ -0,0 +1,122 @@
+<?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="64dp"
+ 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:focusable="true"
+ android:clickable="true">
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:layout_height="40dp"
+ android:layout_width="40dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:background="@drawable/phone_type_icon_background">
+ <ImageView
+ android:id="@+id/phone_type_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+ </FrameLayout>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="center_vertical|start"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/phone_number"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:autoSizeTextType="uniform"
+ android:maxLines="1"
+ android:textStyle="bold"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+ <TextView
+ android:id="@+id/phone_number_description"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:autoSizeTextType="uniform"
+ android:maxLines="1"/>
+ </LinearLayout>
+ </LinearLayout>
+ <ImageView
+ android:id="@+id/microphone_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:src="@drawable/fab_ic_call"/>
+ </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="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:layout_height="40dp"
+ android:layout_width="40dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:background="@drawable/phone_type_icon_background">
+ <ImageView
+ android:id="@+id/confirmed_phone_type_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+ </FrameLayout>
+ <FrameLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="center_vertical|start"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/phone_call_hint"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:autoSizeTextType="uniform"
+ android:maxLines="1"
+ android:textColor="@android:color/white"
+ android:textStyle="italic|bold"/>
+ </FrameLayout>
+ </LinearLayout>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:src="@drawable/fab_ic_call"/>
+ </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..5ba0533
--- /dev/null
+++ b/res/layout/emergency_shortcut_buttons_group.xml
@@ -0,0 +1,63 @@
+<?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="58dp"
+ android:orientation="vertical">
+ <FrameLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:paddingBottom="12dp">
+ <TextView
+ android:id="@+id/emergency_number_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:textStyle="bold"
+ android:maxLines="1"
+ android:text="@string/single_emergency_number_title"/>
+ <LinearLayout
+ android:id="@+id/location_info"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/location_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ 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:maxLines="1"
+ android:textStyle="italic"/>
+ </LinearLayout>
+ </FrameLayout>
+ <LinearLayout
+ android:id="@+id/emergency_shortcut_buttons_container"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ 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..98ffff7 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -54,4 +54,5 @@
<color name="dialer_dialpad_touch_tint">#330288d1</color>
<color name="floating_action_button_touch_tint">#80ffffff</color>
+ <color name="emergency_shortcut_confirm_button_background_color">#E25142</color>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f192ae..2bce34b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1122,8 +1122,18 @@
<!-- 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>
+ <!-- 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 +1377,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 157cf1d..ea9eae1 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;
@@ -56,7 +58,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 +69,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 +88,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";
@@ -119,6 +133,10 @@
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 +166,8 @@
private boolean mIsWfcEmergencyCallingWarningEnabled;
private float mDefaultDigitsTextSize;
+ private boolean mAreEmergencyDialerShortcutsEnabled;
+
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing
@@ -273,6 +293,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
@@ -328,6 +355,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
*/
@@ -375,13 +415,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)) {
+ Log.d(LOG_TAG, "dial emergency number: " + 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 +454,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;
+ }
}
}
@@ -792,4 +858,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..8100a5a
--- /dev/null
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -0,0 +1,126 @@
+/*
+ * 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.util.AttributeSet;
+import android.view.View;
+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 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;
+ }
+}
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();
+ }
+ };
+}