diff options
author | Dan Pasanen <dan.pasanen@gmail.com> | 2017-04-05 08:59:17 -0500 |
---|---|---|
committer | Dan Pasanen <dan.pasanen@gmail.com> | 2017-04-05 13:20:35 -0500 |
commit | 7099d766dc334ddbe9317e6d3c4395fe37e421d6 (patch) | |
tree | 533f40d3d389f4dd462488c92be4966b98bc5b17 | |
parent | 1d870ae06b0bef6ed7ee7e459e270dee22b2371a (diff) | |
parent | ad18dc9e336c73922192e1693a836781cff6c929 (diff) | |
download | android_packages_services_Telecomm-staging/cm-14.1_android-7.1.2_r2.tar.gz android_packages_services_Telecomm-staging/cm-14.1_android-7.1.2_r2.tar.bz2 android_packages_services_Telecomm-staging/cm-14.1_android-7.1.2_r2.zip |
Merge tag 'android-7.1.2_r2' into cm-14.1staging/cm-14.1_android-7.1.2_r2
Android 7.1.2 Release 2 (N2G47E)
Change-Id: I7d921a147376e4c7b065c538023e4d9a43cbbdb2
34 files changed, 467 insertions, 121 deletions
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml index fd5beff6..e1571b33 100644 --- a/res/values-bs-rBA/strings.xml +++ b/res/values-bs-rBA/strings.xml @@ -52,18 +52,18 @@ <string name="blocked_numbers" msgid="2751843139572970579">"Blokirani brojevi"</string> <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nećete primati pozive i poruke od blokiranih brojeva."</string> <string name="block_number" msgid="1101252256321306179">"Dodaj broj"</string> - <string name="unblock_dialog_body" msgid="1614238499771862793">"Odblokirati <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string> - <string name="unblock_button" msgid="3078048901972674170">"Odblokiraj"</string> + <string name="unblock_dialog_body" msgid="1614238499771862793">"Deblokirati <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string> + <string name="unblock_button" msgid="3078048901972674170">"Deblokiraj"</string> <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Blokiraj pozive i tekstualne poruke od"</string> - <string name="add_blocked_number_hint" msgid="6847675097085433553">"Telefonski broj"</string> + <string name="add_blocked_number_hint" msgid="6847675097085433553">"Broj telefona"</string> <string name="block_button" msgid="8822290682524373357">"Blokiraj"</string> <string name="non_primary_user" msgid="5180129233352533459">"Samo vlasnik uređaja može pregledati i upravljati blokiranim brojevima."</string> - <string name="delete_icon_description" msgid="8903995728252556724">"Odblokiraj"</string> + <string name="delete_icon_description" msgid="8903995728252556724">"Deblokiraj"</string> <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Blokiranje je privremeno isključeno"</string> <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"Nakon što pozovete ili pošaljete poruku na broj za hitne slučajeve, blokiranje se isključuje da bi vas hitna služba mogla kontaktirati."</string> <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"Ponovo omogući sada"</string> <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> je blokiran"</string> - <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> je odblokiran"</string> + <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> je deblokiran"</string> <string name="blocked_numbers_block_emergency_number_message" msgid="917851876780698387">"Nije moguće blokirati broj za hitne slučajeve."</string> <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> diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml index 7f2ef593..1dd4963f 100644 --- a/res/values-eu-rES/strings.xml +++ b/res/values-eu-rES/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">"Dei galdua"</string> + <string name="notification_missedCallTitle" msgid="7554385905572364535">"Galdutako deia"</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-hi/strings.xml b/res/values-hi/strings.xml index 874712d8..2aafb5f9 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -54,7 +54,7 @@ <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_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> diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml index 7c6d12b2..94696a74 100644 --- a/res/values-hy-rAM/strings.xml +++ b/res/values-hy-rAM/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">"Արգելափակված համարներից զանգեր կամ SMS–ներ չեք ստանա:"</string> + <string name="blocked_numbers_msg" msgid="1045015186124965643">"Արգելափակված համարներից զանգեր և SMS-ներ չեք ստանա:"</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-it/strings.xml b/res/values-it/strings.xml index 716f765c..8139609b 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -19,10 +19,10 @@ <string name="telecommAppLabel" product="default" msgid="382363169988504520">"Gestione chiamate"</string> <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefono"</string> <string name="unknown" msgid="6878797917991465859">"Sconosciuto"</string> - <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chiamata senza risposta"</string> + <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chiamata persa"</string> <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Chiamata di lavoro persa"</string> - <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chiamate senza risposta"</string> - <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chiamate senza risposta"</string> + <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chiamate perse"</string> + <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chiamate perse"</string> <string name="notification_missedCallTicker" msgid="504686252427747209">"Chiamata senza risposta da <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string> <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Richiama"</string> <string name="notification_missedCall_message" msgid="3049928912736917988">"Messaggio"</string> diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml index f3fa21b1..fa81963c 100644 --- a/res/values-km-rKH/strings.xml +++ b/res/values-km-rKH/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-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml index 7ae3a29e..86834d90 100644 --- a/res/values-kn-rIN/strings.xml +++ b/res/values-kn-rIN/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="telecommAppLabel" product="default" msgid="382363169988504520">"ಕರೆ ನಿರ್ವಹಣೆ"</string> <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ಫೋನ್"</string> - <string name="unknown" msgid="6878797917991465859">"ಅಜ್ಞಾತ"</string> + <string name="unknown" msgid="6878797917991465859">"ಅಪರಿಚಿತ"</string> <string name="notification_missedCallTitle" msgid="7554385905572364535">"ಮಿಸ್ಡ್ ಕಾಲ್"</string> <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"ಮಿಸ್ಡ್ ಕೆಲಸದ ಕರೆ"</string> <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ತಪ್ಪಿದ ಕರೆಗಳು"</string> @@ -47,7 +47,7 @@ <string name="add_vm_number_str" msgid="4676479471644687453">"ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಿ"</string> <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> ಅನ್ನು ನಿಮ್ಮ ಡಿಫಾಲ್ಟ್ ಫೋನ್ ಅಪ್ಲಿಕೇಶನ್ ಆಗಿ ಮಾಡುವುದೇ?"</string> <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ಡಿಫಾಲ್ಟ್ ಹೊಂದಿಸಿ"</string> - <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ರದ್ದುಮಾಡು"</string> + <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> diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml index 7ed47f4d..d1b89bce 100644 --- a/res/values-ne-rNP/strings.xml +++ b/res/values-ne-rNP/strings.xml @@ -62,7 +62,7 @@ <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"रोक लगाउने काम अस्थायी रूपमा निष्क्रिय छ"</string> <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"तपाईँले आपतकालीन नम्बरमा डायल गरेपछि वा पाठ सन्देश पठाएपछि आपतकालीन सेवाहरूले तपाईँलाई सम्पर्क गर्न सकून् भन्ने कुरा सुनिश्चित गर्न कलमाथिको अवरोध निष्क्रिय गरिन्छ।"</string> <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"अब पुन:-सक्रिय गर्नुहोस्"</string> - <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> लाई रोकियो"</string> + <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> माथि रोक लगाइयो"</string> <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> माथिको रोक हटाइयो"</string> <string name="blocked_numbers_block_emergency_number_message" msgid="917851876780698387">"आपतकालीन नम्बरमाथि रोक लगाउन सकिएन।"</string> <string name="blocked_numbers_number_already_blocked_message" msgid="4392247814500811798">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> लाई पहिले नै रोकिएको छ।"</string> diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml index 73800d96..1f4cb3ed 100644 --- a/res/values-pa-rIN/strings.xml +++ b/res/values-pa-rIN/strings.xml @@ -55,7 +55,7 @@ <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="add_blocked_number_hint" msgid="6847675097085433553">"ਫ਼ੋਨ ਨੰਬਰ"</string> <string name="block_button" msgid="8822290682524373357">"ਬਲੌਕ ਕਰੋ"</string> <string name="non_primary_user" msgid="5180129233352533459">"ਸਿਰਫ਼ ਡੀਵਾਈਸ ਮਾਲਕ ਹੀ ਬਲੌਕ ਕੀਤੇ ਗਏ ਨੰਬਰਾਂ ਨੂੰ ਵੇਖ ਅਤੇ ਪ੍ਰਬੰਧਿਤ ਕਰ ਸਕਦਾ ਹੈ।"</string> <string name="delete_icon_description" msgid="8903995728252556724">"ਅਨਬਲੌਕ ਕਰੋ"</string> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index b7b9edf8..d6623cde 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -54,7 +54,7 @@ <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_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> diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml index 6a445bb3..caf3eddc 100644 --- a/res/values-si-rLK/strings.xml +++ b/res/values-si-rLK/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-sk/strings.xml b/res/values-sk/strings.xml index 9dbb2326..28227a86 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -62,8 +62,8 @@ <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Blokovanie je dočasne vypnuté"</string> <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"Keď vytočíte číslo tiesňového volania alebo naň odošlete textovú správu, blokovanie bude vypnuté, aby vás mohli pohotovostné služby kontaktovať."</string> <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"Znova zapnúť"</string> - <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"Číslo <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> je zablokované"</string> - <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"Číslo je <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> odblokované"</string> + <string name="blocked_numbers_number_blocked_message" msgid="7678509606805029540">"Číslo <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> je blokované"</string> + <string name="blocked_numbers_number_unblocked_message" msgid="977894647366750418">"Číslo <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> je odblokované"</string> <string name="blocked_numbers_block_emergency_number_message" msgid="917851876780698387">"Číslo tiesňového volania sa nedá zablokovať."</string> <string name="blocked_numbers_number_already_blocked_message" msgid="4392247814500811798">"Číslo <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> je už zablokované."</string> <string name="toast_personal_call_msg" msgid="5115361633476779723">"Na volanie sa používa osobné vytáčanie"</string> diff --git a/res/values/config.xml b/res/values/config.xml index 11fd6199..e50e1c81 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -39,13 +39,14 @@ <!-- Flag indicating if the tty is enabled --> <bool name="tty_enabled">true</bool> - <!-- Component name for the notification handler. The presence of this value will disable - MissedCallNotifierImpl's presentation of missed call/voice notifications [DO NOT TRANSLATE] --> - <string name="notification_component" translatable="false"></string> - <!-- Flag indicating whether audio should be routed to speaker when docked --> <bool name="use_speaker_when_docked">true</bool> + <!-- Flag indicating whether allow (silence rather than reject) the incoming call if it has a + different source (connection service) from the existing ringing call when reaching + maximum ringing calls. --> + <bool name="silence_incoming_when_different_service_and_maximum_ringing">false</bool> + <!-- DTMF key to be used for LCH hold tone --> <string name="lch_dtmf_key" translatable="false">D</string> </resources> diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java index 44567343..2b6ace55 100644 --- a/src/com/android/server/telecom/Analytics.java +++ b/src/com/android/server/telecom/Analytics.java @@ -33,6 +33,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; import java.util.stream.Collectors; import static android.telecom.ParcelableCallAnalytics.AnalyticsEvent; @@ -521,8 +522,11 @@ public class Analytics { public static final long MILLIS_IN_1_SECOND = ParcelableCallAnalytics.MILLIS_IN_1_SECOND; + public static final int MAX_NUM_CALLS_TO_STORE = 100; + private static final Object sLock = new Object(); // Coarse lock for all of analytics private static final Map<String, CallInfoImpl> sCallIdToInfo = new HashMap<>(); + private static final LinkedList<String> sActiveCallIds = new LinkedList<>(); private static final List<SessionTiming> sSessionTimings = new LinkedList<>(); public static void addSessionTiming(String sessionName, long time) { @@ -538,7 +542,12 @@ public class Analytics { Log.d(TAG, "Starting analytics for call " + callId); CallInfoImpl callInfo = new CallInfoImpl(callId, direction); synchronized (sLock) { + while (sActiveCallIds.size() >= MAX_NUM_CALLS_TO_STORE) { + String callToRemove = sActiveCallIds.remove(); + sCallIdToInfo.remove(callToRemove); + } sCallIdToInfo.put(callId, callInfo); + sActiveCallIds.add(callId); } return callInfo; } diff --git a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java index 3d0a9aea..ed69d207 100644 --- a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java +++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java @@ -761,7 +761,12 @@ public class BluetoothPhoneServiceImpl { } else { addressUri = call.getHandle(); } + String address = addressUri == null ? null : addressUri.getSchemeSpecificPart(); + if (address != null) { + address = PhoneNumberUtils.stripSeparators(address); + } + int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address); if (shouldLog) { diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java index 1fcf69c1..899f148b 100644 --- a/src/com/android/server/telecom/Call.java +++ b/src/com/android/server/telecom/Call.java @@ -26,6 +26,7 @@ import android.os.Looper; import android.os.RemoteException; import android.os.Trace; import android.provider.ContactsContract.Contacts; +import android.telecom.CallAudioState; import android.telecom.Conference; import android.telecom.DisconnectCause; import android.telecom.Connection; @@ -109,7 +110,7 @@ public class Call implements CreateConnectionResponse { void onConnectionManagerPhoneAccountChanged(Call call); void onPhoneAccountChanged(Call call); void onConferenceableCallsChanged(Call call); - boolean onCanceledViaNewOutgoingCallBroadcast(Call call); + boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout); void onHoldToneRequested(Call call); void onConnectionEvent(Call call, String event, Bundle extras); void onExternalCallChanged(Call call, boolean isExternalCall); @@ -171,7 +172,7 @@ public class Call implements CreateConnectionResponse { @Override public void onConferenceableCallsChanged(Call call) {} @Override - public boolean onCanceledViaNewOutgoingCallBroadcast(Call call) { + public boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout) { return false; } @@ -321,6 +322,8 @@ public class Call implements CreateConnectionResponse { private int mConnectionProperties; + private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL; + private boolean mIsConference = false; private final boolean mShouldAttachToExistingConnection; @@ -1084,6 +1087,16 @@ public class Call implements CreateConnectionResponse { } } + public int getSupportedAudioRoutes() { + return mSupportedAudioRoutes; + } + + void setSupportedAudioRoutes(int audioRoutes) { + if (mSupportedAudioRoutes != audioRoutes) { + mSupportedAudioRoutes = audioRoutes; + } + } + @VisibleForTesting public Call getParentCall() { return mParentCall; @@ -1221,6 +1234,7 @@ public class Call implements CreateConnectionResponse { setConnectionCapabilities(connection.getConnectionCapabilities()); setConnectionProperties(connection.getConnectionProperties()); + setSupportedAudioRoutes(connection.getSupportedAudioRoutes()); setVideoProvider(connection.getVideoProvider()); setVideoState(connection.getVideoState()); setRingbackRequested(connection.isRingbackRequested()); @@ -1322,14 +1336,14 @@ public class Call implements CreateConnectionResponse { @VisibleForTesting public void disconnect() { - disconnect(false); + disconnect(0); } /** * Attempts to disconnect the call through the connection service. */ @VisibleForTesting - public void disconnect(boolean wasViaNewOutgoingCallBroadcaster) { + public void disconnect(long disconnectionTimeout) { Log.event(this, Log.Events.REQUEST_DISCONNECT); // Track that the call is now locally disconnecting. @@ -1339,7 +1353,7 @@ public class Call implements CreateConnectionResponse { if (mState == CallState.NEW || mState == CallState.SELECT_PHONE_ACCOUNT || mState == CallState.CONNECTING) { Log.v(this, "Aborting call %s", this); - abort(wasViaNewOutgoingCallBroadcaster); + abort(disconnectionTimeout); } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) { if (mConnectionService == null) { Log.e(this, new Exception(), "disconnect() request on a call without a" @@ -1355,22 +1369,25 @@ public class Call implements CreateConnectionResponse { } } - void abort(boolean wasViaNewOutgoingCallBroadcaster) { + void abort(long disconnectionTimeout) { if (mCreateConnectionProcessor != null && !mCreateConnectionProcessor.isProcessingComplete()) { mCreateConnectionProcessor.abort(); } else if (mState == CallState.NEW || mState == CallState.SELECT_PHONE_ACCOUNT || mState == CallState.CONNECTING) { - if (wasViaNewOutgoingCallBroadcaster) { - // If the cancelation was from NEW_OUTGOING_CALL, then we do not automatically - // destroy the call. Instead, we announce the cancelation and CallsManager handles + if (disconnectionTimeout > 0) { + // If the cancelation was from NEW_OUTGOING_CALL with a timeout of > 0 + // milliseconds, do not destroy the call. + // Instead, we announce the cancellation and CallsManager handles // it through a timer. Since apps often cancel calls through NEW_OUTGOING_CALL and // then re-dial them quickly using a gateway, allowing the first call to end // causes jank. This timeout allows CallsManager to transition the first call into // the second call so that in-call only ever sees a single call...eliminating the - // jank altogether. + // jank altogether. The app will also be able to set the timeout via an extra on + // the ordered broadcast. for (Listener listener : mListeners) { - if (listener.onCanceledViaNewOutgoingCallBroadcast(this)) { + if (listener.onCanceledViaNewOutgoingCallBroadcast( + this, disconnectionTimeout)) { // The first listener to handle this wins. A return value of true means that // the listener will handle the disconnection process later and so we // should not continue it here. diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java index 78a92eb4..8d64f181 100644 --- a/src/com/android/server/telecom/CallAudioManager.java +++ b/src/com/android/server/telecom/CallAudioManager.java @@ -229,6 +229,9 @@ public class CallAudioManager extends CallsManagerListenerBase { makeArgsForModeStateMachine()); } + // Turn off mute when a new incoming call is answered. + mute(false /* shouldMute */); + maybeStopRingingAndCallWaitingForAnsweredOrRejectedCall(call); } @@ -360,7 +363,8 @@ public class CallAudioManager extends CallsManagerListenerBase { CallAudioRouteStateMachine.TOGGLE_MUTE); } - void mute(boolean shouldMute) { + @VisibleForTesting + public void mute(boolean shouldMute) { Log.v(this, "mute, shouldMute: %b", shouldMute); // Don't mute if there are any emergency calls. diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java index 7b6c2b5f..7f6b82b0 100644 --- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java +++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java @@ -62,6 +62,9 @@ import java.util.HashMap; * mIsMuted: a boolean indicating whether the audio is muted */ public class CallAudioRouteStateMachine extends StateMachine { + private static final String TELECOM_PACKAGE = + CallAudioRouteStateMachine.class.getPackage().getName(); + /** Direct the audio stream through the device's earpiece. */ public static final int ROUTE_EARPIECE = CallAudioState.ROUTE_EARPIECE; @@ -164,6 +167,19 @@ public class CallAudioRouteStateMachine extends StateMachine { String action = intent.getAction(); if (action.equals(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)) { + // We get an this broadcast any time the notification filter is changed, even if + // we are the initiator of the change. + // So, we'll look at who the initiator of the manual zen rule is in the + // notification manager. If its us, then we can just exit now. + String initiator = + mInterruptionFilterProxy.getInterruptionModeInitiator(); + + if (TELECOM_PACKAGE.equals(initiator)) { + // We are the initiator of this change, so ignore it. + Log.i(this, "interruptionFilterChanged - ignoring own change"); + return; + } + if (mAreNotificationSuppressed) { // If we've already set the interruption filter, and the user changes it to // something other than INTERRUPTION_FILTER_ALARMS, assume we will no longer @@ -171,6 +187,8 @@ public class CallAudioRouteStateMachine extends StateMachine { mAreNotificationSuppressed = mInterruptionFilterProxy.getCurrentInterruptionFilter() == NotificationManager.INTERRUPTION_FILTER_ALARMS; + Log.i(this, "interruptionFilterChanged - changing to %b", + mAreNotificationSuppressed); } } } finally { @@ -222,31 +240,34 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public boolean processMessage(Message msg) { + int addedRoutes = 0; + int removedRoutes = 0; + switch (msg.what) { case CONNECT_WIRED_HEADSET: Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE, "Wired headset connected"); - mAvailableRoutes &= ~ROUTE_EARPIECE; - mAvailableRoutes |= ROUTE_WIRED_HEADSET; - return NOT_HANDLED; + removedRoutes |= ROUTE_EARPIECE; + addedRoutes |= ROUTE_WIRED_HEADSET; + break; case CONNECT_BLUETOOTH: Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE, "Bluetooth connected"); - mAvailableRoutes |= ROUTE_BLUETOOTH; - return NOT_HANDLED; + addedRoutes |= ROUTE_BLUETOOTH; + break; case DISCONNECT_WIRED_HEADSET: Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE, "Wired headset disconnected"); - mAvailableRoutes &= ~ROUTE_WIRED_HEADSET; + removedRoutes |= ROUTE_WIRED_HEADSET; if (mDoesDeviceSupportEarpieceRoute) { - mAvailableRoutes |= ROUTE_EARPIECE; + addedRoutes |= ROUTE_EARPIECE; } - return NOT_HANDLED; + break; case DISCONNECT_BLUETOOTH: Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE, "Bluetooth disconnected"); - mAvailableRoutes &= ~ROUTE_BLUETOOTH; - return NOT_HANDLED; + removedRoutes |= ROUTE_BLUETOOTH; + break; case SWITCH_BASELINE_ROUTE: sendInternalMessage(calculateBaselineRouteMessage(false)); return HANDLED; @@ -259,6 +280,14 @@ public class CallAudioRouteStateMachine extends StateMachine { default: return NOT_HANDLED; } + + if (addedRoutes != 0 || removedRoutes != 0) { + mAvailableRoutes = modifyRoutes(mAvailableRoutes, removedRoutes, addedRoutes, true); + mDeviceSupportedRoutes = modifyRoutes(mDeviceSupportedRoutes, removedRoutes, + addedRoutes, false); + } + + return NOT_HANDLED; } // Behavior will depend on whether the state is an active one or a quiescent one. @@ -1112,6 +1141,7 @@ public class CallAudioRouteStateMachine extends StateMachine { * A few pieces of hidden state. Used to avoid exponential explosion of number of explicit * states */ + private int mDeviceSupportedRoutes; private int mAvailableRoutes; private int mAudioFocusType; private boolean mWasOnSpeaker; @@ -1201,9 +1231,15 @@ public class CallAudioRouteStateMachine extends StateMachine { } public void initialize(CallAudioState initState) { + if ((initState.getRoute() & getCurrentCallSupportedRoutes()) == 0) { + Log.e(this, new IllegalArgumentException(), "Route %d specified when supported call" + + " routes are: %d", initState.getRoute(), getCurrentCallSupportedRoutes()); + } + mCurrentCallAudioState = initState; mLastKnownCallAudioState = initState; - mAvailableRoutes = initState.getSupportedRouteMask(); + mDeviceSupportedRoutes = initState.getSupportedRouteMask(); + mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes(); mIsMuted = initState.isMuted(); mWasOnSpeaker = false; @@ -1261,6 +1297,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return; case UPDATE_SYSTEM_AUDIO_ROUTE: + updateRouteForForegroundCall(); resendSystemAudioState(); return; case RUN_RUNNABLE: @@ -1460,7 +1497,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } private CallAudioState getInitialAudioState() { - int supportedRouteMask = calculateSupportedRoutes(); + int supportedRouteMask = calculateSupportedRoutes() & getCurrentCallSupportedRoutes(); final int route; if ((supportedRouteMask & ROUTE_BLUETOOTH) != 0) { @@ -1513,19 +1550,15 @@ public class CallAudioRouteStateMachine extends StateMachine { return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE; } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { return isExplicitUserRequest ? USER_SWITCH_HEADSET : SWITCH_HEADSET; - } else if (!mDoesDeviceSupportEarpieceRoute) { - return isExplicitUserRequest ? USER_SWITCH_SPEAKER : SWITCH_SPEAKER; } else { - Log.e(this, new IllegalStateException(), - "Neither headset nor earpiece are available, but there is an " + - "earpiece on the device. Defaulting to earpiece."); - return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE; + return isExplicitUserRequest ? USER_SWITCH_SPEAKER : SWITCH_SPEAKER; } } private void reinitialize() { CallAudioState initState = getInitialAudioState(); - mAvailableRoutes = initState.getSupportedRouteMask(); + mDeviceSupportedRoutes = initState.getSupportedRouteMask(); + mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes(); mIsMuted = initState.isMuted(); setMuteOn(mIsMuted); mWasOnSpeaker = false; @@ -1533,4 +1566,37 @@ public class CallAudioRouteStateMachine extends StateMachine { mLastKnownCallAudioState = initState; transitionTo(mRouteCodeToQuiescentState.get(initState.getRoute())); } + + private void updateRouteForForegroundCall() { + mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes(); + + CallAudioState currentState = getCurrentCallAudioState(); + + // Move to baseline route in the case the current route is no longer available. + if ((mAvailableRoutes & currentState.getRoute()) == 0) { + sendInternalMessage(calculateBaselineRouteMessage(false)); + } + } + + private int getCurrentCallSupportedRoutes() { + int supportedRoutes = CallAudioState.ROUTE_ALL; + + if (mCallsManager.getForegroundCall() != null) { + supportedRoutes &= mCallsManager.getForegroundCall().getSupportedAudioRoutes(); + } + + return supportedRoutes; + } + + private int modifyRoutes(int base, int remove, int add, boolean considerCurrentCall) { + base &= ~remove; + + if (considerCurrentCall) { + add &= getCurrentCallSupportedRoutes(); + } + + base |= add; + + return base; + } } diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java index 461501db..fb2129e6 100644 --- a/src/com/android/server/telecom/CallsManager.java +++ b/src/com/android/server/telecom/CallsManager.java @@ -437,9 +437,13 @@ public class CallsManager extends Call.ListenerBase if (result.shouldAllowCall) { if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) { - Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " + - "ringing calls."); - rejectCallAndLog(incomingCall); + if (shouldSilenceInsteadOfReject(incomingCall)) { + incomingCall.silence(); + } else { + Log.i(this, "onCallFilteringCompleted: Call rejected! " + + "Exceeds maximum number of ringing calls."); + rejectCallAndLog(incomingCall); + } } else if (hasMaximumDialingCalls()) { Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " + "dialing calls."); @@ -502,6 +506,37 @@ public class CallsManager extends Call.ListenerBase return (state == CallState.RINGING); } + /** + * Whether allow (silence rather than reject) the incoming call if it has a different source + * (connection service) from the existing ringing call when reaching maximum ringing calls. + */ + private boolean shouldSilenceInsteadOfReject(Call incomingCall) { + if (!mContext.getResources().getBoolean( + R.bool.silence_incoming_when_different_service_and_maximum_ringing)) { + return false; + } + + Call ringingCall = null; + + for (Call call : mCalls) { + // Only operate on top-level calls + if (call.getParentCall() != null) { + continue; + } + + if (call.isExternalCall()) { + continue; + } + + if (CallState.RINGING == call.getState() && + call.getConnectionService() == incomingCall.getConnectionService()) { + return false; + } + } + + return true; + } + @Override public void onFailedIncomingCall(Call call) { setCallState(call, CallState.DISCONNECTED, "failed incoming call"); @@ -603,7 +638,8 @@ public class CallsManager extends Call.ListenerBase } @Override - public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call) { + public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call, + long disconnectionTimeout) { mPendingCallsToDisconnect.add(call); mHandler.postDelayed(new Runnable("CM.oCVNOCB", mLock) { @Override @@ -613,7 +649,7 @@ public class CallsManager extends Call.ListenerBase call.disconnect(); } } - }.prepare(), Timeouts.getNewOutgoingCallCancelMillis(mContext.getContentResolver())); + }.prepare(), disconnectionTimeout); return true; } diff --git a/src/com/android/server/telecom/InterruptionFilterProxy.java b/src/com/android/server/telecom/InterruptionFilterProxy.java index 434c3413..b659de8f 100644 --- a/src/com/android/server/telecom/InterruptionFilterProxy.java +++ b/src/com/android/server/telecom/InterruptionFilterProxy.java @@ -24,4 +24,5 @@ package com.android.server.telecom; public interface InterruptionFilterProxy { void setInterruptionFilter(int interruptionFilter); int getCurrentInterruptionFilter(); + String getInterruptionModeInitiator(); } diff --git a/src/com/android/server/telecom/Log.java b/src/com/android/server/telecom/Log.java index 2282ff01..9903eecf 100644 --- a/src/com/android/server/telecom/Log.java +++ b/src/com/android/server/telecom/Log.java @@ -125,6 +125,9 @@ public class Log { public static final String STOP_DTMF = "STOP_DTMF"; public static final String START_RINGER = "START_RINGER"; public static final String STOP_RINGER = "STOP_RINGER"; + public static final String START_VIBRATOR = "START_VIBRATOR"; + public static final String STOP_VIBRATOR = "STOP_VIBRATOR"; + public static final String SKIP_VIBRATION = "SKIP_VIBRATION"; public static final String SKIP_RINGING = "SKIP_RINGING"; public static final String START_CALL_WAITING_TONE = "START_CALL_WAITING_TONE"; public static final String STOP_CALL_WAITING_TONE = "STOP_CALL_WAITING_TONE"; diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java index 94b52203..bb747258 100644 --- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java +++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; +import android.os.Bundle; import android.os.Trace; import android.os.UserHandle; import android.telecom.GatewayInfo; @@ -114,19 +115,24 @@ public class NewOutgoingCallIntentBroadcaster { Log.pii(resultNumber)); boolean endEarly = false; + long disconnectTimeout = + Timeouts.getNewOutgoingCallCancelMillis(mContext.getContentResolver()); if (resultNumber == null) { Log.v(this, "Call cancelled (null number), returning..."); + disconnectTimeout = getDisconnectTimeoutFromApp( + getResultExtras(false), disconnectTimeout); endEarly = true; } else if (TelephonyUtil.isPotentialLocalEmergencyNumber( mPhoneNumberUtilsAdapter, mContext, resultNumber)) { Log.w(this, "Cannot modify outgoing call to emergency number %s.", resultNumber); + disconnectTimeout = 0; endEarly = true; } if (endEarly) { if (mCall != null) { - mCall.disconnect(true /* wasViaNewOutgoingCall */); + mCall.disconnect(disconnectTimeout); } return; } @@ -471,4 +477,18 @@ public class NewOutgoingCallIntentBroadcaster { intent.setAction(action); } } + + private long getDisconnectTimeoutFromApp(Bundle resultExtras, long defaultTimeout) { + if (resultExtras != null) { + long disconnectTimeout = resultExtras.getLong( + TelecomManager.EXTRA_NEW_OUTGOING_CALL_CANCEL_TIMEOUT, defaultTimeout); + if (disconnectTimeout < 0) { + disconnectTimeout = 0; + } + return Math.min(disconnectTimeout, + Timeouts.getMaxNewOutgoingCallCancelMillis(mContext.getContentResolver())); + } else { + return defaultTimeout; + } + } } diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java index 288f48cf..2880aa11 100644 --- a/src/com/android/server/telecom/ParcelableCallUtils.java +++ b/src/com/android/server/telecom/ParcelableCallUtils.java @@ -88,6 +88,8 @@ public class ParcelableCallUtils { } int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities()); int properties = convertConnectionToCallProperties(call.getConnectionProperties()); + int supportedAudioRoutes = call.getSupportedAudioRoutes(); + if (call.isConference()) { properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE; } @@ -154,8 +156,9 @@ public class ParcelableCallUtils { call.getCannedSmsResponses(), capabilities, properties, - connectTimeMillis, call.getCreationTimeMillis(), + supportedAudioRoutes, + connectTimeMillis, handle, call.getHandlePresentation(), callerDisplayName, diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java index da0b023b..122036bb 100644 --- a/src/com/android/server/telecom/PhoneAccountRegistrar.java +++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java @@ -35,6 +35,7 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.telecom.CallAudioState; import android.telecom.ConnectionService; import android.telecom.DefaultDialerManager; import android.telecom.PhoneAccount; @@ -1562,6 +1563,7 @@ public class PhoneAccountRegistrar { private static final String ADDRESS = "handle"; private static final String SUBSCRIPTION_ADDRESS = "subscription_number"; private static final String CAPABILITIES = "capabilities"; + private static final String SUPPORTED_AUDIO_ROUTES = "supported_audio_routes"; private static final String ICON_RES_ID = "icon_res_id"; private static final String ICON_PACKAGE_NAME = "icon_package_name"; private static final String ICON_BITMAP = "icon_bitmap"; @@ -1597,6 +1599,8 @@ public class PhoneAccountRegistrar { writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer); writeBundle(EXTRAS, o.getExtras(), serializer); writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer); + writeTextIfNonNull(SUPPORTED_AUDIO_ROUTES, Integer.toString( + o.getSupportedAudioRoutes()), serializer); serializer.endTag(null, CLASS_PHONE_ACCOUNT); } @@ -1610,6 +1614,7 @@ public class PhoneAccountRegistrar { Uri address = null; Uri subscriptionAddress = null; int capabilities = 0; + int supportedAudioRoutes = 0; int iconResId = PhoneAccount.NO_RESOURCE_ID; String iconPackageName = null; Bitmap iconBitmap = null; @@ -1668,6 +1673,9 @@ public class PhoneAccountRegistrar { enabled = "true".equalsIgnoreCase(parser.getText()); } else if (parser.getName().equals(EXTRAS)) { extras = readBundle(parser); + } else if (parser.getName().equals(SUPPORTED_AUDIO_ROUTES)) { + parser.next(); + supportedAudioRoutes = Integer.parseInt(parser.getText()); } } @@ -1726,10 +1734,16 @@ public class PhoneAccountRegistrar { } } + if (version < 9) { + // Set supported audio routes to all by default + supportedAudioRoutes = CallAudioState.ROUTE_ALL; + } + PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label) .setAddress(address) .setSubscriptionAddress(subscriptionAddress) .setCapabilities(capabilities) + .setSupportedAudioRoutes(supportedAudioRoutes) .setShortDescription(shortDescription) .setSupportedUriSchemes(supportedUriSchemes) .setHighlightColor(highlightColor) diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java index f53f212c..4bb43ae4 100644 --- a/src/com/android/server/telecom/Ringer.java +++ b/src/com/android/server/telecom/Ringer.java @@ -64,9 +64,11 @@ public class Ringer { private RingtoneFactory mRingtoneFactory; /** - * Call objects that are ringing or call-waiting. These are used only for logging purposes. + * Call objects that are ringing, vibrating or call-waiting. These are used only for logging + * purposes. */ private Call mRingingCall; + private Call mVibratingCall; private Call mCallWaitingCall; /** @@ -146,10 +148,13 @@ public class Ringer { Log.i(this, "startRingingOrCallWaiting, skipping because volume is 0"); } - if (vibrationAllowed && shouldVibrate(mContext) && !mIsVibrating) { + if (vibrationAllowed && shouldVibrate(mContext, foregroundCall) && !mIsVibrating) { + mVibratingCall = foregroundCall; mVibrator.vibrate(VIBRATION_PATTERN, VIBRATION_PATTERN_REPEAT, VIBRATION_ATTRIBUTES); mIsVibrating = true; + } else if (mIsVibrating) { + Log.event(foregroundCall, Log.Events.SKIP_VIBRATION, "already vibrating"); } return isRingerAudible; @@ -187,8 +192,10 @@ public class Ringer { mRingtonePlayer.stop(); if (mIsVibrating) { + Log.event(mVibratingCall, Log.Events.STOP_VIBRATOR); mVibrator.cancel(); mIsVibrating = false; + mVibratingCall = null; } } @@ -215,14 +222,31 @@ public class Ringer { return manager.matchesCallFilter(extras); } - private boolean shouldVibrate(Context context) { + private boolean shouldVibrate(Context context, Call call) { AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); int ringerMode = audioManager.getRingerModeInternal(); + boolean shouldVibrate; if (getVibrateWhenRinging(context)) { - return ringerMode != AudioManager.RINGER_MODE_SILENT; + shouldVibrate = ringerMode != AudioManager.RINGER_MODE_SILENT; } else { - return ringerMode == AudioManager.RINGER_MODE_VIBRATE; + shouldVibrate = ringerMode == AudioManager.RINGER_MODE_VIBRATE; } + + // Technically this should be in the calling method, but it seemed a little odd to pass + // around a whole bunch of state just for logging purposes. + if (shouldVibrate) { + Log.event(call, Log.Events.START_VIBRATOR, + "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", + mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context), + ringerMode, mIsVibrating); + } else { + Log.event(call, Log.Events.SKIP_VIBRATION, + "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b", + mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context), + ringerMode, mIsVibrating); + } + + return shouldVibrate; } private boolean getVibrateWhenRinging(Context context) { diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java index 7be59c3a..b2f4b6dd 100644 --- a/src/com/android/server/telecom/Timeouts.java +++ b/src/com/android/server/telecom/Timeouts.java @@ -63,7 +63,16 @@ public final class Timeouts { * in-call UI. */ public static long getNewOutgoingCallCancelMillis(ContentResolver contentResolver) { - return get(contentResolver, "new_outgoing_call_cancel_ms", 100000L); + return get(contentResolver, "new_outgoing_call_cancel_ms", 500L); + } + + /** + * Returns the maximum amount of time to wait before disconnecting a call that was canceled via + * NEW_OUTGOING_CALL broadcast. This prevents malicious or poorly configured apps from + * forever tying up the Telecom stack. + */ + public static long getMaxNewOutgoingCallCancelMillis(ContentResolver contentResolver) { + return get(contentResolver, "max_new_outgoing_call_cancel_ms", 10000L); } /** diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java index ef5bf96e..f6080f84 100644 --- a/src/com/android/server/telecom/components/TelecomService.java +++ b/src/com/android/server/telecom/components/TelecomService.java @@ -26,6 +26,7 @@ import android.media.IAudioService; import android.os.IBinder; import android.os.PowerManager; import android.os.ServiceManager; +import android.service.notification.ZenModeConfig; import com.android.internal.telephony.CallerInfoAsyncQuery; import com.android.server.telecom.AsyncRingtonePlayer; @@ -179,6 +180,15 @@ public class TelecomService extends Service implements TelecomSystem.Component { public int getCurrentInterruptionFilter() { return notificationManager.getCurrentInterruptionFilter(); } + + @Override + public String getInterruptionModeInitiator() { + ZenModeConfig config = notificationManager.getZenModeConfig(); + if (config.manualRule != null) { + return config.manualRule.enabler; + } + return null; + } } )); } diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java index b9cc2510..38074ced 100644 --- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java +++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java @@ -142,7 +142,6 @@ public class MissedCallNotifierImpl extends CallsManagerListenerBase implements private final PhoneAccountRegistrar mPhoneAccountRegistrar; private final NotificationManager mNotificationManager; private final NotificationBuilderFactory mNotificationBuilderFactory; - private final ComponentName mNotificationComponent; private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; private UserHandle mCurrentUserHandle; @@ -164,11 +163,8 @@ public class MissedCallNotifierImpl extends CallsManagerListenerBase implements mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - final String notificationComponent = context.getString(R.string.notification_component); mNotificationBuilderFactory = notificationBuilderFactory; - mNotificationComponent = notificationComponent != null - ? ComponentName.unflattenFromString(notificationComponent) : null; mMissedCallCounts = new ConcurrentHashMap<>(); } @@ -210,44 +206,6 @@ public class MissedCallNotifierImpl extends CallsManagerListenerBase implements } /** - * Broadcasts missed call notification to custom component if set. - * Currently the component is set in phone capable android wear device. - * @param userHandle The user that has the missed call(s). - * @return {@code true} if the broadcast was sent. {@code false} otherwise. - */ - private boolean sendNotificationCustomComponent(Call call, UserHandle userHandle) { - if (mNotificationComponent != null) { - int count = mMissedCallCounts.get(userHandle).get(); - Intent intent = new Intent(); - intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); - intent.setComponent(mNotificationComponent); - intent.setAction(TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION); - intent.putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, count); - intent.putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER, - call != null ? call.getPhoneNumber() : null); - intent.putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT, - createClearMissedCallsPendingIntent(userHandle)); - - - if (count == 1 && call != null) { - final Uri handleUri = call.getHandle(); - String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart(); - - if (!TextUtils.isEmpty(handle) && !TextUtils.equals(handle, - mContext.getString(R.string.handle_restricted))) { - intent.putExtra(TelecomManager.EXTRA_CALL_BACK_INTENT, - createCallBackPendingIntent(handleUri, userHandle)); - } - } - - mContext.sendBroadcast(intent); - return true; - } - - return false; - } - - /** * Returns the missed-call notificatino intent to send to the default dialer for the given user. * Note, the passed in userHandle is always the non-managed user for SIM calls (multi-user * calls). In this case we return the default dialer for the logged in user. This is never the * managed (work profile) dialer. @@ -281,10 +239,24 @@ public class MissedCallNotifierImpl extends CallsManagerListenerBase implements int count = mMissedCallCounts.get(userHandle).get(); Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle) .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) + .putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT, + createClearMissedCallsPendingIntent(userHandle)) .putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, count) .putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER, call != null ? call.getPhoneNumber() : null); + if (count == 1 && call != null) { + final Uri handleUri = call.getHandle(); + String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart(); + + if (!TextUtils.isEmpty(handle) && !TextUtils.equals(handle, + mContext.getString(R.string.handle_restricted))) { + intent.putExtra(TelecomManager.EXTRA_CALL_BACK_INTENT, + createCallBackPendingIntent(handleUri, userHandle)); + } + } + + Log.w(this, "Showing missed calls through default dialer."); mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE); } @@ -313,10 +285,6 @@ public class MissedCallNotifierImpl extends CallsManagerListenerBase implements mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0)); int missCallCounts = mMissedCallCounts.get(userHandle).incrementAndGet(); - if (sendNotificationCustomComponent(call, userHandle)) { - return; - } - if (shouldManageNotificationThroughDefaultDialer(userHandle)) { sendNotificationThroughDefaultDialer(call, userHandle); return; @@ -429,10 +397,6 @@ public class MissedCallNotifierImpl extends CallsManagerListenerBase implements mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0)); mMissedCallCounts.get(userHandle).set(0); - if (sendNotificationCustomComponent(null, userHandle)) { - return; - } - if (shouldManageNotificationThroughDefaultDialer(userHandle)) { sendNotificationThroughDefaultDialer(null, userHandle); return; diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java index 81d4aa5b..021ce82f 100644 --- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java +++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java @@ -36,6 +36,7 @@ import com.android.server.telecom.TelecomLogClass; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -337,6 +338,26 @@ public class AnalyticsTests extends TelecomSystemTest { analyticsProto.callLogs[0].getConnectionProperties() & expectedProperties); } + @SmallTest + public void testAnalyticsMaxSize() throws Exception { + Analytics.reset(); + for (int i = 0; i < Analytics.MAX_NUM_CALLS_TO_STORE * 2; i++) { + Analytics.initiateCallAnalytics(String.valueOf(i), Analytics.INCOMING_DIRECTION) + .addCallTechnology(i); + } + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Analytics.dumpToEncodedProto(pw, new String[]{}); + TelecomLogClass.TelecomLog analyticsProto = + TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT)); + + assertEquals(Analytics.MAX_NUM_CALLS_TO_STORE, analyticsProto.callLogs.length); + assertEquals(Arrays.stream(analyticsProto.callLogs) + .filter(x -> x.getCallTechnologies() < 100) + .count(), 0); + } + private void assertIsRoundedToOneSigFig(long x) { assertEquals(x, Analytics.roundToOneSigFig(x)); } diff --git a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java index 34325f0a..488ac296 100644 --- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java +++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java @@ -36,10 +36,13 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import java.util.LinkedHashSet; +import java.util.List; +import java.util.stream.Collectors; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -79,6 +82,69 @@ public class CallAudioManagerTest extends TelecomTestCase { } @MediumTest + public void testUnmuteOfSecondIncomingCall() { + // Start with a single incoming call. + Call call = createIncomingCall(); + when(call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) + .thenReturn(false); + when(call.getId()).thenReturn("1"); + + ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = + ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class); + // Answer the incoming call + mCallAudioManager.onIncomingCallAnswered(call); + when(call.getState()).thenReturn(CallState.ACTIVE); + mCallAudioManager.onCallStateChanged(call, CallState.RINGING, CallState.ACTIVE); + verify(mCallAudioModeStateMachine).sendMessageWithArgs( + eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture()); + CallAudioModeStateMachine.MessageArgs correctArgs = + new CallAudioModeStateMachine.MessageArgs( + true, // hasActiveOrDialingCalls + false, // hasRingingCalls + false, // hasHoldingCalls + false, // isTonePlaying + false, // foregroundCallIsVoip + null // session + ); + assertMessageArgEquality(correctArgs, captor.getValue()); + verify(mCallAudioModeStateMachine).sendMessageWithArgs( + eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture()); + assertMessageArgEquality(correctArgs, captor.getValue()); + + // Mute the current ongoing call. + mCallAudioManager.mute(true); + + // Create a second incoming call. + Call call2 = mock(Call.class); + when(call2.getState()).thenReturn(CallState.RINGING); + when(call2.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) + .thenReturn(false); + when(call2.getId()).thenReturn("2"); + mCallAudioManager.onCallAdded(call2); + + // Answer the incoming call + mCallAudioManager.onIncomingCallAnswered(call); + + // Capture the calls to sendMessageWithSessionInfo; we want to look for mute on and off + // messages and make sure that there was a mute on before the mute off. + ArgumentCaptor<Integer> muteCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mCallAudioRouteStateMachine, atLeastOnce()) + .sendMessageWithSessionInfo(muteCaptor.capture()); + List<Integer> values = muteCaptor.getAllValues(); + values = values.stream() + .filter(value -> value == CallAudioRouteStateMachine.MUTE_ON || + value == CallAudioRouteStateMachine.MUTE_OFF) + .collect(Collectors.toList()); + + // Make sure we got a mute on and a mute off. + assertTrue(values.contains(CallAudioRouteStateMachine.MUTE_ON)); + assertTrue(values.contains(CallAudioRouteStateMachine.MUTE_OFF)); + // And that the mute on happened before the off. + assertTrue(values.indexOf(CallAudioRouteStateMachine.MUTE_ON) < values + .lastIndexOf(CallAudioRouteStateMachine.MUTE_OFF)); + } + + @MediumTest public void testSingleIncomingCallFlowWithoutMTSpeedUp() { Call call = createIncomingCall(); when(call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java index dddf9e69..0766b722 100644 --- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java +++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java @@ -86,6 +86,8 @@ public class CallAudioRouteStateMachineTest public boolean doesDeviceSupportEarpiece; // set to false in the case of Wear devices public boolean shouldRunWithFocus; + public int callSupportedRoutes = CallAudioState.ROUTE_ALL; + public RoutingTestParameters(String name, int initialRoute, int initialNotificationFilter, int availableRoutes, int speakerInteraction, int bluetoothInteraction, int action, int expectedRoute, @@ -107,6 +109,11 @@ public class CallAudioRouteStateMachineTest this.shouldRunWithFocus = shouldRunWithFocus; } + public RoutingTestParameters setCallSupportedRoutes(int routes) { + callSupportedRoutes = routes; + return this; + } + @Override public String toString() { return "RoutingTestParameters{" + @@ -159,6 +166,7 @@ public class CallAudioRouteStateMachineTest when(mockCallsManager.getLock()).thenReturn(mLock); when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper); when(fakeCall.isAlive()).thenReturn(true); + when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL); setupInterruptionFilterMocks(); doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class), @@ -878,6 +886,38 @@ public class CallAudioRouteStateMachineTest shouldRunWithFocus )); + params.add(new RoutingTestParameters( + "Disconnect wired headset when call doesn't support earpiece", // name + CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute + NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter + CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes + ON, // speakerInteraction + NONE, // bluetoothInteraction + CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action + CallAudioState.ROUTE_SPEAKER, // expectedRoute + CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes + NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter + false, // isNotificationChangeExpected + true, // doesDeviceSupportEarpiece + shouldRunWithFocus + ).setCallSupportedRoutes(CallAudioState.ROUTE_ALL & ~CallAudioState.ROUTE_EARPIECE)); + + params.add(new RoutingTestParameters( + "Disconnect bluetooth when call does not support earpiece", // name + CallAudioState.ROUTE_BLUETOOTH, // initialRoute + NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter + CallAudioState.ROUTE_BLUETOOTH, // availableRoutes + ON, // speakerInteraction + OFF, // bluetoothInteraction + CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action + CallAudioState.ROUTE_SPEAKER, // expectedRoute + CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes + NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter + false, // isNotificationChangeExpected + true, // doesDeviceSupportEarpiece + shouldRunWithFocus + ).setCallSupportedRoutes(CallAudioState.ROUTE_ALL & ~CallAudioState.ROUTE_EARPIECE)); + return params; } @@ -916,6 +956,7 @@ public class CallAudioRouteStateMachineTest || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0); doReturn(params.initialRoute == CallAudioState.ROUTE_SPEAKER).when(mockAudioManager). isSpeakerphoneOn(); + when(fakeCall.getSupportedAudioRoutes()).thenReturn(params.callSupportedRoutes); // Set the initial CallAudioState object final CallAudioState initState = new CallAudioState(false, @@ -999,6 +1040,7 @@ public class CallAudioRouteStateMachineTest || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0); when(mockAudioManager.isSpeakerphoneOn()).thenReturn( params.initialRoute == CallAudioState.ROUTE_SPEAKER); + when(fakeCall.getSupportedAudioRoutes()).thenReturn(params.callSupportedRoutes); // Set the initial CallAudioState object CallAudioState initState = new CallAudioState(false, @@ -1051,10 +1093,13 @@ public class CallAudioRouteStateMachineTest private void resetMocks() { reset(mockAudioManager, mockBluetoothManager, mockCallsManager, - mockConnectionServiceWrapper, mMockInterruptionFilterProxy); + mockConnectionServiceWrapper, mMockInterruptionFilterProxy, fakeCall); mMockInterruptionFilterProxy = mock(InterruptionFilterProxy.class); setupInterruptionFilterMocks(); when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall); + when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper); + when(fakeCall.isAlive()).thenReturn(true); + when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL); when(mockCallsManager.getLock()).thenReturn(mLock); doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class), any(CallAudioState.class)); diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java index 65e0d7f7..698da266 100644 --- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java +++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java @@ -336,6 +336,7 @@ public class ConnectionServiceFixture implements TestFixture<IConnectionService> int addressPresentation; int capabilities; int properties; + int supportedAudioRoutes; StatusHints statusHints; DisconnectCause disconnectCause; String conferenceId; @@ -597,6 +598,7 @@ public class ConnectionServiceFixture implements TestFixture<IConnectionService> c.state, c.capabilities, c.properties, + c.supportedAudioRoutes, c.request.getAddress(), c.addressPresentation, c.callerDisplayName, diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java index 54613d47..9b7dc375 100644 --- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java +++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java @@ -313,7 +313,28 @@ public class NewOutgoingCallIntentBroadcasterTest extends TelecomTestCase { result.receiver.onReceive(mContext, result.intent); verifyNoCallPlaced(); - verify(mCall).disconnect(true); + ArgumentCaptor<Long> timeoutCaptor = ArgumentCaptor.forClass(Long.class); + verify(mCall).disconnect(timeoutCaptor.capture()); + assertTrue(timeoutCaptor.getValue() > 0); + } + + @SmallTest + public void testCallNumberModifiedToNullWithLongCustomTimeout() { + Uri handle = Uri.parse("tel:6505551234"); + Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null); + ReceiverIntentPair result = regularCallTestHelper(callIntent, null); + + long customTimeout = 100000000; + Bundle bundle = new Bundle(); + bundle.putLong(TelecomManager.EXTRA_NEW_OUTGOING_CALL_CANCEL_TIMEOUT, customTimeout); + result.receiver.setResultData(null); + result.receiver.setResultExtras(bundle); + + result.receiver.onReceive(mContext, result.intent); + verifyNoCallPlaced(); + ArgumentCaptor<Long> timeoutCaptor = ArgumentCaptor.forClass(Long.class); + verify(mCall).disconnect(timeoutCaptor.capture()); + assertTrue(timeoutCaptor.getValue() < customTimeout); } @SmallTest @@ -328,7 +349,7 @@ public class NewOutgoingCallIntentBroadcasterTest extends TelecomTestCase { doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber( any(Context.class), eq(newEmergencyNumber)); result.receiver.onReceive(mContext, result.intent); - verify(mCall).disconnect(true); + verify(mCall).disconnect(eq(0L)); } private ReceiverIntentPair regularCallTestHelper(Intent intent, diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java index fab45405..cf17b5c1 100644 --- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java +++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java @@ -182,6 +182,11 @@ public class TelecomSystemTest extends TelecomTestCase { public int getCurrentInterruptionFilter() { return mInterruptionFilter; } + + @Override + public String getInterruptionModeInitiator() { + return "com.android.server.telecom"; + } } @Mock HeadsetMediaButton mHeadsetMediaButton; |