[automerger] Add flag to default dialer change dialog am: 1a02fa9e6e am: 4c5c776091 am: 173a9f1884 am: 8ace012336 am: 7de3927260 am: 24cf84d6f0
am: 8f3b02ff3f
Change-Id: I1c4a9669266d8bdb2d0294c387b1841c7885f20b
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 286b73e..9684b94 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -50,14 +50,14 @@
<string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"إلغاء"</string>
<string name="change_default_dialer_warning_message" msgid="1417671460801684999">"سيتمكن <xliff:g id="NEW_APP">%s</xliff:g> من إجراء المكالمات والتحكم في كل جوانبها. يمكن فقط تعيين التطبيقات التي تثق بها باعتبارها تطبيق الهاتف الافتراضي."</string>
<string name="blocked_numbers" msgid="2751843139572970579">"الأرقام المحظورة"</string>
- <string name="blocked_numbers_msg" msgid="1045015186124965643">"لن تتلقى المكالمات أو المراسلات النصية من الأرقام المحظورة."</string>
+ <string name="blocked_numbers_msg" msgid="1045015186124965643">"لن تتلقى أي مكالمات أو مراسلات نصية من الأرقام المحظورة."</string>
<string name="block_number" msgid="1101252256321306179">"إضافة رقم"</string>
<string name="unblock_dialog_body" msgid="1614238499771862793">"هل تريد إلغاء حظر <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>؟"</string>
<string name="unblock_button" msgid="3078048901972674170">"إلغاء الحظر"</string>
<string name="add_blocked_dialog_body" msgid="9030243212265516828">"حظر المكالمات والرسائل النصية من"</string>
<string name="add_blocked_number_hint" msgid="6847675097085433553">"رقم الهاتف"</string>
<string name="block_button" msgid="8822290682524373357">"حظر"</string>
- <string name="non_primary_user" msgid="5180129233352533459">"يمكن لمالك الجهاز فقط الاطلاع على الأرقام المحظورة وإدارتها."</string>
+ <string name="non_primary_user" msgid="5180129233352533459">"يمكن لمالك الجهاز فقط الاطّلاع على الأرقام المحظورة وإدارتها."</string>
<string name="delete_icon_description" msgid="8903995728252556724">"إلغاء الحظر"</string>
<string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"تم إيقاف الحظر مؤقتًا"</string>
<string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"بعد الاتصال الهاتفي أو إرسال رسالة نصية إلى رقم طوارئ، يتم إيقاف تشغيل الحظر لضمان تمكن خدمات الطوارئ من الاتصال بك."</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 63bccaa..569e738 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -39,7 +39,7 @@
<string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Poruka poslana na <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
<string name="enable_account_preference_title" msgid="2021848090086481720">"Računi za pozivanje"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="6872406278300131364">"Dozvoljeni su samo hitni pozivi."</string>
- <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ova aplikacija ne može upućivati odlazne pozive bez dozvole za Telefon."</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ova aplikacija ne može upućivati odlazne pozive bez odobrenja za Telefon."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Da uputite poziv, upišite važeći broj."</string>
<string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Trenutno nije moguće dodati poziv."</string>
<string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj govorne pošte"</string>
@@ -68,13 +68,13 @@
<string name="blocked_numbers_number_already_blocked_message" msgid="4392247814500811798">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> je već blokiran."</string>
<string name="toast_personal_call_msg" msgid="5115361633476779723">"Za upućivanje poziva koristi se lična brojčana tastatura"</string>
<string name="notification_incoming_call" msgid="7713197997773986670">"<xliff:g id="CALL_VIA">%1$s</xliff:g> poziv od osobe <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
- <string name="notification_incoming_video_call" msgid="6638486071698373893">"<xliff:g id="CALL_VIA">%1$s</xliff:g> videopoziv od osobe <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="notification_incoming_video_call" msgid="6638486071698373893">"<xliff:g id="CALL_VIA">%1$s</xliff:g> video poziv od osobe <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
<string name="answering_ends_other_call" msgid="8282145910153766401">"Odgovaranje će prekinuti poziv: <xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
<string name="answering_ends_other_calls" msgid="1198589551399049197">"Odgovaranje će prekinuti pozive: <xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
- <string name="answering_ends_other_video_call" msgid="8510410917384186360">"Odgovaranje će prekinuti videopoziv: <xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
+ <string name="answering_ends_other_video_call" msgid="8510410917384186360">"Odgovaranje će prekinuti video poziv: <xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
<string name="answering_ends_other_managed_call" msgid="5186137550267947785">"Odgovaranje će prekinuti poziv koji je u toku"</string>
<string name="answering_ends_other_managed_calls" msgid="6429838309560397988">"Odgovaranje će prekinuti pozive koji su u toku"</string>
- <string name="answering_ends_other_managed_video_call" msgid="1585423762458248435">"Odgovaranje će prekinuti videopoziv koji je u toku"</string>
+ <string name="answering_ends_other_managed_video_call" msgid="1585423762458248435">"Odgovaranje će prekinuti video poziv koji je u toku"</string>
<string name="answer_incoming_call" msgid="4140530013111794587">"Odgovori"</string>
<string name="decline_incoming_call" msgid="806026168661598368">"Odbij"</string>
<string name="cant_call_due_to_ongoing_call" msgid="4952615196237854748">"Pozivanje nije moguće zbog poziva: <xliff:g id="OTHER_CALL">%1$s</xliff:g>."</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..7d344f1
--- /dev/null
+++ b/res/values-en-rCA/strings.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="telecommAppLabel" product="default" msgid="382363169988504520">"Call Management"</string>
+ <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Phone"</string>
+ <string name="unknown" msgid="6878797917991465859">"Unknown"</string>
+ <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missed call"</string>
+ <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Missed work call"</string>
+ <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missed calls"</string>
+ <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missed calls"</string>
+ <string name="notification_missedCallTicker" msgid="504686252427747209">"Missed call from <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+ <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Call back"</string>
+ <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+ <string name="accessibility_call_muted" msgid="2776111226185342220">"Call muted."</string>
+ <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Speakerphone enabled."</string>
+ <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Can\'t talk now. What\'s up?"</string>
+ <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"I\'ll call you right back."</string>
+ <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"I\'ll call you later."</string>
+ <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Can\'t talk now. Call me later?"</string>
+ <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Quick responses"</string>
+ <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit quick responses"</string>
+ <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+ <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Quick response"</string>
+ <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message sent to <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+ <string name="enable_account_preference_title" msgid="2021848090086481720">"Calling accounts"</string>
+ <string name="outgoing_call_not_allowed_user_restriction" msgid="6872406278300131364">"Only emergency calls are allowed."</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"This application cannot make outgoing calls without Phone permission."</string>
+ <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"To place a call, enter a valid number."</string>
+ <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Call cannot be added at this time."</string>
+ <string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
+ <string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
+ <string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
+ <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Make <xliff:g id="NEW_APP">%s</xliff:g> your default Phone app?"</string>
+ <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Set Default"</string>
+ <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancel"</string>
+ <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> will be able to place and control all aspects of calls. Only apps that you trust should be set as the default Phone app."</string>
+ <string name="blocked_numbers" msgid="2751843139572970579">"Blocked numbers"</string>
+ <string name="blocked_numbers_msg" msgid="1045015186124965643">"You won\'t receive calls or texts from blocked numbers."</string>
+ <string name="block_number" msgid="1101252256321306179">"Add a number"</string>
+ <string name="unblock_dialog_body" msgid="1614238499771862793">"Unblock <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+ <string name="unblock_button" msgid="3078048901972674170">"Unblock"</string>
+ <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Block calls and texts from"</string>
+ <string name="add_blocked_number_hint" msgid="6847675097085433553">"Phone number"</string>
+ <string name="block_button" msgid="8822290682524373357">"Block"</string>
+ <string name="non_primary_user" msgid="5180129233352533459">"Only the device owner can view and manage blocked numbers."</string>
+ <string name="delete_icon_description" msgid="8903995728252556724">"Unblock"</string>
+ <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Blocking temporarily off"</string>
+ <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"When you dial or text an emergency number, blocking is turned off to ensure that emergency services can contact you."</string>
+ <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"Re-enable now"</string>
+ <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> blocked"</string>
+ <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> unblocked"</string>
+ <string name="blocked_numbers_block_emergency_number_message" msgid="917851876780698387">"Unable to block emergency number."</string>
+ <string name="blocked_numbers_number_already_blocked_message" msgid="4392247814500811798">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> is already blocked."</string>
+ <string name="toast_personal_call_msg" msgid="5115361633476779723">"Using the personal dialler to make the call"</string>
+ <string name="notification_incoming_call" msgid="7713197997773986670">"<xliff:g id="CALL_VIA">%1$s</xliff:g> call from <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="notification_incoming_video_call" msgid="6638486071698373893">"<xliff:g id="CALL_VIA">%1$s</xliff:g> video call from <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="answering_ends_other_call" msgid="8282145910153766401">"Answering will end your <xliff:g id="CALL_VIA">%1$s</xliff:g> call"</string>
+ <string name="answering_ends_other_calls" msgid="1198589551399049197">"Answering will end your <xliff:g id="CALL_VIA">%1$s</xliff:g> calls"</string>
+ <string name="answering_ends_other_video_call" msgid="8510410917384186360">"Answering will end your <xliff:g id="CALL_VIA">%1$s</xliff:g> video call"</string>
+ <string name="answering_ends_other_managed_call" msgid="5186137550267947785">"Answering will end your ongoing call"</string>
+ <string name="answering_ends_other_managed_calls" msgid="6429838309560397988">"Answering will end your ongoing calls"</string>
+ <string name="answering_ends_other_managed_video_call" msgid="1585423762458248435">"Answering will end your ongoing video call"</string>
+ <string name="answer_incoming_call" msgid="4140530013111794587">"Answer"</string>
+ <string name="decline_incoming_call" msgid="806026168661598368">"Decline"</string>
+ <string name="cant_call_due_to_ongoing_call" msgid="4952615196237854748">"Call cannot be placed due to your <xliff:g id="OTHER_CALL">%1$s</xliff:g> call."</string>
+ <string name="cant_call_due_to_ongoing_calls" msgid="1380804892363503856">"Call cannot be placed due to your <xliff:g id="OTHER_CALL">%1$s</xliff:g> calls."</string>
+ <string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Call cannot be placed due to a call in another app."</string>
+ <string name="notification_channel_incoming_call" msgid="3513761697082968084">"Incoming calls"</string>
+ <string name="notification_channel_missed_call" msgid="8727062678632713146">"Missed calls"</string>
+ <string name="alert_outgoing_call" msgid="982908156825958001">"Placing this call will end your <xliff:g id="OTHER_APP">%1$s</xliff:g> call."</string>
+</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..26daa02
--- /dev/null
+++ b/res/values-en-rXC/strings.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="telecommAppLabel" product="default" msgid="382363169988504520">"Call Management"</string>
+ <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Phone"</string>
+ <string name="unknown" msgid="6878797917991465859">"Unknown"</string>
+ <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missed call"</string>
+ <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Missed work call"</string>
+ <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missed calls"</string>
+ <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missed calls"</string>
+ <string name="notification_missedCallTicker" msgid="504686252427747209">"Missed call from <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+ <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Call back"</string>
+ <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+ <string name="accessibility_call_muted" msgid="2776111226185342220">"Call muted."</string>
+ <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Speakerphone enabled."</string>
+ <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Can\'t talk now. What\'s up?"</string>
+ <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"I\'ll call you right back."</string>
+ <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"I\'ll call you later."</string>
+ <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Can\'t talk now. Call me later?"</string>
+ <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Quick responses"</string>
+ <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit quick responses"</string>
+ <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+ <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Quick response"</string>
+ <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message sent to <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+ <string name="enable_account_preference_title" msgid="2021848090086481720">"Calling accounts"</string>
+ <string name="outgoing_call_not_allowed_user_restriction" msgid="6872406278300131364">"Only emergency calls are allowed."</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"This application cannot make outgoing calls without the Phone permission."</string>
+ <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"To place a call, enter a valid number."</string>
+ <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Call cannot be added at this time."</string>
+ <string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
+ <string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
+ <string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
+ <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Make <xliff:g id="NEW_APP">%s</xliff:g> your default Phone app?"</string>
+ <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Set Default"</string>
+ <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancel"</string>
+ <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> will be able to place and control all aspects of calls. Only apps you trust should be set as the default Phone app."</string>
+ <string name="blocked_numbers" msgid="2751843139572970579">"Blocked numbers"</string>
+ <string name="blocked_numbers_msg" msgid="1045015186124965643">"You won\'t receive calls or texts from blocked numbers."</string>
+ <string name="block_number" msgid="1101252256321306179">"Add a number"</string>
+ <string name="unblock_dialog_body" msgid="1614238499771862793">"Unblock <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+ <string name="unblock_button" msgid="3078048901972674170">"Unblock"</string>
+ <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Block calls and texts from"</string>
+ <string name="add_blocked_number_hint" msgid="6847675097085433553">"Phone number"</string>
+ <string name="block_button" msgid="8822290682524373357">"Block"</string>
+ <string name="non_primary_user" msgid="5180129233352533459">"Only the device owner can view and manage blocked numbers."</string>
+ <string name="delete_icon_description" msgid="8903995728252556724">"Unblock"</string>
+ <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Blocking temporarily off"</string>
+ <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"After you dial or text an emergency number, blocking is turned off to ensure that emergency services can contact you."</string>
+ <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"Re-enable now"</string>
+ <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> blocked"</string>
+ <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> unblocked"</string>
+ <string name="blocked_numbers_block_emergency_number_message" msgid="917851876780698387">"Unable to block emergency number."</string>
+ <string name="blocked_numbers_number_already_blocked_message" msgid="4392247814500811798">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> is already blocked."</string>
+ <string name="toast_personal_call_msg" msgid="5115361633476779723">"Using the personal dialer to make the call"</string>
+ <string name="notification_incoming_call" msgid="7713197997773986670">"<xliff:g id="CALL_VIA">%1$s</xliff:g> call from <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="notification_incoming_video_call" msgid="6638486071698373893">"<xliff:g id="CALL_VIA">%1$s</xliff:g> video call from <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="answering_ends_other_call" msgid="8282145910153766401">"Answering will end your <xliff:g id="CALL_VIA">%1$s</xliff:g> call"</string>
+ <string name="answering_ends_other_calls" msgid="1198589551399049197">"Answering will end your <xliff:g id="CALL_VIA">%1$s</xliff:g> calls"</string>
+ <string name="answering_ends_other_video_call" msgid="8510410917384186360">"Answering will end your <xliff:g id="CALL_VIA">%1$s</xliff:g> video call"</string>
+ <string name="answering_ends_other_managed_call" msgid="5186137550267947785">"Answering will end your ongoing call"</string>
+ <string name="answering_ends_other_managed_calls" msgid="6429838309560397988">"Answering will end your ongoing calls"</string>
+ <string name="answering_ends_other_managed_video_call" msgid="1585423762458248435">"Answering will end your ongoing video call"</string>
+ <string name="answer_incoming_call" msgid="4140530013111794587">"Answer"</string>
+ <string name="decline_incoming_call" msgid="806026168661598368">"Decline"</string>
+ <string name="cant_call_due_to_ongoing_call" msgid="4952615196237854748">"Call cannot be placed due to your <xliff:g id="OTHER_CALL">%1$s</xliff:g> call."</string>
+ <string name="cant_call_due_to_ongoing_calls" msgid="1380804892363503856">"Call cannot be placed due to your <xliff:g id="OTHER_CALL">%1$s</xliff:g> calls."</string>
+ <string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Call cannot be placed due to a call in another app."</string>
+ <string name="notification_channel_incoming_call" msgid="3513761697082968084">"Incoming calls"</string>
+ <string name="notification_channel_missed_call" msgid="8727062678632713146">"Missed calls"</string>
+ <string name="alert_outgoing_call" msgid="982908156825958001">"Placing this call will end your <xliff:g id="OTHER_APP">%1$s</xliff:g> call."</string>
+</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index eb97fe5..529c845 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -19,7 +19,7 @@
<string name="telecommAppLabel" product="default" msgid="382363169988504520">"Deien kudeaketa"</string>
<string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefonoa"</string>
<string name="unknown" msgid="6878797917991465859">"Ezezaguna"</string>
- <string name="notification_missedCallTitle" msgid="7554385905572364535">"Galdutako deia"</string>
+ <string name="notification_missedCallTitle" msgid="7554385905572364535">"Dei galdua"</string>
<string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Laneko dei bat galdu duzu"</string>
<string name="notification_missedCallsTitle" msgid="1361677948941502522">"Dei galduak"</string>
<string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> dei galdu"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 7b50130..a7fcb0e 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -50,7 +50,7 @@
<string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"キャンセル"</string>
<string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> はすべての通話の発信や制御を行えるようになります。デフォルトの電話アプリに設定するのは信頼できるアプリだけにしてください。"</string>
<string name="blocked_numbers" msgid="2751843139572970579">"ブロックした番号"</string>
- <string name="blocked_numbers_msg" msgid="1045015186124965643">"ブロックした電話番号からの通話やテキスト メッセージを受け取ることはありません。"</string>
+ <string name="blocked_numbers_msg" msgid="1045015186124965643">"ブロックした電話番号から通話やテキスト メッセージを受け取ることはありません。"</string>
<string name="block_number" msgid="1101252256321306179">"番号を追加"</string>
<string name="unblock_dialog_body" msgid="1614238499771862793">"<xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g> のブロックを解除しますか?"</string>
<string name="unblock_button" msgid="3078048901972674170">"ブロックを解除"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index aafe222..9f2991a 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -40,7 +40,7 @@
<string name="enable_account_preference_title" msgid="2021848090086481720">"कॉल करण्याची खाती"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="6872406278300131364">"फक्त आणीबाणी कॉल करण्याची परवानगी आहे."</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"हा अॅप्लिकेशन फोन परवानगी शिवाय कॉल करू शकत नाही."</string>
- <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"कॉल करण्यासाठी, एक वैध नंबर प्रविष्ट करा."</string>
+ <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"कॉल करण्यासाठी, एक वैध नंबर एंटर करा."</string>
<string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"यावेळी कॉल जोडला जाऊ शकत नाही."</string>
<string name="no_vm_number" msgid="4164780423805688336">"व्हॉइसमेल नंबर गहाळ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्डवर कोणताही व्हॉइसमेल नंबर संचयित केला नाही."</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 7a8b28b..8f56cb2 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -52,18 +52,18 @@
<string name="blocked_numbers" msgid="2751843139572970579">"Mga naka-block na numero"</string>
<string name="blocked_numbers_msg" msgid="1045015186124965643">"Hindi ka makakatanggap ng mga tawag o mga text mula sa mga naka-block na numero."</string>
<string name="block_number" msgid="1101252256321306179">"Magdagdag ng numero"</string>
- <string name="unblock_dialog_body" msgid="1614238499771862793">"Aalisin ba sa pagkaka-block ang <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
- <string name="unblock_button" msgid="3078048901972674170">"Alisin sa pagkaka-block"</string>
+ <string name="unblock_dialog_body" msgid="1614238499771862793">"Ia-unblock ba ang <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+ <string name="unblock_button" msgid="3078048901972674170">"I-unblock"</string>
<string name="add_blocked_dialog_body" msgid="9030243212265516828">"I-block ang mga tawag at text mula sa"</string>
<string name="add_blocked_number_hint" msgid="6847675097085433553">"Numero ng telepono"</string>
<string name="block_button" msgid="8822290682524373357">"I-block"</string>
<string name="non_primary_user" msgid="5180129233352533459">"Ang may-ari ng device lang ang makakakita at makakapamahala sa mga naka-block na numero."</string>
- <string name="delete_icon_description" msgid="8903995728252556724">"Inaalis sa pagkaka-block"</string>
+ <string name="delete_icon_description" msgid="8903995728252556724">"Na-unblock"</string>
<string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Pansamantalang naka-off ang pag-block"</string>
<string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"Pagkatapos mong i-dial o i-text ang isang pang-emergency na numero, ino-off ang pag-block upang matiyak na maaaring makipag-ugnayan sa iyo ang mga serbisyong pang-emergency."</string>
<string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"I-enable muli ngayon"</string>
<string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"Naka-block ang <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g>"</string>
- <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"Naka-unblock ang <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g>"</string>
+ <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"Na-unblock ang <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g>"</string>
<string name="blocked_numbers_block_emergency_number_message" msgid="917851876780698387">"Hindi ma-block ang numerong pang-emergency."</string>
<string name="blocked_numbers_number_already_blocked_message" msgid="4392247814500811798">"Naka-block na ang <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g>."</string>
<string name="toast_personal_call_msg" msgid="5115361633476779723">"Ginagamit ang personal na dialer upang tumawag"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 5c043ea..8a9ca00 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -32,8 +32,8 @@
<string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"我待會就回電。"</string>
<string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"我晚點回電。"</string>
<string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"我現在不方便講話,晚點再打來好嗎?"</string>
- <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"快速回應"</string>
- <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"編輯快速回應"</string>
+ <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"應答短訊"</string>
+ <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"編輯應答短訊"</string>
<string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"快速回應"</string>
<string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"訊息已傳送至 <xliff:g id="PHONE_NUMBER">%s</xliff:g>。"</string>
diff --git a/res/xml/layout_blocked_number.xml b/res/xml/layout_blocked_number.xml
index 94cdbae..fbd7de3 100644
--- a/res/xml/layout_blocked_number.xml
+++ b/res/xml/layout_blocked_number.xml
@@ -28,8 +28,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:layout_toStartOf="@+id/delete_blocked_number"
- android:paddingTop="@dimen/blocked_numbers_delete_icon_padding" />
+ android:paddingTop="@dimen/blocked_numbers_delete_icon_padding"
+ android:textDirection="ltr" />
<ImageView
android:id="@+id/delete_blocked_number"
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 9ab5290..90c1fe8 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -27,6 +27,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.Trace;
import android.provider.ContactsContract.Contacts;
import android.telecom.CallAudioState;
@@ -242,17 +243,38 @@
private String mViaNumber = "";
/**
- * The time this call was created. Beyond logging and such, may also be used for bookkeeping
- * and specifically for marking certain call attempts as failed attempts.
+ * The wall clock time this call was created. Beyond logging and such, may also be used for
+ * bookkeeping and specifically for marking certain call attempts as failed attempts.
+ * Note: This timestamp should NOT be used for calculating call duration.
*/
- private long mCreationTimeMillis = System.currentTimeMillis();
+ private long mCreationTimeMillis;
/** The time this call was made active. */
private long mConnectTimeMillis = 0;
- /** The time this call was disconnected. */
+ /**
+ * The time, in millis, since boot when this call was connected. This should ONLY be used when
+ * calculating the duration of the call.
+ *
+ * The reason for this is that the {@link SystemClock#elapsedRealtime()} is based on the
+ * elapsed time since the device was booted. Changes to the system clock (e.g. due to NITZ
+ * time sync, time zone changes user initiated clock changes) would cause a duration calculated
+ * based on {@link #mConnectTimeMillis} to change based on the delta in the time.
+ * Using the {@link SystemClock#elapsedRealtime()} ensures that changes to the wall clock do
+ * not impact the call duration.
+ */
+ private long mConnectElapsedTimeMillis = 0;
+
+ /** The wall clock time this call was disconnected. */
private long mDisconnectTimeMillis = 0;
+ /**
+ * The elapsed time since boot when this call was disconnected. Recorded as the
+ * {@link SystemClock#elapsedRealtime()}. This ensures that the call duration is not impacted
+ * by changes in the wall time clock.
+ */
+ private long mDisconnectElapsedTimeMillis = 0;
+
/** The gateway information associated with this call. This stores the original call handle
* that the user is attempting to connect to via the gateway, the actual handle to dial in
* order to connect the call via the gateway, as well as the package name of the gateway
@@ -376,6 +398,7 @@
private final ConnectionServiceRepository mRepository;
private final Context mContext;
private final CallsManager mCallsManager;
+ private final ClockProxy mClockProxy;
private final TelecomSystem.SyncRoot mLock;
private final String mId;
private String mConnectionId;
@@ -471,20 +494,19 @@
/**
* Persists the specified parameters and initializes the new instance.
- *
- * @param context The context.
+ * @param context The context.
* @param repository The connection service repository.
* @param handle The handle to dial.
* @param gatewayInfo Gateway information to use for the call.
* @param connectionManagerPhoneAccountHandle Account to use for the service managing the call.
- * This account must be one that was registered with the
- * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} flag.
+* This account must be one that was registered with the
+* {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} flag.
* @param targetPhoneAccountHandle Account information to use for the call. This account must be
- * one that was registered with the {@link PhoneAccount#CAPABILITY_CALL_PROVIDER} flag.
+* one that was registered with the {@link PhoneAccount#CAPABILITY_CALL_PROVIDER} flag.
* @param callDirection one of CALL_DIRECTION_INCOMING, CALL_DIRECTION_OUTGOING,
- * or CALL_DIRECTION_UNKNOWN.
+* or CALL_DIRECTION_UNKNOWN.
* @param shouldAttachToExistingConnection Set to true to attach the call to an existing
- * connection, regardless of whether it's incoming or outgoing.
+ * @param clockProxy
*/
public Call(
String callId,
@@ -501,7 +523,8 @@
PhoneAccountHandle targetPhoneAccountHandle,
int callDirection,
boolean shouldAttachToExistingConnection,
- boolean isConference) {
+ boolean isConference,
+ ClockProxy clockProxy) {
mId = callId;
mConnectionId = callId;
mState = isConference ? CallState.ACTIVE : CallState.NEW;
@@ -522,26 +545,27 @@
|| callDirection == CALL_DIRECTION_INCOMING;
maybeLoadCannedSmsResponses();
mAnalytics = new Analytics.CallInfo();
-
+ mClockProxy = clockProxy;
+ mCreationTimeMillis = mClockProxy.currentTimeMillis();
}
/**
* Persists the specified parameters and initializes the new instance.
- *
- * @param context The context.
+ * @param context The context.
* @param repository The connection service repository.
* @param handle The handle to dial.
* @param gatewayInfo Gateway information to use for the call.
* @param connectionManagerPhoneAccountHandle Account to use for the service managing the call.
- * This account must be one that was registered with the
- * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} flag.
+* This account must be one that was registered with the
+* {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} flag.
* @param targetPhoneAccountHandle Account information to use for the call. This account must be
- * one that was registered with the {@link PhoneAccount#CAPABILITY_CALL_PROVIDER} flag.
+* one that was registered with the {@link PhoneAccount#CAPABILITY_CALL_PROVIDER} flag.
* @param callDirection one of CALL_DIRECTION_INCOMING, CALL_DIRECTION_OUTGOING,
- * or CALL_DIRECTION_UNKNOWN
+* or CALL_DIRECTION_UNKNOWN
* @param shouldAttachToExistingConnection Set to true to attach the call to an existing
- * connection, regardless of whether it's incoming or outgoing.
+* connection, regardless of whether it's incoming or outgoing.
* @param connectTimeMillis The connection time of the call.
+ * @param clockProxy
*/
Call(
String callId,
@@ -559,13 +583,16 @@
int callDirection,
boolean shouldAttachToExistingConnection,
boolean isConference,
- long connectTimeMillis) {
+ long connectTimeMillis,
+ long connectElapsedTimeMillis,
+ ClockProxy clockProxy) {
this(callId, context, callsManager, lock, repository, contactsAsyncHelper,
callerInfoAsyncQueryFactory, phoneNumberUtilsAdapter, handle, gatewayInfo,
connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection,
- shouldAttachToExistingConnection, isConference);
+ shouldAttachToExistingConnection, isConference, clockProxy);
mConnectTimeMillis = connectTimeMillis;
+ mConnectElapsedTimeMillis = connectElapsedTimeMillis;
mAnalytics.setCallStartTime(connectTimeMillis);
}
@@ -790,14 +817,17 @@
// We check to see if mConnectTime is already set to prevent the
// call from resetting active time when it goes in and out of
// ACTIVE/ON_HOLD
- mConnectTimeMillis = System.currentTimeMillis();
+ mConnectTimeMillis = mClockProxy.currentTimeMillis();
+ mConnectElapsedTimeMillis = mClockProxy.elapsedRealtime();
mAnalytics.setCallStartTime(mConnectTimeMillis);
}
// We're clearly not disconnected, so reset the disconnected time.
mDisconnectTimeMillis = 0;
+ mDisconnectElapsedTimeMillis = 0;
} else if (mState == CallState.DISCONNECTED) {
- mDisconnectTimeMillis = System.currentTimeMillis();
+ mDisconnectTimeMillis = mClockProxy.currentTimeMillis();
+ mDisconnectElapsedTimeMillis = mClockProxy.elapsedRealtime();
mAnalytics.setCallEndTime(mDisconnectTimeMillis);
setLocallyDisconnecting(false);
fixParentAfterDisconnect();
@@ -1200,9 +1230,11 @@
}
/**
+ * Note: This method relies on {@link #mConnectElapsedTimeMillis} and
+ * {@link #mDisconnectElapsedTimeMillis} which are independent of the wall clock (which could
+ * change due to clock changes).
* @return The "age" of this call object in milliseconds, which typically also represents the
- * period since this call was added to the set pending outgoing calls, see
- * mCreationTimeMillis.
+ * period since this call was added to the set pending outgoing calls.
*/
@VisibleForTesting
public long getAgeMillis() {
@@ -1211,16 +1243,16 @@
mDisconnectCause.getCode() == DisconnectCause.MISSED)) {
// Rejected and missed calls have no age. They're immortal!!
return 0;
- } else if (mConnectTimeMillis == 0) {
+ } else if (mConnectElapsedTimeMillis == 0) {
// Age is measured in the amount of time the call was active. A zero connect time
// indicates that we never went active, so return 0 for the age.
return 0;
- } else if (mDisconnectTimeMillis == 0) {
+ } else if (mDisconnectElapsedTimeMillis == 0) {
// We connected, but have not yet disconnected
- return System.currentTimeMillis() - mConnectTimeMillis;
+ return mClockProxy.elapsedRealtime() - mConnectElapsedTimeMillis;
}
- return mDisconnectTimeMillis - mConnectTimeMillis;
+ return mDisconnectElapsedTimeMillis - mConnectElapsedTimeMillis;
}
/**
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 5f56fcf..705d5a8 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -408,7 +408,8 @@
return;
case CallAudioState.ROUTE_WIRED_OR_EARPIECE:
mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
- CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE);
+ CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE,
+ CallAudioRouteStateMachine.NO_INCLUDE_BLUETOOTH_IN_BASELINE);
return;
default:
Log.wtf(this, "Invalid route specified: %d", route);
@@ -432,7 +433,9 @@
@VisibleForTesting
public void startCallWaiting() {
- mRinger.startCallWaiting(mRingingCalls.iterator().next());
+ if (mRingingCalls.size() == 1) {
+ mRinger.startCallWaiting(mRingingCalls.iterator().next());
+ }
}
@VisibleForTesting
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index df912ed..b5c7e7a 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -270,9 +270,10 @@
// This happens when an IMS call is answered by the in-call UI. Special case
// that we have to deal with for some reason.
- // VOIP calls should never invoke this mechanism, so transition directly to
- // the sim call focus state.
- transitionTo(mSimCallFocusState);
+ // The IMS audio routing may be via modem or via RTP stream. In case via RTP
+ // stream, the state machine should transit to mVoipCallFocusState.
+ transitionTo(args.foregroundCallIsVoip
+ ? mVoipCallFocusState : mSimCallFocusState);
return HANDLED;
default:
// The forced focus switch commands are handled by BaseState.
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 8ab0bf8..d96ed1c 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -32,6 +32,7 @@
import android.telecom.Logging.Session;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IState;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.State;
@@ -115,7 +116,12 @@
public static final int ACTIVE_FOCUS = 2;
public static final int RINGING_FOCUS = 3;
- private static final SparseArray<String> AUDIO_ROUTE_TO_LOG_EVENT = new SparseArray<String>() {{
+ /** Valid values for the argument for SWITCH_BASELINE_ROUTE */
+ public static final int NO_INCLUDE_BLUETOOTH_IN_BASELINE = 0;
+ public static final int INCLUDE_BLUETOOTH_IN_BASELINE = 1;
+
+ @VisibleForTesting
+ public static final SparseArray<String> AUDIO_ROUTE_TO_LOG_EVENT = new SparseArray<String>() {{
put(CallAudioState.ROUTE_BLUETOOTH, LogUtils.Events.AUDIO_ROUTE_BT);
put(CallAudioState.ROUTE_EARPIECE, LogUtils.Events.AUDIO_ROUTE_EARPIECE);
put(CallAudioState.ROUTE_SPEAKER, LogUtils.Events.AUDIO_ROUTE_SPEAKER);
@@ -186,6 +192,10 @@
super.enter();
Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
"Entering state " + getName());
+ if (isActive()) {
+ Log.addEvent(mCallsManager.getForegroundCall(),
+ AUDIO_ROUTE_TO_LOG_EVENT.get(getRouteCode(), LogUtils.Events.AUDIO_ROUTE));
+ }
}
@Override
@@ -226,10 +236,12 @@
removedRoutes |= ROUTE_BLUETOOTH;
break;
case SWITCH_BASELINE_ROUTE:
- sendInternalMessage(calculateBaselineRouteMessage(false));
+ sendInternalMessage(calculateBaselineRouteMessage(false,
+ msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
return HANDLED;
case USER_SWITCH_BASELINE_ROUTE:
- sendInternalMessage(calculateBaselineRouteMessage(true));
+ sendInternalMessage(calculateBaselineRouteMessage(true,
+ msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
return HANDLED;
case SWITCH_FOCUS:
mAudioFocusType = msg.arg1;
@@ -250,6 +262,7 @@
// Behavior will depend on whether the state is an active one or a quiescent one.
abstract public void updateSystemAudioState();
abstract public boolean isActive();
+ abstract public int getRouteCode();
}
class ActiveEarpieceRoute extends EarpieceRoute {
@@ -388,6 +401,11 @@
abstract class EarpieceRoute extends AudioState {
@Override
+ public int getRouteCode() {
+ return CallAudioState.ROUTE_EARPIECE;
+ }
+
+ @Override
public boolean processMessage(Message msg) {
if (super.processMessage(msg) == HANDLED) {
return HANDLED;
@@ -566,6 +584,11 @@
abstract class HeadsetRoute extends AudioState {
@Override
+ public int getRouteCode() {
+ return CallAudioState.ROUTE_WIRED_HEADSET;
+ }
+
+ @Override
public boolean processMessage(Message msg) {
if (super.processMessage(msg) == HANDLED) {
return HANDLED;
@@ -594,7 +617,7 @@
if (mWasOnSpeaker) {
sendInternalMessage(SWITCH_SPEAKER);
} else {
- sendInternalMessage(SWITCH_BASELINE_ROUTE);
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
}
return HANDLED;
case BT_AUDIO_DISCONNECT:
@@ -684,7 +707,7 @@
}
return HANDLED;
case BT_AUDIO_DISCONNECT:
- sendInternalMessage(SWITCH_BASELINE_ROUTE);
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
return HANDLED;
default:
return NOT_HANDLED;
@@ -765,7 +788,7 @@
return HANDLED;
case BT_AUDIO_DISCONNECT:
// BT SCO might be connected when in-band ringing is enabled
- sendInternalMessage(SWITCH_BASELINE_ROUTE);
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
return HANDLED;
default:
return NOT_HANDLED;
@@ -846,6 +869,11 @@
abstract class BluetoothRoute extends AudioState {
@Override
+ public int getRouteCode() {
+ return CallAudioState.ROUTE_BLUETOOTH;
+ }
+
+ @Override
public boolean processMessage(Message msg) {
if (super.processMessage(msg) == HANDLED) {
return HANDLED;
@@ -860,7 +888,7 @@
// in the bluetooth route.
return HANDLED;
case DISCONNECT_BLUETOOTH:
- sendInternalMessage(SWITCH_BASELINE_ROUTE);
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
mWasOnSpeaker = false;
return HANDLED;
case DISCONNECT_WIRED_HEADSET:
@@ -1032,6 +1060,11 @@
abstract class SpeakerRoute extends AudioState {
@Override
+ public int getRouteCode() {
+ return CallAudioState.ROUTE_SPEAKER;
+ }
+
+ @Override
public boolean processMessage(Message msg) {
if (super.processMessage(msg) == HANDLED) {
return HANDLED;
@@ -1064,7 +1097,7 @@
// Nothing to do here
return HANDLED;
case DISCONNECT_DOCK:
- sendInternalMessage(SWITCH_BASELINE_ROUTE);
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
return HANDLED;
default:
return NOT_HANDLED;
@@ -1260,11 +1293,9 @@
}
private void setSpeakerphoneOn(boolean on) {
- if (mAudioManager.isSpeakerphoneOn() != on) {
- Log.i(this, "turning speaker phone %s", on);
- mAudioManager.setSpeakerphoneOn(on);
- mStatusBarNotifier.notifySpeakerphone(on);
- }
+ Log.i(this, "turning speaker phone %s", on);
+ mAudioManager.setSpeakerphoneOn(on);
+ mStatusBarNotifier.notifySpeakerphone(on);
}
private void setBluetoothOn(boolean on) {
@@ -1338,11 +1369,6 @@
Log.i(this, "setSystemAudioState: changing from %s to %s", mLastKnownCallAudioState,
newCallAudioState);
if (force || !newCallAudioState.equals(mLastKnownCallAudioState)) {
- if (newCallAudioState.getRoute() != mLastKnownCallAudioState.getRoute()) {
- Log.addEvent(mCallsManager.getForegroundCall(),
- AUDIO_ROUTE_TO_LOG_EVENT.get(newCallAudioState.getRoute(),
- LogUtils.Events.AUDIO_ROUTE));
- }
mCallsManager.onCallAudioStateChanged(mLastKnownCallAudioState, newCallAudioState);
updateAudioForForegroundCall(newCallAudioState);
@@ -1375,6 +1401,10 @@
}
private void sendInternalMessage(int messageCode) {
+ sendInternalMessage(messageCode, 0);
+ }
+
+ private void sendInternalMessage(int messageCode, int arg1) {
// Internal messages are messages which the state machine sends to itself in the
// course of processing externally-sourced messages. We want to send these messages at
// the front of the queue in order to make actions appear atomic to the user and to
@@ -1389,9 +1419,9 @@
// 7. State machine handler processes SWITCH_HEADSET.
Session subsession = Log.createSubsession();
if(subsession != null) {
- sendMessageAtFrontOfQueue(messageCode, subsession);
+ sendMessageAtFrontOfQueue(messageCode, arg1, 0, subsession);
} else {
- sendMessageAtFrontOfQueue(messageCode);
+ sendMessageAtFrontOfQueue(messageCode, arg1);
}
}
@@ -1444,7 +1474,8 @@
return true;
}
- private int calculateBaselineRouteMessage(boolean isExplicitUserRequest) {
+ private int calculateBaselineRouteMessage(boolean isExplicitUserRequest,
+ boolean includeBluetooth) {
boolean isSkipEarpiece = false;
if (!isExplicitUserRequest) {
synchronized (mLock) {
@@ -1453,7 +1484,11 @@
isSkipEarpiece = mCallsManager.hasVideoCall();
}
}
- if ((mAvailableRoutes & ROUTE_EARPIECE) != 0 && !isSkipEarpiece) {
+ if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0
+ && !mHasUserExplicitlyLeftBluetooth
+ && includeBluetooth) {
+ return isExplicitUserRequest ? USER_SWITCH_BLUETOOTH : SWITCH_BLUETOOTH;
+ } else if ((mAvailableRoutes & ROUTE_EARPIECE) != 0 && !isSkipEarpiece) {
return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE;
} else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
return isExplicitUserRequest ? USER_SWITCH_HEADSET : SWITCH_HEADSET;
@@ -1467,6 +1502,7 @@
mDeviceSupportedRoutes = initState.getSupportedRouteMask();
mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes();
mIsMuted = initState.isMuted();
+ setSpeakerphoneOn(initState.getRoute() == CallAudioState.ROUTE_SPEAKER);
setMuteOn(mIsMuted);
mWasOnSpeaker = false;
mHasUserExplicitlyLeftBluetooth = false;
@@ -1481,7 +1517,7 @@
// Move to baseline route in the case the current route is no longer available.
if ((mAvailableRoutes & currentState.getRoute()) == 0) {
- sendInternalMessage(calculateBaselineRouteMessage(false));
+ sendInternalMessage(calculateBaselineRouteMessage(false, true));
}
}
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index ba03e5c..01b0de8 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -27,6 +27,7 @@
import android.os.UserHandle;
import android.os.PersistableBundle;
import android.provider.CallLog.Calls;
+import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.Log;
import android.telecom.PhoneAccount;
@@ -226,7 +227,9 @@
call.getCallDataUsage();
int callFeatures = getCallFeatures(call.getVideoStateHistory(),
- call.getDisconnectCause().getCode() == DisconnectCause.CALL_PULLED);
+ call.getDisconnectCause().getCode() == DisconnectCause.CALL_PULLED,
+ (call.getConnectionProperties() & Connection.PROPERTY_ASSISTED_DIALING_USED) ==
+ Connection.PROPERTY_ASSISTED_DIALING_USED);
logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
creationTime, age, callDataUsage, call.isEmergencyCall(), call.getInitiatingUser(),
@@ -303,7 +306,8 @@
* @param isPulledCall {@code true} if this call was pulled to another device.
* @return The call features.
*/
- private static int getCallFeatures(int videoState, boolean isPulledCall) {
+ private static int getCallFeatures(int videoState, boolean isPulledCall,
+ boolean isUsingAssistedDialing) {
int features = 0;
if (VideoProfile.isVideo(videoState)) {
features |= Calls.FEATURES_VIDEO;
@@ -311,6 +315,9 @@
if (isPulledCall) {
features |= Calls.FEATURES_PULLED_EXTERNALLY;
}
+ if (isUsingAssistedDialing) {
+ features |= Calls.FEATURES_ASSISTED_DIALING_USED;
+ }
return features;
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 115280a..3e8e3d0 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -257,6 +257,7 @@
private final DefaultDialerCache mDefaultDialerCache;
private final Timeouts.Adapter mTimeoutsAdapter;
private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
+ private final ClockProxy mClockProxy;
private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
/* Handler tied to thread in which CallManager was initialized. */
@@ -306,7 +307,8 @@
AsyncRingtonePlayer asyncRingtonePlayer,
PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
EmergencyCallHelper emergencyCallHelper,
- InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory) {
+ InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory,
+ ClockProxy clockProxy) {
mContext = context;
mLock = lock;
mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
@@ -370,6 +372,7 @@
mConnectionServiceRepository =
new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this);
mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this);
+ mClockProxy = clockProxy;
mListeners.add(mInCallWakeLockController);
mListeners.add(statusBarNotifier);
@@ -833,8 +836,8 @@
phoneAccountHandle,
Call.CALL_DIRECTION_INCOMING /* callDirection */,
false /* forceAttachToExistingConnection */,
- false /* isConference */
- );
+ false, /* isConference */
+ mClockProxy);
// Ensure new calls related to self-managed calls/connections are set as such. This will
// be overridden when the actual connection is returned in startCreateConnection, however
@@ -967,8 +970,8 @@
// Use onCreateIncomingConnection in TelephonyConnectionService, so that we attach
// to the existing connection instead of trying to create a new one.
true /* forceAttachToExistingConnection */,
- false /* isConference */
- );
+ false, /* isConference */
+ mClockProxy);
call.initAnalytics();
setIntentExtrasAndStartTime(call, extras);
@@ -1047,8 +1050,8 @@
null /* phoneAccountHandle */,
Call.CALL_DIRECTION_OUTGOING /* callDirection */,
false /* forceAttachToExistingConnection */,
- false /* isConference */
- );
+ false, /* isConference */
+ mClockProxy);
call.initAnalytics();
// Ensure new calls related to self-managed calls/connections are set as such. This
@@ -1812,10 +1815,12 @@
*/
void handleConnectionServiceDeath(ConnectionServiceWrapper service) {
if (service != null) {
+ Log.i(this, "handleConnectionServiceDeath: service %s died", service);
for (Call call : mCalls) {
if (call.getConnectionService() == service) {
if (call.getState() != CallState.DISCONNECTED) {
- markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR));
+ markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
+ "CS_DEATH"));
}
markCallAsRemoved(call);
}
@@ -2021,6 +2026,10 @@
parcelableConference.getConnectTimeMillis() ==
Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
parcelableConference.getConnectTimeMillis();
+ long connectElapsedTime =
+ parcelableConference.getConnectElapsedTimeMillis() ==
+ Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
+ parcelableConference.getConnectElapsedTimeMillis();
Call call = new Call(
callId,
@@ -2038,7 +2047,9 @@
Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
false /* forceAttachToExistingConnection */,
true /* isConference */,
- connectTime);
+ connectTime,
+ connectElapsedTime,
+ mClockProxy);
setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()),
"new conference call");
@@ -2287,6 +2298,12 @@
handoverTo.sendCallEvent(android.telecom.Call.EVENT_HANDOVER_COMPLETE, null);
answerCall(handoverTo, handoverTo.getVideoState());
call.markFinishedHandoverStateAndCleanup(HandoverState.HANDOVER_COMPLETE);
+
+ // If the call we handed over to is self-managed, we need to disconnect the calls for other
+ // ConnectionServices.
+ if (handoverTo.isSelfManaged()) {
+ disconnectOtherCalls(handoverTo.getTargetPhoneAccount());
+ }
}
private void rejectHandoverTo(Call handoverTo) {
@@ -2325,6 +2342,11 @@
// Disconnect the call we handed over from.
disconnectCall(handoverFrom);
+ // If we handed over to a self-managed ConnectionService, we need to disconnect calls for
+ // other ConnectionServices.
+ if (handoverTo.isSelfManaged()) {
+ disconnectOtherCalls(handoverTo.getTargetPhoneAccount());
+ }
}
private void updateCanAddCall() {
@@ -2694,7 +2716,9 @@
Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
false /* forceAttachToExistingConnection */,
isDowngradedConference /* isConference */,
- connection.getConnectTimeMillis() /* connectTimeMillis */);
+ connection.getConnectTimeMillis() /* connectTimeMillis */,
+ connection.getConnectElapsedTimeMillis(), /* connectElapsedTimeMillis */
+ mClockProxy);
call.initAnalytics();
call.getAnalytics().setCreatedFromExistingConnection(true);
@@ -2869,10 +2893,10 @@
// Only permit outgoing calls if there is no ongoing emergency calls and all other calls
// are associated with the current PhoneAccountHandle.
return !hasEmergencyCall() && (
- excludeCall.getHandoverSourceCall() != null ||
- (!hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle) &&
- !hasCallsForOtherPhoneAccount(phoneAccountHandle) &&
- !hasManagedCalls()));
+ (excludeCall != null && excludeCall.getHandoverSourceCall() != null) || (
+ !hasMaximumSelfManagedCalls(excludeCall, phoneAccountHandle)
+ && !hasCallsForOtherPhoneAccount(phoneAccountHandle)
+ && !hasManagedCalls()));
}
}
diff --git a/src/com/android/server/telecom/ClockProxy.java b/src/com/android/server/telecom/ClockProxy.java
new file mode 100644
index 0000000..6f92f94
--- /dev/null
+++ b/src/com/android/server/telecom/ClockProxy.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.server.telecom;
+
+import android.os.SystemClock;
+
+/**
+ * Defines common clock functionality used in Telecom. Provided to make unit testing of clock
+ * operations testable.
+ */
+public interface ClockProxy {
+ /**
+ * Returns the current wall-clock time of the system, as typically returned by
+ * {@link System#currentTimeMillis()}.
+ * @return The current wall-clock time.
+ */
+ long currentTimeMillis();
+
+ /**
+ * Returns the elapsed time since boot of the system, as typically returned by
+ * {@link SystemClock#elapsedRealtime()}.
+ * @return the current elapsed real time.
+ */
+ long elapsedRealtime();
+}
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 8f54cec..845cd37 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -1375,7 +1375,7 @@
mPendingResponses.clear();
for (int i = 0; i < responses.length; i++) {
responses[i].handleCreateConnectionFailure(
- new DisconnectCause(DisconnectCause.ERROR));
+ new DisconnectCause(DisconnectCause.ERROR, "CS_DEATH"));
}
}
mCallIdMapper.clear();
diff --git a/src/com/android/server/telecom/DtmfLocalTonePlayer.java b/src/com/android/server/telecom/DtmfLocalTonePlayer.java
index 10551a4..304a698 100644
--- a/src/com/android/server/telecom/DtmfLocalTonePlayer.java
+++ b/src/com/android/server/telecom/DtmfLocalTonePlayer.java
@@ -28,7 +28,6 @@
import android.telecom.Logging.Session;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
// TODO: Needed for move to system service: import com.android.internal.R;
@@ -86,37 +85,41 @@
@Override
public void handleMessage(Message msg) {
- if (msg.obj instanceof Session) {
- Log.continueSession((Session) msg.obj, "DLTP.TH");
- }
+ try {
+ if (msg.obj instanceof Session) {
+ Log.continueSession((Session) msg.obj, "DLTP.TH");
+ }
- switch(msg.what) {
- case EVENT_START_SESSION:
- mToneGeneratorProxy.create();
- break;
- case EVENT_END_SESSION:
- mToneGeneratorProxy.release();
- break;
- case EVENT_PLAY_TONE:
- char c = (char) msg.arg1;
- if (!mToneGeneratorProxy.isPresent()) {
- Log.d(this, "playTone: no tone generator, %c.", c);
- } else {
- Log.d(this, "starting local tone: %c.", c);
- int tone = getMappedTone(c);
- if (tone != ToneGenerator.TONE_UNKNOWN) {
- mToneGeneratorProxy.startTone(tone, -1 /* toneDuration */);
+ switch (msg.what) {
+ case EVENT_START_SESSION:
+ mToneGeneratorProxy.create();
+ break;
+ case EVENT_END_SESSION:
+ mToneGeneratorProxy.release();
+ break;
+ case EVENT_PLAY_TONE:
+ char c = (char) msg.arg1;
+ if (!mToneGeneratorProxy.isPresent()) {
+ Log.d(this, "playTone: no tone generator, %c.", c);
+ } else {
+ Log.d(this, "starting local tone: %c.", c);
+ int tone = getMappedTone(c);
+ if (tone != ToneGenerator.TONE_UNKNOWN) {
+ mToneGeneratorProxy.startTone(tone, -1 /* toneDuration */);
+ }
}
- }
- break;
- case EVENT_STOP_TONE:
- if (mToneGeneratorProxy.isPresent()) {
- mToneGeneratorProxy.stopTone();
- }
- break;
- default:
- Log.w(this, "Unknown message: %d", msg.what);
- break;
+ break;
+ case EVENT_STOP_TONE:
+ if (mToneGeneratorProxy.isPresent()) {
+ mToneGeneratorProxy.stopTone();
+ }
+ break;
+ default:
+ Log.w(this, "Unknown message: %d", msg.what);
+ break;
+ }
+ } finally {
+ Log.endSession();
}
}
}
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index fde2910..58f489c 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -287,7 +287,7 @@
}
protected void onDisconnected() {
- InCallController.this.onDisconnected(mInCallServiceInfo.getComponentName());
+ InCallController.this.onDisconnected(mInCallServiceInfo);
disconnect(); // Unbind explicitly if we get disconnected.
if (mListener != null) {
mListener.onDisconnect(InCallServiceBindingConnection.this);
@@ -756,6 +756,10 @@
// We are bound, and we are connected.
adjustServiceBindingsForEmergency();
+ // This is in case an emergency call is added while there is an existing call.
+ mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(call,
+ mCallsManager.getCurrentUserHandle());
+
Log.i(this, "onCallAdded: %s", call);
// Track the call if we don't already know about it.
addCall(call);
@@ -807,6 +811,8 @@
// Check again to make sure there are no active calls.
if (mCallsManager.getCalls().isEmpty()) {
unbindFromServices();
+
+ mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
}
}
}.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
@@ -1026,6 +1032,7 @@
mNonUIInCallServiceConnections.disconnect();
mNonUIInCallServiceConnections = null;
}
+ mInCallServices.clear();
}
/**
@@ -1319,12 +1326,12 @@
/**
* Cleans up an instance of in-call app after the service has been unbound.
*
- * @param disconnectedComponent The {@link ComponentName} of the service which disconnected.
+ * @param disconnectedInfo The {@link InCallServiceInfo} of the service which disconnected.
*/
- private void onDisconnected(ComponentName disconnectedComponent) {
- Log.i(this, "onDisconnected from %s", disconnectedComponent);
+ private void onDisconnected(InCallServiceInfo disconnectedInfo) {
+ Log.i(this, "onDisconnected from %s", disconnectedInfo.getComponentName());
- mInCallServices.remove(disconnectedComponent);
+ mInCallServices.remove(disconnectedInfo);
}
/**
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index 74ee668..c592fcd 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -30,6 +30,7 @@
import android.telecom.GatewayInfo;
import android.telecom.Log;
import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.DisconnectCause;
@@ -269,6 +270,21 @@
return DisconnectCause.INVALID_NUMBER;
}
+ // True for all managed calls, false for self-managed calls.
+ boolean sendNewOutgoingCallBroadcast = true;
+ PhoneAccountHandle targetPhoneAccount = mIntent.getParcelableExtra(
+ TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+ if (targetPhoneAccount != null) {
+ PhoneAccount phoneAccount =
+ mCallsManager.getPhoneAccountRegistrar().getPhoneAccountUnchecked(
+ targetPhoneAccount);
+ if (phoneAccount != null && phoneAccount.isSelfManaged()) {
+ callImmediately = true;
+ sendNewOutgoingCallBroadcast = false;
+ Log.i(this, "Skipping NewOutgoingCallBroadcast for self-managed call.");
+ }
+ }
+
if (callImmediately) {
Log.i(this, "Placing call immediately instead of waiting for "
+ " OutgoingCallBroadcastReceiver: %s", intent);
@@ -287,9 +303,11 @@
// initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.
}
- UserHandle targetUser = mCall.getInitiatingUser();
- Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
- broadcastIntent(intent, number, !callImmediately, targetUser);
+ if (sendNewOutgoingCallBroadcast) {
+ UserHandle targetUser = mCall.getInitiatingUser();
+ Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
+ broadcastIntent(intent, number, !callImmediately, targetUser);
+ }
return DisconnectCause.NOT_DISCONNECTED;
}
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 07be216..527e8e6 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -336,7 +336,10 @@
android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
Connection.PROPERTY_SELF_MANAGED,
- android.telecom.Call.Details.PROPERTY_SELF_MANAGED
+ android.telecom.Call.Details.PROPERTY_SELF_MANAGED,
+
+ Connection.PROPERTY_ASSISTED_DIALING_USED,
+ android.telecom.Call.Details.PROPERTY_ASSISTED_DIALING_USED
};
private static int convertConnectionToCallProperties(int connectionProperties) {
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index 5a1ae02..47ba295 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.telecom.Log;
import android.text.TextUtils;
@@ -104,6 +105,29 @@
}
}
+ private class ServiceDeathRecipient implements IBinder.DeathRecipient {
+
+ private ComponentName mComponentName;
+
+ ServiceDeathRecipient(ComponentName name) {
+ mComponentName = name;
+ }
+
+ @Override
+ public void binderDied() {
+ try {
+ synchronized (mLock) {
+ Log.startSession("SDR.bD");
+ Log.i(this, "binderDied: ConnectionService %s died.", mComponentName);
+ logServiceDisconnected("binderDied");
+ handleDisconnect();
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+ }
+
private final class ServiceBinderConnection implements ServiceConnection {
/**
* The initial call for which the service was bound.
@@ -132,10 +156,20 @@
handleFailedConnection();
return;
}
-
- mServiceConnection = this;
- setBinder(binder);
- handleSuccessfulConnection();
+ if (binder != null) {
+ mServiceDeathRecipient = new ServiceDeathRecipient(componentName);
+ try {
+ binder.linkToDeath(mServiceDeathRecipient, 0);
+ mServiceConnection = this;
+ setBinder(binder);
+ handleSuccessfulConnection();
+ } catch (RemoteException e) {
+ Log.w(this, "onServiceConnected: %s died.");
+ if (mServiceDeathRecipient != null) {
+ mServiceDeathRecipient.binderDied();
+ }
+ }
+ }
}
} finally {
Log.endSession();
@@ -148,11 +182,7 @@
Log.startSession("SBC.oSD");
synchronized (mLock) {
logServiceDisconnected("onServiceDisconnected");
-
- mServiceConnection = null;
- clearAbort();
-
- handleServiceDisconnected();
+ handleDisconnect();
}
} finally {
Log.endSession();
@@ -160,6 +190,13 @@
}
}
+ private void handleDisconnect() {
+ mServiceConnection = null;
+ clearAbort();
+
+ handleServiceDisconnected();
+ }
+
/** The application context. */
private final Context mContext;
@@ -178,6 +215,9 @@
/** Used to bind and unbind from the service. */
private ServiceConnection mServiceConnection;
+ /** Used to handle death of the service. */
+ private ServiceDeathRecipient mServiceDeathRecipient;
+
/** {@link UserHandle} to use for binding, to support work profiles and multi-user. */
private UserHandle mUserHandle;
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 3a09aa8..cd9b2df 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -204,10 +204,16 @@
String callingPackage) {
try {
Log.startSession("TSI.gPASS");
+ try {
+ enforceModifyPermission(
+ "getPhoneAccountsSupportingScheme requires MODIFY_PHONE_STATE");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", Binder.getCallingUid(),
+ "getPhoneAccountsSupportingScheme: " + callingPackage);
+ return Collections.emptyList();
+ }
+
synchronized (mLock) {
- if (!canReadPhoneState(callingPackage, "getPhoneAccountsSupportingScheme")) {
- return Collections.emptyList();
- }
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
try {
@@ -270,33 +276,57 @@
@Override
public int getAllPhoneAccountsCount() {
- synchronized (mLock) {
+ try {
+ Log.startSession("TSI.gAPAC");
try {
- Log.startSession("TSI.gAPAC");
- // This list is pre-filtered for the calling user.
- return getAllPhoneAccounts().size();
- } catch (Exception e) {
- Log.e(this, e, "getAllPhoneAccountsCount");
+ enforceModifyPermission(
+ "getAllPhoneAccountsCount requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", Binder.getCallingUid(),
+ "getAllPhoneAccountsCount");
throw e;
- } finally {
- Log.endSession();
}
+
+ synchronized (mLock) {
+ try {
+ // This list is pre-filtered for the calling user.
+ return getAllPhoneAccounts().size();
+ } catch (Exception e) {
+ Log.e(this, e, "getAllPhoneAccountsCount");
+ throw e;
+
+ }
+ }
+ } finally {
+ Log.endSession();
}
}
@Override
public List<PhoneAccount> getAllPhoneAccounts() {
synchronized (mLock) {
- final UserHandle callingUserHandle = Binder.getCallingUserHandle();
- long token = Binder.clearCallingIdentity();
try {
Log.startSession("TSI.gAPA");
- return mPhoneAccountRegistrar.getAllPhoneAccounts(callingUserHandle);
- } catch (Exception e) {
- Log.e(this, e, "getAllPhoneAccounts");
- throw e;
+ try {
+ enforceModifyPermission(
+ "getAllPhoneAccounts requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", Binder.getCallingUid(),
+ "getAllPhoneAccounts");
+ throw e;
+ }
+
+ final UserHandle callingUserHandle = Binder.getCallingUserHandle();
+ long token = Binder.clearCallingIdentity();
+ try {
+ return mPhoneAccountRegistrar.getAllPhoneAccounts(callingUserHandle);
+ } catch (Exception e) {
+ Log.e(this, e, "getAllPhoneAccounts");
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
} finally {
- Binder.restoreCallingIdentity(token);
Log.endSession();
}
}
@@ -304,19 +334,31 @@
@Override
public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
- synchronized (mLock) {
- final UserHandle callingUserHandle = Binder.getCallingUserHandle();
- long token = Binder.clearCallingIdentity();
+ try {
+ Log.startSession("TSI.gAPAH");
try {
- Log.startSession("TSI.gAPAH");
- return mPhoneAccountRegistrar.getAllPhoneAccountHandles(callingUserHandle);
- } catch (Exception e) {
- Log.e(this, e, "getAllPhoneAccounts");
+ enforceModifyPermission(
+ "getAllPhoneAccountHandles requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", Binder.getCallingUid(),
+ "getAllPhoneAccountHandles");
throw e;
- } finally {
- Binder.restoreCallingIdentity(token);
- Log.endSession();
}
+
+ synchronized (mLock) {
+ final UserHandle callingUserHandle = Binder.getCallingUserHandle();
+ long token = Binder.clearCallingIdentity();
+ try {
+ return mPhoneAccountRegistrar.getAllPhoneAccountHandles(callingUserHandle);
+ } catch (Exception e) {
+ Log.e(this, e, "getAllPhoneAccounts");
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } finally {
+ Log.endSession();
}
}
@@ -682,8 +724,14 @@
public boolean isRinging(String callingPackage) {
try {
Log.startSession("TSI.iR");
- if (!canReadPhoneState(callingPackage, "isRinging")) {
- return false;
+ if (!isPrivilegedDialerCalling(callingPackage)) {
+ try {
+ enforceModifyPermission(
+ "isRinging requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", "isRinging: " + callingPackage);
+ throw e;
+ }
}
synchronized (mLock) {
@@ -932,8 +980,15 @@
public boolean isTtySupported(String callingPackage) {
try {
Log.startSession("TSI.iTS");
- if (!canReadPhoneState(callingPackage, "hasVoiceMailNumber")) {
- return false;
+ if (!isPrivilegedDialerCalling(callingPackage)) {
+ try {
+ enforceModifyPermission(
+ "isTtySupported requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", "isTtySupported: " +
+ callingPackage);
+ throw e;
+ }
}
synchronized (mLock) {
@@ -1033,6 +1088,15 @@
public void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
try {
Log.startSession("TSI.aNUC");
+ try {
+ enforceModifyPermission(
+ "addNewUnknownCall requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ EventLog.writeEvent(0x534e4554, "62347125", Binder.getCallingUid(),
+ "addNewUnknownCall");
+ throw e;
+ }
+
synchronized (mLock) {
if (phoneAccountHandle != null &&
phoneAccountHandle.getComponentName() != null) {
@@ -1516,6 +1580,10 @@
enforcePermission(MODIFY_PHONE_STATE);
}
+ private void enforceModifyPermission(String message) {
+ mContext.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, message);
+ }
+
private void enforcePermission(String permission) {
mContext.enforceCallingOrSelfPermission(permission, null);
}
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index b40381b..31afbba 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -22,7 +22,6 @@
import com.android.server.telecom.components.UserCallIntentProcessor;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.ui.IncomingCallNotifier;
-import com.android.server.telecom.ui.IncomingCallNotifier.IncomingCallNotifierFactory;
import com.android.server.telecom.ui.MissedCallNotifierImpl.MissedCallNotifierImplFactory;
import com.android.server.telecom.BluetoothPhoneServiceImpl.BluetoothPhoneServiceImplFactory;
import com.android.server.telecom.CallAudioManager.AudioServiceFactory;
@@ -190,7 +189,8 @@
AsyncRingtonePlayer asyncRingtonePlayer,
PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
IncomingCallNotifier incomingCallNotifier,
- InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory) {
+ InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory,
+ ClockProxy clockProxy) {
mContext = context.getApplicationContext();
LogUtils.initLogging(mContext);
DefaultDialerManagerAdapter defaultDialerAdapter =
@@ -255,7 +255,8 @@
asyncRingtonePlayer,
phoneNumberUtilsAdapter,
emergencyCallHelper,
- toneGeneratorFactory);
+ toneGeneratorFactory,
+ clockProxy);
mIncomingCallNotifier = incomingCallNotifier;
incomingCallNotifier.setCallsManagerProxy(new IncomingCallNotifier.CallsManagerProxy() {
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index d9d60b8..19dd404 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -25,6 +25,7 @@
import android.os.IBinder;
import android.os.PowerManager;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.telecom.Log;
import com.android.internal.telephony.CallerInfoAsyncQuery;
@@ -33,6 +34,7 @@
import com.android.server.telecom.BluetoothPhoneServiceImpl;
import com.android.server.telecom.CallerInfoAsyncQueryFactory;
import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.HeadsetMediaButton;
import com.android.server.telecom.HeadsetMediaButtonFactory;
@@ -161,8 +163,18 @@
new AsyncRingtonePlayer(),
new PhoneNumberUtilsAdapterImpl(),
new IncomingCallNotifier(context),
- ToneGenerator::new
- ));
+ ToneGenerator::new,
+ new ClockProxy() {
+ @Override
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ @Override
+ public long elapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+ }));
}
if (BluetoothAdapter.getDefaultAdapter() != null) {
context.startService(new Intent(context, BluetoothPhoneService.class));
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
index 705e031..1278a4b 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
@@ -41,12 +41,9 @@
super.bindView(view, context, cursor);
final String rawNumber = cursor.getString(cursor.getColumnIndex(
BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER));
- String formattedNumber = PhoneNumberUtils.formatNumber(rawNumber,
- BlockedNumbersUtil.getLocaleDefaultToUS());
- final String finalFormattedNumber = formattedNumber == null ? rawNumber : formattedNumber;
-
+ final String formattedNumber = BlockedNumbersUtil.formatNumber(rawNumber);
TextView numberView = (TextView) view.findViewById(R.id.blocked_number);
- Spannable numberSpannable = new SpannableString(finalFormattedNumber);
+ Spannable numberSpannable = new SpannableString(formattedNumber);
PhoneNumberUtils.addTtsSpan(numberSpannable, 0, numberSpannable.length());
numberView.setText(numberSpannable);
@@ -54,7 +51,7 @@
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- showDeleteBlockedNumberDialog(context, rawNumber, finalFormattedNumber);
+ showDeleteBlockedNumberDialog(context, rawNumber, formattedNumber);
}
});
}
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
index 5d2e238..b75c4b3 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
@@ -18,11 +18,11 @@
import android.content.Context;
import android.telephony.PhoneNumberUtils;
+import android.text.BidiFormatter;
import android.text.Spannable;
import android.text.SpannableString;
+import android.text.TextDirectionHeuristics;
import android.widget.Toast;
-import com.android.server.telecom.R;
-
import java.util.Locale;
public final class BlockedNumbersUtil {
@@ -40,18 +40,28 @@
}
/**
+ * Attempts to format the number, or returns the original number if it is not formattable. Also
+ * wraps the returned number as LTR.
+ */
+ public static String formatNumber(String number){
+ String formattedNumber = PhoneNumberUtils.formatNumber(number, getLocaleDefaultToUS());
+ return BidiFormatter.getInstance().unicodeWrap(
+ formattedNumber == null ? number : formattedNumber,
+ TextDirectionHeuristics.LTR);
+ }
+
+ /**
* Formats the number in the string and shows a toast for {@link Toast#LENGTH_SHORT}.
*
* <p>Adds the number in a TsSpan so that it reads as a phone number when talk back is on.
*/
public static void showToastWithFormattedNumber(Context context, int stringId, String number) {
- String formattedNumber = PhoneNumberUtils.formatNumber(number, getLocaleDefaultToUS());
- String finalFormattedNumber = formattedNumber == null ? number : formattedNumber;
- String message = context.getString(stringId, finalFormattedNumber);
- int startingPosition = message.indexOf(finalFormattedNumber);
+ String formattedNumber = formatNumber(number);
+ String message = context.getString(stringId, formattedNumber);
+ int startingPosition = message.indexOf(formattedNumber);
Spannable messageSpannable = new SpannableString(message);
PhoneNumberUtils.addTtsSpan(messageSpannable, startingPosition,
- startingPosition + finalFormattedNumber.length());
+ startingPosition + formattedNumber.length());
Toast.makeText(
context,
messageSpannable,
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index bbacd36..9851674 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -309,6 +309,7 @@
publicBuilder.setSmallIcon(android.R.drawable.stat_notify_missed_call)
.setColor(mContext.getResources().getColor(R.color.theme_color))
.setWhen(callInfo.getCreationTimeMillis())
+ .setShowWhen(true)
// Show "Phone" for notification title.
.setContentTitle(mContext.getText(R.string.userCallActivityLabel))
// Notification details shows that there are missed call(s), but does not reveal
@@ -323,6 +324,7 @@
builder.setSmallIcon(android.R.drawable.stat_notify_missed_call)
.setColor(mContext.getResources().getColor(R.color.theme_color))
.setWhen(callInfo.getCreationTimeMillis())
+ .setShowWhen(true)
.setContentTitle(mContext.getText(titleResId))
.setContentText(expandedText)
.setContentIntent(createCallLogPendingIntent(userHandle))
diff --git a/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java b/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
index 9bb6977..78ebbe5 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestRttActivity.java
@@ -93,7 +93,8 @@
}
// inner read loop
while (true) {
- String receivedText = rttCall.read();
+ String receivedText;
+ receivedText = rttCall.read();
if (receivedText == null) {
if (Thread.currentThread().isInterrupted()) {
break begin;
diff --git a/tests/Android.mk b/tests/Android.mk
index 212bbd7..77abcad 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -23,8 +23,7 @@
android-support-test \
guava \
mockito-target \
- platform-test-annotations \
- legacy-android-test
+ platform-test-annotations
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
@@ -41,7 +40,8 @@
$(SUPPORT_LIBRARY_ROOT)/compat/res
LOCAL_JAVA_LIBRARIES := \
- android.test.runner \
+ android.test.mock \
+ legacy-android-test \
telephony-common
LOCAL_AAPT_FLAGS := \
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index 1c786e5..e70a63a 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -18,10 +18,14 @@
import android.content.Context;
import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.telecom.CallAudioState;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.InCallService;
import android.telecom.Log;
+import android.telecom.Logging.EventManager;
import android.telecom.ParcelableCallAnalytics;
import android.telecom.TelecomAnalytics;
import android.telecom.TelecomManager;
@@ -34,6 +38,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.Analytics;
+import com.android.server.telecom.CallAudioRouteStateMachine;
import com.android.server.telecom.LogUtils;
import com.android.server.telecom.nano.TelecomLogClass;
@@ -41,6 +46,7 @@
import java.io.StringWriter;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -309,6 +315,38 @@
}
@MediumTest
+ public void testAnalyticsAudioRoutes() throws Exception {
+ Analytics.reset();
+ IdPair testCall = startAndMakeActiveIncomingCall(
+ "650-555-1212",
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+ List<Integer> audioRoutes = new LinkedList<>();
+
+ waitForHandlerAction(
+ mTelecomSystem.getCallsManager().getCallAudioManager()
+ .getCallAudioRouteStateMachine().getHandler(),
+ TEST_TIMEOUT);
+ audioRoutes.add(mInCallServiceFixtureX.mCallAudioState.getRoute());
+ mInCallServiceFixtureX.getInCallAdapter().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
+ waitForHandlerAction(
+ mTelecomSystem.getCallsManager().getCallAudioManager()
+ .getCallAudioRouteStateMachine().getHandler(),
+ TEST_TIMEOUT);
+ audioRoutes.add(CallAudioState.ROUTE_SPEAKER);
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ assertTrue(analyticsMap.containsKey(testCall.mCallId));
+
+ Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
+ List<EventManager.Event> events = callAnalytics.callEvents.getEvents();
+ for (int route : audioRoutes) {
+ String logEvent = CallAudioRouteStateMachine.AUDIO_ROUTE_TO_LOG_EVENT.get(route);
+ assertTrue(events.stream().anyMatch(event -> event.eventId.equals(logEvent)));
+ }
+ }
+
+ @MediumTest
public void testAnalyticsConnectionProperties() throws Exception {
Analytics.reset();
IdPair testCall = startAndMakeActiveIncomingCall(
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index ce774a7..e18ffb2 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -82,11 +82,22 @@
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ assertEquals(TEST_CONNECT_TIME,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getConnectTimeMillis());
+ assertEquals(TEST_CONNECT_TIME,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getConnectTimeMillis());
+ assertEquals(TEST_CREATE_TIME,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getCreationTimeMillis());
+ assertEquals(TEST_CREATE_TIME,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getCreationTimeMillis());
+
verifyNoBlockChecks();
}
@@ -95,6 +106,8 @@
IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureX.getCall(ids.mCallId).getState());
@@ -219,6 +232,8 @@
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureX.getCall(ids.mCallId).getState());
@@ -231,6 +246,8 @@
IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureX.getCall(ids.mCallId).getState());
@@ -290,6 +307,8 @@
IdPair ids = outgoingCallPhoneAccountSelected(mPhoneAccountA0.getAccountHandle(),
startingNumConnections, startingNumCalls, mConnectionServiceFixtureA);
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureX.getCall(ids.mCallId).getState());
@@ -341,6 +360,8 @@
@LargeTest
public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() throws Exception {
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME);
Bundle extras = new Bundle();
extras.putParcelable(
TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
@@ -377,6 +398,8 @@
verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
.addCall(any(ParcelableCall.class));
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
disconnectCall(mInCallServiceFixtureX.mLatestCallId,
mConnectionServiceFixtureA.mLatestConnectionId);
}
@@ -736,9 +759,15 @@
}
private void disconnectCall(String callId, String connectionId) throws Exception {
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
+ assertEquals(TEST_CREATE_TIME,
+ mInCallServiceFixtureX.getCall(callId).getCreationTimeMillis());
+ assertEquals(TEST_CREATE_TIME,
+ mInCallServiceFixtureY.getCall(callId).getCreationTimeMillis());
}
/**
@@ -891,4 +920,59 @@
assert(!call.isVideoCallingSupported());
assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState());
}
+
+ /**
+ * Basic test to ensure that a self-managed ConnectionService can place a call.
+ * @throws Exception
+ */
+ @LargeTest
+ public void testSelfManagedOutgoing() throws Exception {
+ PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle();
+ IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", phoneAccountHandle,
+ mConnectionServiceFixtureA);
+
+ // The InCallService should not know about the call since its self-managed.
+ assertNull(mInCallServiceFixtureX.getCall(ids.mCallId));
+ }
+
+ /**
+ * Basic test to ensure that a self-managed ConnectionService can add an incoming call.
+ * @throws Exception
+ */
+ @LargeTest
+ public void testSelfManagedIncoming() throws Exception {
+ PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle();
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", phoneAccountHandle,
+ mConnectionServiceFixtureA);
+
+ // The InCallService should not know about the call since its self-managed.
+ assertNull(mInCallServiceFixtureX.getCall(ids.mCallId));
+ }
+
+ /**
+ * Basic test to ensure that when there are no calls, we permit outgoing calls by a self managed
+ * CS.
+ * @throws Exception
+ */
+ @LargeTest
+ public void testIsOutgoingCallPermitted() throws Exception {
+ assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
+ .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+ }
+
+ /**
+ * Basic test to ensure that when there are other calls, we do not permit outgoing calls by a
+ * self managed CS.
+ * @throws Exception
+ */
+ @LargeTest
+ public void testIsOutgoingCallPermittedOngoing() throws Exception {
+ // Start a regular call; the self-managed CS can't make a call now.
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+ assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+ assertFalse(mTelecomSystem.getTelecomServiceImpl().getBinder()
+ .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 129d86e..6e09c90 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -68,6 +68,7 @@
private static final int NONE = 0;
private static final int ON = 1;
private static final int OFF = 2;
+ private static final int OPTIONAL = 3;
static class RoutingTestParameters extends TestParameters {
public String name;
@@ -405,7 +406,7 @@
"Connect headset during earpiece", // name
CallAudioState.ROUTE_EARPIECE, // initialRoute
CallAudioState.ROUTE_EARPIECE, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
@@ -418,7 +419,7 @@
"Connect headset during bluetooth", // name
CallAudioState.ROUTE_BLUETOOTH, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
OFF, // bluetoothInteraction
CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
@@ -444,7 +445,7 @@
"Disconnect headset during headset", // name
CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
CallAudioState.ROUTE_EARPIECE, // expectedRoute
@@ -457,10 +458,10 @@
"Disconnect headset during headset with bluetooth available", // name
CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
- NONE, // speakerInteraction
- NONE, // bluetoothInteraction
+ OPTIONAL, // speakerInteraction
+ ON, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
- CallAudioState.ROUTE_EARPIECE, // expectedRoute
+ CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
true, // doesDeviceSupportEarpiece
shouldRunWithFocus
@@ -470,7 +471,7 @@
"Disconnect headset during bluetooth", // name
CallAudioState.ROUTE_BLUETOOTH, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
@@ -483,7 +484,7 @@
"Disconnect headset during speakerphone", // name
CallAudioState.ROUTE_SPEAKER, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
CallAudioState.ROUTE_SPEAKER, // expectedRoute
@@ -496,7 +497,7 @@
"Disconnect headset during speakerphone with bluetooth available", // name
CallAudioState.ROUTE_SPEAKER, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
CallAudioState.ROUTE_SPEAKER, // expectedRoute
@@ -509,7 +510,7 @@
"Connect bluetooth during earpiece", // name
CallAudioState.ROUTE_EARPIECE, // initialRoute
CallAudioState.ROUTE_EARPIECE, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
ON, // bluetoothInteraction
CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
@@ -522,7 +523,7 @@
"Connect bluetooth during wired headset", // name
CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
ON, // bluetoothInteraction
CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
@@ -548,7 +549,7 @@
"Disconnect bluetooth during bluetooth without headset in", // name
CallAudioState.ROUTE_BLUETOOTH, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
OFF, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_EARPIECE, // expectedRoute
@@ -561,7 +562,7 @@
"Disconnect bluetooth during bluetooth without headset in, priority mode ", // name
CallAudioState.ROUTE_BLUETOOTH, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
OFF, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_EARPIECE, // expectedRoute
@@ -574,7 +575,7 @@
"Disconnect bluetooth during bluetooth with headset in", // name
CallAudioState.ROUTE_BLUETOOTH, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
OFF, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
@@ -587,7 +588,7 @@
"Disconnect bluetooth during speakerphone", // name
CallAudioState.ROUTE_SPEAKER, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_SPEAKER, // expectedRoute
@@ -600,7 +601,7 @@
"Disconnect bluetooth during earpiece", // name
CallAudioState.ROUTE_EARPIECE, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
NONE, // bluetoothInteraction
CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
CallAudioState.ROUTE_EARPIECE, // expectedRoute
@@ -652,7 +653,7 @@
"Switch to earpiece from bluetooth", // name
CallAudioState.ROUTE_BLUETOOTH, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
OFF, // bluetoothInteraction
CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
CallAudioState.ROUTE_EARPIECE, // expectedRoute
@@ -717,7 +718,7 @@
"Switch to bluetooth from earpiece", // name
CallAudioState.ROUTE_EARPIECE, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
ON, // bluetoothInteraction
CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
@@ -730,7 +731,7 @@
"Switch to bluetooth from wired headset", // name
CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
- NONE, // speakerInteraction
+ OPTIONAL, // speakerInteraction
ON, // bluetoothInteraction
CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
@@ -855,6 +856,10 @@
case OFF:
verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(null);
verify(mockBluetoothRouteManager).disconnectBluetoothAudio();
+ break;
+ case OPTIONAL:
+ // optional, don't test
+ break;
}
switch (params.speakerInteraction) {
@@ -864,6 +869,10 @@
case ON: // fall through
case OFF:
verify(mockAudioManager).setSpeakerphoneOn(params.speakerInteraction == ON);
+ break;
+ case OPTIONAL:
+ // optional, don't test
+ break;
}
// Verify the end state
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index e815b5c..39f70c8 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -50,7 +50,6 @@
import java.lang.Override;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -410,6 +409,7 @@
IVideoProvider videoProvider;
int videoState;
long connectTimeMillis;
+ long connectElapsedTimeMillis;
StatusHints statusHints;
Bundle extras;
}
@@ -640,6 +640,7 @@
c.videoProvider,
c.videoState,
c.connectTimeMillis,
+ c.connectElapsedTimeMillis,
c.statusHints,
c.extras);
}
@@ -660,6 +661,7 @@
false, /* ringback requested */
false, /* voip audio mode */
0, /* Connect Time for conf call on this connection */
+ 0, /* Connect Real Time comes from conference call */
c.statusHints,
c.disconnectCause,
c.conferenceableConnectionIds,
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 205d778..6b2cf4f 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -65,11 +65,10 @@
import com.android.server.telecom.AsyncRingtonePlayer;
import com.android.server.telecom.BluetoothPhoneServiceImpl;
import com.android.server.telecom.CallAudioManager;
-import com.android.server.telecom.CallAudioRouteStateMachine;
-import com.android.server.telecom.CallerInfoAsyncQueryFactory;
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.CallsManagerListenerBase;
+import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.HeadsetMediaButton;
import com.android.server.telecom.HeadsetMediaButtonFactory;
@@ -83,7 +82,6 @@
import com.android.server.telecom.ProximitySensorManagerFactory;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
-import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
import com.android.server.telecom.components.UserCallIntentProcessor;
import com.android.server.telecom.ui.IncomingCallNotifier;
import com.android.server.telecom.ui.MissedCallNotifierImpl.MissedCallNotifierImplFactory;
@@ -108,6 +106,16 @@
static final int TEST_POLL_INTERVAL = 10; // milliseconds
static final int TEST_TIMEOUT = 1000; // milliseconds
+ // Purposely keep the connect time (which is wall clock) and elapsed time (which is time since
+ // boot) different to test that wall clock time operations and elapsed time operations perform
+ // as they individually should.
+ static final long TEST_CREATE_TIME = 100;
+ static final long TEST_CREATE_ELAPSED_TIME = 200;
+ static final long TEST_CONNECT_TIME = 1000;
+ static final long TEST_CONNECT_ELAPSED_TIME = 2000;
+ static final long TEST_DISCONNECT_TIME = 8000;
+ static final long TEST_DISCONNECT_ELAPSED_TIME = 4000;
+
public class HeadsetMediaButtonFactoryF implements HeadsetMediaButtonFactory {
@Override
public HeadsetMediaButton create(Context context, CallsManager callsManager,
@@ -194,6 +202,7 @@
@Mock BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl;
@Mock AsyncRingtonePlayer mAsyncRingtonePlayer;
@Mock IncomingCallNotifier mIncomingCallNotifier;
+ @Mock ClockProxy mClockProxy;
final ComponentName mInCallServiceComponentNameX =
new ComponentName(
@@ -251,6 +260,16 @@
PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
.build();
+ final PhoneAccount mPhoneAccountSelfManaged =
+ PhoneAccount.builder(
+ new PhoneAccountHandle(
+ mConnectionServiceComponentNameA,
+ "id SM"),
+ "Phone account service A SM")
+ .addSupportedUriScheme("tel")
+ .setCapabilities(
+ PhoneAccount.CAPABILITY_SELF_MANAGED)
+ .build();
final PhoneAccount mPhoneAccountB0 =
PhoneAccount.builder(
new PhoneAccountHandle(
@@ -393,7 +412,9 @@
when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class)))
.thenReturn(TEST_TIMEOUT / 5L);
mIncomingCallNotifier = mock(IncomingCallNotifier.class);
-
+ mClockProxy = mock(ClockProxy.class);
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME);
mTelecomSystem = new TelecomSystem(
mComponentContextFixture.getTestDouble(),
new MissedCallNotifierImplFactory() {
@@ -426,7 +447,8 @@
mAsyncRingtonePlayer,
mPhoneNumberUtilsAdapter,
mIncomingCallNotifier,
- (streamType, volume) -> mock(ToneGenerator.class));
+ (streamType, volume) -> mock(ToneGenerator.class),
+ mClockProxy);
mComponentContextFixture.setTelecomManager(new TelecomManager(
mComponentContextFixture.getTestDouble(),
@@ -456,6 +478,7 @@
mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA2);
+ mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountSelfManaged);
mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0);
mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1);
@@ -646,7 +669,8 @@
mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
CallerInfoAsyncQueryFactoryFixture.Request::reply);
- if (!hasInCallAdapter) {
+ boolean isSelfManaged = phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle();
+ if (!hasInCallAdapter && !isSelfManaged) {
verify(mInCallServiceFixtureX.getTestDouble())
.setInCallAdapter(
any(IInCallAdapter.class));
@@ -668,27 +692,28 @@
ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mComponentContextFixture.getTestDouble().getApplicationContext(),
- times(mNumOutgoingCallsMade))
- .sendOrderedBroadcastAsUser(
- newOutgoingCallIntent.capture(),
- any(UserHandle.class),
- anyString(),
- anyInt(),
- newOutgoingCallReceiver.capture(),
- nullable(Handler.class),
- anyInt(),
- anyString(),
- nullable(Bundle.class));
-
- // Pass on the new outgoing call Intent
- // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
- newOutgoingCallReceiver.getValue().setPendingResult(
- new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
- newOutgoingCallReceiver.getValue().setResultData(
- newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
- newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(),
- newOutgoingCallIntent.getValue());
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ verify(mComponentContextFixture.getTestDouble().getApplicationContext(),
+ times(mNumOutgoingCallsMade))
+ .sendOrderedBroadcastAsUser(
+ newOutgoingCallIntent.capture(),
+ any(UserHandle.class),
+ anyString(),
+ anyInt(),
+ newOutgoingCallReceiver.capture(),
+ nullable(Handler.class),
+ anyInt(),
+ anyString(),
+ nullable(Bundle.class));
+ // Pass on the new outgoing call Intent
+ // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
+ newOutgoingCallReceiver.getValue().setPendingResult(
+ new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
+ newOutgoingCallReceiver.getValue().setResultData(
+ newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
+ newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(),
+ newOutgoingCallIntent.getValue());
+ }
return mInCallServiceFixtureX.mLatestCallId;
}
@@ -735,8 +760,13 @@
verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
.createConnectionComplete(anyString(), any());
- assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
- assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
+ if (phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size());
+ assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size());
+ } else {
+ assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
+ assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
+ }
assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
@@ -812,58 +842,59 @@
// is added, future interactions as triggered by the ConnectionService, through the various
// test fixtures, will be synchronous.
- if (!hasInCallAdapter) {
+ if (!hasInCallAdapter
+ && phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
.setInCallAdapter(any(IInCallAdapter.class));
verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
.setInCallAdapter(any(IInCallAdapter.class));
+
+ // Give the InCallService time to respond
+ assertTrueWithTimeout(new Predicate<Void>() {
+ @Override
+ public boolean apply(Void v) {
+ return mInCallServiceFixtureX.mInCallAdapter != null;
+ }
+ });
+
+ assertTrueWithTimeout(new Predicate<Void>() {
+ @Override
+ public boolean apply(Void v) {
+ return mInCallServiceFixtureY.mInCallAdapter != null;
+ }
+ });
+
+ verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
+ .addCall(any(ParcelableCall.class));
+ verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
+ .addCall(any(ParcelableCall.class));
+
+ // Give the InCallService time to respond
+
+ assertTrueWithTimeout(new Predicate<Void>() {
+ @Override
+ public boolean apply(Void v) {
+ return startingNumConnections + 1 ==
+ connectionServiceFixture.mConnectionById.size();
+ }
+ });
+ assertTrueWithTimeout(new Predicate<Void>() {
+ @Override
+ public boolean apply(Void v) {
+ return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size();
+ }
+ });
+ assertTrueWithTimeout(new Predicate<Void>() {
+ @Override
+ public boolean apply(Void v) {
+ return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size();
+ }
+ });
+
+ assertEquals(mInCallServiceFixtureX.mLatestCallId,
+ mInCallServiceFixtureY.mLatestCallId);
}
- // Give the InCallService time to respond
-
- assertTrueWithTimeout(new Predicate<Void>() {
- @Override
- public boolean apply(Void v) {
- return mInCallServiceFixtureX.mInCallAdapter != null;
- }
- });
-
- assertTrueWithTimeout(new Predicate<Void>() {
- @Override
- public boolean apply(Void v) {
- return mInCallServiceFixtureY.mInCallAdapter != null;
- }
- });
-
- verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
- .addCall(any(ParcelableCall.class));
- verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
- .addCall(any(ParcelableCall.class));
-
- // Give the InCallService time to respond
-
- assertTrueWithTimeout(new Predicate<Void>() {
- @Override
- public boolean apply(Void v) {
- return startingNumConnections + 1 ==
- connectionServiceFixture.mConnectionById.size();
- }
- });
- assertTrueWithTimeout(new Predicate<Void>() {
- @Override
- public boolean apply(Void v) {
- return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size();
- }
- });
- assertTrueWithTimeout(new Predicate<Void>() {
- @Override
- public boolean apply(Void v) {
- return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size();
- }
- });
-
- assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
-
return new IdPair(connectionServiceFixture.mLatestConnectionId,
mInCallServiceFixtureX.mLatestCallId);
}
@@ -886,15 +917,22 @@
Process.myUserHandle(), videoState);
connectionServiceFixture.sendSetDialing(ids.mConnectionId);
- assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_DIALING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DIALING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ }
connectionServiceFixture.sendSetVideoState(ids.mConnectionId);
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
connectionServiceFixture.sendSetActive(ids.mConnectionId);
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
-
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ }
return ids;
}
@@ -914,24 +952,32 @@
int videoState) throws Exception {
IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
- assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_RINGING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_RINGING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
- mInCallServiceFixtureX.mInCallAdapter
- .answerCall(ids.mCallId, videoState);
+ mInCallServiceFixtureX.mInCallAdapter
+ .answerCall(ids.mCallId, videoState);
- if (!VideoProfile.isVideo(videoState)) {
- verify(connectionServiceFixture.getTestDouble())
- .answer(eq(ids.mConnectionId), any());
- } else {
- verify(connectionServiceFixture.getTestDouble())
- .answerVideo(eq(ids.mConnectionId), eq(videoState), any());
+ if (!VideoProfile.isVideo(videoState)) {
+ verify(connectionServiceFixture.getTestDouble())
+ .answer(eq(ids.mConnectionId), any());
+ } else {
+ verify(connectionServiceFixture.getTestDouble())
+ .answerVideo(eq(ids.mConnectionId), eq(videoState), any());
+ }
}
+ when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
+ when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
connectionServiceFixture.sendSetActive(ids.mConnectionId);
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ }
return ids;
}