Merge "Modified not to occur NPE when handle call of failed connection"
diff --git a/Android.bp b/Android.bp
index b7eb450..88cffb8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,6 +25,9 @@
":Telecom-srcs",
"proto/**/*.proto",
],
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
resource_dirs: ["res"],
proto: {
type: "nano",
@@ -37,7 +40,6 @@
optimize: {
proguard_flags_files: ["proguard.flags"],
},
- defaults: ["SettingsLibDefaults"],
}
android_test {
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 327d0a2..0776e9d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -47,6 +47,7 @@
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
<uses-permission android:name="android.permission.VIBRATE"/>
@@ -55,6 +56,7 @@
<uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS"/>
<uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"/>
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
+ <uses-permission android:name="com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID"/>
<permission android:name="android.permission.BROADCAST_CALLLOG_INFO"
android:label="Broadcast the call type/duration information"
@@ -165,6 +167,7 @@
<activity-alias android:name="PrivilegedCallActivity"
android:targetActivity=".components.UserCallActivity"
android:permission="android.permission.CALL_PRIVILEGED"
+ android:exported="true"
android:process=":ui">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.CALL_PRIVILEGED"/>
@@ -200,6 +203,7 @@
<activity-alias android:name="EmergencyCallActivity"
android:targetActivity=".components.UserCallActivity"
android:permission="android.permission.CALL_PRIVILEGED"
+ android:exported="true"
android:process=":ui">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.CALL_EMERGENCY"/>
diff --git a/res/raw/InCallQualityNotification.ogg b/res/raw/InCallQualityNotification.ogg
new file mode 100644
index 0000000..84c029a
--- /dev/null
+++ b/res/raw/InCallQualityNotification.ogg
Binary files differ
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 2857be3..0775323 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Oproepbestuur"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Foonoproepe"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Bel"</string>
<string name="unknown" msgid="6993977514360123431">"Onbekend"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Gemiste oproep"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokkeer oproepe vanaf telefoonhokkies"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Onbekend"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokkeer oproepe vanaf onbekende bellers"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Oproepblokkering"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Oproepblokkering is gedeaktiveer"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Noodoproep gemaak"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Oproepblokkering is gedeaktiveer sodat noodeenhede jou kan kontak."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom-ontwikkelaarkieslys"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Oproepe kan nie gedurende \'n noodoproep geneem word nie."</string>
+ <string name="cancel" msgid="6733466216239934756">"Kanselleer"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index df8215c..a539414 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"የጥሪ አስተዳደር"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"የስልክ ጥሪዎች"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ስልክ"</string>
<string name="unknown" msgid="6993977514360123431">"ያልታወቀ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ያመለጠጥሪ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"የክፍያ ስልኮች የሚመጡ ጥሪዎችን አግድ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ያልታወቀ"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ካልታወቁ ደዋዮች የሚመጡ ጥሪዎችን አግድ"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ጥሪን ማገድ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ጥሪ ማገድ ተሰናክሏል"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"የአደጋ ጊዜ ጥሪ ተደርጓል"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"የአደጋ ጊዜ ምላሽ ሰጪዎች እርስዎን ለማግኘት እንዲችሉ ጥሪ ማገድ ተሰናክሏል።"</string>
<string name="developer_title" msgid="9146088855661672353">"የቴሌኮም ገንቢ ምናሌ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ጥሪዎች በአደጋ ጊዜ ጥሪ ላይ ሊነሱ አይችሉም።"</string>
+ <string name="cancel" msgid="6733466216239934756">"ይቅር"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 7e204d0..454b8b0 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"إدارة المكالمات"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"مكالمات هاتفية"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"الهاتف"</string>
<string name="unknown" msgid="6993977514360123431">"غير معروف"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"مكالمة فائتة"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"حظر المكالمات من الهواتف المدفوعة"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"غير معروف"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"حظر المكالمات من المتّصلين مجهولي الهوية"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"حظر المكالمات"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"تم إيقاف حظر المكالمات"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"تم إجراء مكالمة طوارئ"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"تم إيقاف حظر المكالمات للسماح لمسؤولي استجابة الطوارئ بالاتصال بك."</string>
<string name="developer_title" msgid="9146088855661672353">"قائمة مطوّر برامج الاتصالات"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"لا يمكن تلقّي المكالمات أثناء إجراء مكالمة طوارئ."</string>
+ <string name="cancel" msgid="6733466216239934756">"إلغاء"</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 2f5de68..048a07f 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"কল পৰিচালনা"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ফ’ন কল"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ফ’ন"</string>
<string name="unknown" msgid="6993977514360123431">"অজ্ঞাত"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"মিছ্ড কল"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"পে\'ফ\'নৰ পৰা অহা কল অৱৰোধ কৰক"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"অজ্ঞাত"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"অচিনাক্ত কল কৰোঁতাৰ পৰা অহা কল অৱৰোধ কৰক"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"কল অৱৰোধ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"কল অৱৰোধ সুবিধাটো অক্ষম কৰি থোৱা আছে"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"জৰুৰীকালীন কল ম\'ড"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"আপোনাক যাতে জৰুৰীকালীন সেৱা প্ৰদানকাৰীসকলে যোগাযোগ কৰিব পাৰে তাৰ বাবে কল অৱৰোধ সুবিধাটো অক্ষম কৰি থোৱা হৈছে।"</string>
<string name="developer_title" msgid="9146088855661672353">"দূৰ-সংযোগ সম্পৰ্কীয় বিকাশকৰ্তাৰ মেনু"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"কোনো জৰুৰীকালীন কলত থাকিলে কলসমূহ গ্ৰহণ কৰিব নোৱাৰি।"</string>
+ <string name="cancel" msgid="6733466216239934756">"বাতিল কৰক"</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index d79343f..c32bc7c 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Zənglərin İdarə Olunması"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefon Zəngləri"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Naməlum"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Buraxılmış zəng"</string>
@@ -96,16 +96,16 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"Başqa bir tətbiqdəki zəng səbəbilə çağrı edilə bilməz."</string>
<string name="notification_channel_incoming_call" msgid="5245550964701715662">"Gələn zənglər"</string>
<string name="notification_channel_missed_call" msgid="7168893015283909012">"Buraxılmış zənglər"</string>
- <string name="notification_channel_call_blocking" msgid="2028807677868598710">"Zəngi Bloklama"</string>
+ <string name="notification_channel_call_blocking" msgid="2028807677868598710">"Zəng bloklanması"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Arxa fon zəngləri"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Əlaqəsi kəsilmiş zənglər"</string>
- <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Xəta baş verən telefon tətbiqləri"</string>
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Kəsilmiş zənglər"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Tətbiq xətaları"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Bu zəngin yerləşdirilməsi <xliff:g id="OTHER_APP">%1$s</xliff:g> zəngini sonlandıracaq."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Bu zəngi necə etməyi seçin"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"<xliff:g id="OTHER_APP">%1$s</xliff:g> istifadə edərək zəngi yönləndirin"</string>
<string name="alert_place_unredirect_outgoing_call" msgid="2467608535225764006">"Telefon nömrəmdən istifadə edərək zəng edin"</string>
<string name="alert_redirect_outgoing_call_timeout" msgid="5568101425637373060">"<xliff:g id="OTHER_APP">%1$s</xliff:g> ilə zəng etmək mümkün deyil. Başqa zəng yönləndirmə tətbiqindən istifadə edin və ya yardım üçün developerlə əlaqə saxlayın."</string>
- <string name="phone_settings_call_blocking_txt" msgid="7311523114822507178">"Zəngi Bloklama"</string>
+ <string name="phone_settings_call_blocking_txt" msgid="7311523114822507178">"Zəng bloklanması"</string>
<string name="phone_settings_number_not_in_contact_txt" msgid="2602249106007265757">"Kontaktda olmayan nömrələr"</string>
<string name="phone_settings_number_not_in_contact_summary_txt" msgid="963327038085718969">"Kontaktda göstərilməyən nömrələri blok edin"</string>
<string name="phone_settings_private_num_txt" msgid="6339272760338475619">"Şəxsi"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Ödənişli telefon zənglərini blok edin"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Naməlum"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Naməlum şəxslərdən gələn zəngləri blok edin"</string>
- <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Zəngi Bloklama"</string>
- <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Zəngi Bloklama deaktivdir"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Zəng bloklanması"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Zəng bloklanmır"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Təcili zəng edildi"</string>
- <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Təcili zənglərə cavab verənlərin Sizinlə əlaqə saxlamalarına icazə vermək üçün Zəngi Bloklama deaktiv edilib."</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Təcili xidmətlərin sizinlə əlaqə saxlamaları üçün zənglər bloklanmır."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Tərtibatçı Menyusu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Təcili zəng zamanı zəng edilə bilməz."</string>
+ <string name="cancel" msgid="6733466216239934756">"Ləğv edin"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index eba8c5c..ab4c435 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Upravljanje pozivima"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonski pozivi"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Nepoznato"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Propušten poziv"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte pozive sa telefonskih govornica"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nepoznati brojevi"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokirajte pozive neidentifikovanih pozivalaca"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje poziva"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje poziva je onemogućeno"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Upućen je hitni poziv"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje poziva je onemogućeno da bi hitne službe mogle da vas kontaktiraju."</string>
<string name="developer_title" msgid="9146088855661672353">"Meni za programere Telecom-a"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Za vreme hitnog poziva nije moguće preuzimati druge pozive."</string>
+ <string name="cancel" msgid="6733466216239934756">"Otkaži"</string>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index b6dd707..989bc11 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Кіраванне выклікамі"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Тэлефонныя выклікі"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Тэлефон"</string>
<string name="unknown" msgid="6993977514360123431">"Невядомы"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Прапушчаны выклік"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блакіраваць выклікі з таксафонаў"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Невядомыя нумары"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блакіраваць выклікі ад неапазнаных абанентаў"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блакіраванне выклікаў"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блакіраванне выклікаў адключана"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Зроблены экстранны выклік"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блакіраванне выклікаў было адключана, каб дазволіць аварыйнай брыгадзе звязацца з вамі."</string>
<string name="developer_title" msgid="9146088855661672353">"Меню распрацоўшчыка Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Падчас экстраннага выкліку іншыя выклікі прымаць немагчыма."</string>
+ <string name="cancel" msgid="6733466216239934756">"Скасаваць"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 7afddc2..892ce12 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Управление на обажданията"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефонни обаждания"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Неизвестен номер"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Пропуснато обаждане"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокиране на обаждания от импулсни телефони"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Неизвестни"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокиране на обажданията от неидентифицирани обаждащи се"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокиране на обажданията"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокирането на обажданията е деактивирано"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Извършено бе спешно обаждане"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокирането на обажданията е деактивирано, за да могат службите за спешни случаи да се свържат с вас."</string>
<string name="developer_title" msgid="9146088855661672353">"Меню за програмисти на Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"По време на спешно обаждане не могат да се поемат обаждания."</string>
+ <string name="cancel" msgid="6733466216239934756">"Отказ"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index cf04d40..2ecd8e1 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"কল ব্যবস্থাপনা"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ফোন কল"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ফোন"</string>
<string name="unknown" msgid="6993977514360123431">"অজানা"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"মিসড কল"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"পাবলিক ফোন থেকে করা কল ব্লক করুন"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"অজানা"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"অচেনা নম্বর থেকে করা কল ব্লক করুন"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"উপলভ্য নেই"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ব্লক করা কলের ক্ষেত্রে ফোন নম্বর দেখা যায় না"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"কল ব্লক করা"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"কল ব্লক করার বৈশিষ্ট্য বন্ধ করা হয়েছে"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"জরুরি অবস্থার কল করা হয়েছে"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"কল ব্লক করার বৈশিষ্ট্য বন্ধ করা হয়েছে যাতে জরুরি অবস্থার সাহায্যকারী ব্যক্তি আপনার সাথে যোগাযোগ করতে পারেন।"</string>
<string name="developer_title" msgid="9146088855661672353">"টেলিকম ডেভেলপার মেনু"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"জরুরি কল চলাকালীন কোনও কল রিসিভ করা যাবে না।"</string>
+ <string name="cancel" msgid="6733466216239934756">"বাতিল করুন"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 1968357..a1f9156 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Upravljanje pozivima"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonski pozivi"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Nepoznato"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Propušteni poziv"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte pozive s telefonskih govornica"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nepoznato"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokiraj pozive neidentificiranih pozivaoca"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nedostupno"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokirajte pozive kod kojih nije dostupan broj"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje poziva"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje poziva je onemogućeno"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Upućen je hitni poziv"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje poziva je onemogućeno kako bi se omogućilo osobama koje reagiraju u hitnim slučajevima da vas kontaktiraju."</string>
<string name="developer_title" msgid="9146088855661672353">"Meni za programere iz telekoma"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Pozivi se ne mogu primati tokom hitnog poziva"</string>
+ <string name="cancel" msgid="6733466216239934756">"Otkaži"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 69a7b6e..3978d69 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestió de trucades"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Trucades telefòniques"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telèfon"</string>
<string name="unknown" msgid="6993977514360123431">"Desconegut"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Trucada perduda"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloqueja les trucades de telèfons públics"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconeguts"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloqueja les trucades de números no identificats"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"No disponibles"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloqueja les trucades de números no disponibles"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueig de trucades"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"El bloqueig de trucades s\'ha desactivat"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"S\'ha fet una trucada d\'emergència"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"El bloqueig de trucades s\'ha desactivat perquè els serveis d\'emergència puguin contactar amb tu."</string>
<string name="developer_title" msgid="9146088855661672353">"Menú per a desenvolupadors de telecomunicacions"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"No es poden respondre trucades durant una trucada d\'emergència."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancel·la"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 1730a30..ab67be3 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Správa hovorů"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonní hovory"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Neznámý volající"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Zmeškaný hovor"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokovat hovory z veřejných telefonů"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Z nerozpoznaných čísel"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokovat hovory od nerozpoznaných volajících"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokování hovorů"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokování hovorů bylo vypnuto"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Uskutečněno tísňové volání"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokování hovorů bylo vypnuto, aby vás mohli kontaktovat pracovníci tísňových služeb."</string>
<string name="developer_title" msgid="9146088855661672353">"Nabídka pro vývojáře Telecomu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Během tísňového volání není možné přijímat hovory."</string>
+ <string name="cancel" msgid="6733466216239934756">"Zrušit"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 6a208c4..55fe41b 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Opkaldsstyring"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonopkald"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Opkald"</string>
<string name="unknown" msgid="6993977514360123431">"Ukendt"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Ubesvaret opkald"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloker opkald fra mønttelefoner"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ukendt"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloker opkald fra numre uden opkalds-id"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Opkaldsblokering"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Opkaldsblokering er deaktiveret"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Foretagne nødopkald"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Opkaldsblokering er blevet deaktiveret for at give nødnumre mulighed for at kontakte dig."</string>
<string name="developer_title" msgid="9146088855661672353">"Udviklermenu for Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Du kan ikke besvare opkald, mens du er i et nødopkald."</string>
+ <string name="cancel" msgid="6733466216239934756">"Annuller"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index c434ecc..ffe8cb7 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Anrufverwaltung"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonanrufe"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Unbekannt"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Entgangener Anruf"</string>
@@ -57,9 +57,9 @@
<string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"Als Standard festlegen"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"Abbrechen"</string>
<string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> wird alle Anruffunktionen steuern. Nur vertrauenswürdige Apps sollten als Standard-Telefon-App festgelegt werden."</string>
- <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"<xliff:g id="NEW_APP">%s</xliff:g> als Standard-App für Call Screening festlegen?"</string>
- <string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"Das Call Screening mit <xliff:g id="OLD_APP">%s</xliff:g> ist nicht mehr möglich."</string>
- <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> kann Informationen zu Anrufern, die nicht in deinen Kontakten gespeichert sind, erkennen und die Anrufe blockieren. Du solltest nur Apps, denen du vertraust, als Standard-App für das Call Screening festlegen."</string>
+ <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"<xliff:g id="NEW_APP">%s</xliff:g> als Standard-App für Anruf-Filter festlegen?"</string>
+ <string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"Der Anruf-Filter mit <xliff:g id="OLD_APP">%s</xliff:g> ist nicht mehr möglich."</string>
+ <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> kann Informationen zu Anrufern, die nicht in deinen Kontakten gespeichert sind, erkennen und die Anrufe blockieren. Du solltest nur Apps, denen du vertraust, als Standard-App für den Anruf-Filter festlegen."</string>
<string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"Als Standard festlegen"</string>
<string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"Abbrechen"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"Blockierte Nummern"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Anrufe von öffentlichen Telefonen blockieren"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unbekannt"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Anrufe von nicht identifizierten Anrufern blockieren"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Anrufblockierung"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Anrufblockierung deaktiviert"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Notruf abgesetzt"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Die Anrufblockierung wurde deaktiviert, damit Ersthelfer und Rettungskräfte dich kontaktieren können."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom-Entwicklermenü"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Während eines Notrufs kannst du keine Anrufe annehmen."</string>
+ <string name="cancel" msgid="6733466216239934756">"Abbrechen"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index ab523c1..e26ae97 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Διαχείριση κλήσεων"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Τηλεφωνικές κλήσεις"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Τηλέφωνο"</string>
<string name="unknown" msgid="6993977514360123431">"Άγνωστος"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Αναπάντητη κλήση"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Αποκλεισμός κλήσεων από καρτοτηλέφωνα"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Άγνωστος"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Αποκλεισμός κλήσεων από αγνώστους"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Φραγή κλήσεων"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Φραγή κλήσεων απενεργοποιημένη"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Πραγματοποιήθηκε κλήση έκτακτης ανάγκης"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Η φραγή κλήσεων έχει απενεργοποιηθεί, ώστε να επιτρέπεται σε άτομα που ανταποκρίνονται σε έκτακτες ανάγκες να επικοινωνούν μαζί σας."</string>
<string name="developer_title" msgid="9146088855661672353">"Μενού προγραμματιστών τηλεπικοινωνιών"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Δεν είναι δυνατή η λήψη κλήσεων κατά τη διάρκεια κλήσης επείγουσας ανάγκης."</string>
+ <string name="cancel" msgid="6733466216239934756">"Ακύρωση"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4de7584..cef6db5 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Call Management"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Phone"</string>
<string name="unknown" msgid="6993977514360123431">"Unknown"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Missed call"</string>
@@ -35,7 +35,7 @@
<string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Your call used the phone app that came with your device"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Call muted."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Speakerphone enabled."</string>
- <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Can\'t talk now. What\'s going on?"</string>
+ <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"I am so sorry, I can\'t answer the phone right now. How can I help you?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"I\'ll call you back."</string>
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"I\'ll call you later."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Can\'t talk now. Call me later?"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 4de7584..cef6db5 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Call Management"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Phone"</string>
<string name="unknown" msgid="6993977514360123431">"Unknown"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Missed call"</string>
@@ -35,7 +35,7 @@
<string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Your call used the phone app that came with your device"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Call muted."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Speakerphone enabled."</string>
- <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Can\'t talk now. What\'s going on?"</string>
+ <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"I am so sorry, I can\'t answer the phone right now. How can I help you?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"I\'ll call you back."</string>
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"I\'ll call you later."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Can\'t talk now. Call me later?"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4de7584..cef6db5 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Call Management"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Phone"</string>
<string name="unknown" msgid="6993977514360123431">"Unknown"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Missed call"</string>
@@ -35,7 +35,7 @@
<string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Your call used the phone app that came with your device"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Call muted."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Speakerphone enabled."</string>
- <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Can\'t talk now. What\'s going on?"</string>
+ <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"I am so sorry, I can\'t answer the phone right now. How can I help you?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"I\'ll call you back."</string>
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"I\'ll call you later."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Can\'t talk now. Call me later?"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4de7584..cef6db5 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Call Management"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Phone"</string>
<string name="unknown" msgid="6993977514360123431">"Unknown"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Missed call"</string>
@@ -35,7 +35,7 @@
<string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Your call used the phone app that came with your device"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Call muted."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Speakerphone enabled."</string>
- <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Can\'t talk now. What\'s going on?"</string>
+ <string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"I am so sorry, I can\'t answer the phone right now. How can I help you?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"I\'ll call you back."</string>
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"I\'ll call you later."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Can\'t talk now. Call me later?"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 3b3a983..da9faf3 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Call Management"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone Calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Phone"</string>
<string name="unknown" msgid="6993977514360123431">"Unknown"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Missed call"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 826b877..34de9c5 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Administración de llamadas"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Llamadas telefónicas"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Teléfono"</string>
<string name="unknown" msgid="6993977514360123431">"Desconocida"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Llamada perdida"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquear llamadas provenientes de teléfonos públicos"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconocido"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear llamadas de emisores desconocidos"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueo de llamadas"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Se inhabilitó el bloqueo de llamadas"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Se realizó una llamada de emergencia"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Se inhabilitó el bloqueo de llamadas para permitir que los servicios de emergencia se comuniquen contigo."</string>
<string name="developer_title" msgid="9146088855661672353">"Menú para desarrolladores de Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"No puedes contestar llamadas mientras estés en una llamada de emergencia."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index e124de4..1d2aa15 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestión de llamadas"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Llamadas"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Teléfono"</string>
<string name="unknown" msgid="6993977514360123431">"Desconocido"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Llamada perdida"</string>
@@ -99,7 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Bloqueo de llamadas"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Llamadas en segundo plano"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Llamadas interrumpidas"</string>
- <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplicaciones para teléfonos con bloqueos"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplicaciones para teléfonos con fallos"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Si haces esta llamada, se finalizará la de <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Elige cómo quieres hacer esta llamada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirigir llamada con <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquea las llamadas de teléfonos públicos"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconocidos"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquea las llamadas de números desconocidos"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"No disponible"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquear llamadas en las que el número no esté disponible"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueo de llamadas"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Se ha inhabilitado el bloqueo de llamadas"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Se ha hecho una llamada de emergencia"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Se ha inhabilitado el bloqueo de llamadas para que los servicios de emergencia puedan ponerse en contacto contigo."</string>
<string name="developer_title" msgid="9146088855661672353">"Menú para desarrolladores de telecomunicaciones"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"No se pueden responder llamadas durante una llamada de emergencia."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index bb291ad..77c61d4 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Kõnehaldus"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonikõned"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Tundmatu"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Vastamata kõne"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Kõnede blokeerimine telefoniautomaatidest"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tundmatud"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Kõnede blokeerimine tuvastamata helistajatelt"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Kõnede blokeerimine"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Kõnede blokeerimine on keelatud"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Tehti hädaabikõne"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Kõnede blokeerimine on keelatud, et lubada hädaabiteenustel teiega ühendust võtta."</string>
<string name="developer_title" msgid="9146088855661672353">"Teenuse Telecom arendaja menüü"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Hädaabikõne ajal ei saa kõnesid vastu võtta."</string>
+ <string name="cancel" msgid="6733466216239934756">"Tühista"</string>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index c8956cd..e811b06 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Deien kudeaketa"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefono-deiak"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefonoa"</string>
<string name="unknown" msgid="6993977514360123431">"Ezezaguna"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Dei galdua"</string>
@@ -85,9 +85,9 @@
<string name="answering_ends_other_call" msgid="8653544281903986641">"Erantzuten baduzu, amaitu egingo da <xliff:g id="CALL_VIA">%1$s</xliff:g> deia"</string>
<string name="answering_ends_other_calls" msgid="3702302838456922535">"Erantzuten baduzu, amaitu egingo dira <xliff:g id="CALL_VIA">%1$s</xliff:g> deiak"</string>
<string name="answering_ends_other_video_call" msgid="8572022039304239958">"Erantzuten baduzu, amaitu egingo da <xliff:g id="CALL_VIA">%1$s</xliff:g> bideo-deia"</string>
- <string name="answering_ends_other_managed_call" msgid="4031778317409881805">"Erantzuten baduzu, amaitu egingo da uneko deia"</string>
- <string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"Erantzuten baduzu, amaitu egingo dira uneko deiak"</string>
- <string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Erantzuten baduzu, amaitu egingo da uneko bideo-deia"</string>
+ <string name="answering_ends_other_managed_call" msgid="4031778317409881805">"Erantzuten baduzu, amaitu egingo da oraingo deia"</string>
+ <string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"Erantzuten baduzu, amaitu egingo dira oraingo deiak"</string>
+ <string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Erantzuten baduzu, amaitu egingo da oraingo bideo-deia"</string>
<string name="answer_incoming_call" msgid="2045888814782215326">"Erantzun"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"Baztertu"</string>
<string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Ezin da egin deia, ez dagoelako mota honetako deiak onartzen duen deiak egiteko konturik."</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokeatu telefono publikoen deiak"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ezezagunak"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokeatu identifikatu gabeko deitzaileen deiak"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Deiak blokeatzeko aukera"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Desgaitu da deiak blokeatzeko aukera"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Larrialdi-deia egin da"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Desgaitu da deiak blokeatzeko aukera, larrialdietako zerbitzuak zurekin harremanetan jarri ahal daitezen."</string>
<string name="developer_title" msgid="9146088855661672353">"Telekomunikazioen garatzaileen menua"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Ezin duzu hartu deirik larrialdi-dei bat abian den bitartean."</string>
+ <string name="cancel" msgid="6733466216239934756">"Utzi"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c873159..85d005c 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"مدیریت تماس"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"تماسهای تلفنی"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"تلفن"</string>
<string name="unknown" msgid="6993977514360123431">"ناشناس"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"تماس بی پاسخ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"مسدود کردن تماسها از تلفنهای عمومی"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ناشناس"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"مسدود کردن تماسهای تماسگیرندگان ناشناس"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"مسدود کردن تماس"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"مسدود کردن تماس غیرفعال شد"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"تماس اضطراری برقرار شد"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"مسدود کردن تماس غیرفعال شده است تا پاسخدهندگان اضطراری بتوانند با شما تماس بگیرند."</string>
<string name="developer_title" msgid="9146088855661672353">"منوی برنامهنویس Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"درحین برقراری تماسی اضطراری، نمیتوان به تماسها پاسخ داد."</string>
+ <string name="cancel" msgid="6733466216239934756">"لغو"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index cf57d62..bb81bb8 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Puhelujen hallinta"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Puhelut"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Puhelin"</string>
<string name="unknown" msgid="6993977514360123431">"Tuntematon"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Vastaamatta jäänyt puhelu"</string>
@@ -55,13 +55,13 @@
<string name="add_vm_number_str" msgid="5179510133063168998">"Lisää numero"</string>
<string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"Valitaanko <xliff:g id="NEW_APP">%s</xliff:g> oletuspuhelinsovellukseksi?"</string>
<string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"Aseta oletukseksi"</string>
- <string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"Peruuta"</string>
+ <string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"Peru"</string>
<string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> voi hallita kaikkia puhelutoimintoja. Aseta oletuspuhelinsovellukseksi vain luotettava sovellus."</string>
<string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Määritetäänkö <xliff:g id="NEW_APP">%s</xliff:g> puheluseulonnan oletussovellukseksi?"</string>
<string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> ei voi enää seuloa puheluita."</string>
<string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> näkee tietoa soittajista, jotka eivät ole yhteystiedoissasi, ja pystyy estämään heiltä tulevat puhelut. Puheluseulonnan oletussovellukseksi kannattaa määrittää vain sellainen sovellus, johon luotat."</string>
<string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"Määritä oletussovellus"</string>
- <string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"Peruuta"</string>
+ <string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"Peru"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"Estetyt numerot"</string>
<string name="blocked_numbers_msg" msgid="2797422132329662697">"Et voi vastaanottaa puheluita tai tekstiviestejä estetyistä numeroista."</string>
<string name="block_number" msgid="3784343046852802722">"Lisää numero"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Estä yleisöpuhelimista soitetut puhelut"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tuntematon"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Estä tuntemattomien soittajien puhelut"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Puhelujen esto"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Puhelujen esto poistettu käytöstä"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Hätäpuhelu soitettu"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Puhelujen esto on poistettu käytöstä, jotta pelastusviranomaiset voivat soittaa puhelimeesi."</string>
<string name="developer_title" msgid="9146088855661672353">"Televiestinnän kehittäjävalikko"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Puheluita ei voi välittää hätäpuhelun aikana."</string>
+ <string name="cancel" msgid="6733466216239934756">"Peru"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 74faab9..1288b2e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestion des appels"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Appels téléphoniques"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Téléphone"</string>
<string name="unknown" msgid="6993977514360123431">"Inconnu"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Appel manqué"</string>
@@ -104,7 +104,7 @@
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Choisissez comment passer cet appel"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Rediriger l\'appel en utilisant <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
<string name="alert_place_unredirect_outgoing_call" msgid="2467608535225764006">"Appeler en utilisant mon numéro de téléphone"</string>
- <string name="alert_redirect_outgoing_call_timeout" msgid="5568101425637373060">"Impossible de passer l\'appel au moyen de l\'application <xliff:g id="OTHER_APP">%1$s</xliff:g>. Essayez d\'utiliser une autre application de redirection d\'appels ou de communiquer avec le concepteur de l\'application pour obtenir de l\'aide."</string>
+ <string name="alert_redirect_outgoing_call_timeout" msgid="5568101425637373060">"Impossible de passer l\'appel au moyen de l\'application <xliff:g id="OTHER_APP">%1$s</xliff:g>. Essayez d\'utiliser une autre application de redirection d\'appels ou de communiquer avec le développeur de l\'application pour obtenir de l\'aide."</string>
<string name="phone_settings_call_blocking_txt" msgid="7311523114822507178">"Blocage des appels"</string>
<string name="phone_settings_number_not_in_contact_txt" msgid="2602249106007265757">"Numéros non répertoriés dans les contacts"</string>
<string name="phone_settings_number_not_in_contact_summary_txt" msgid="963327038085718969">"Bloquer les numéros non répertoriés dans vos contacts"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquer les appels provenant de téléphones publics"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Inconnu"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquer les appels provenant d\'appelants non identifiés"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocage des appels"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocage des appels désactivé"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Appel d\'urgence effectué"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Le blocage des appels a été désactivé pour permettre aux intervenants d\'urgence de communiquer avec vous."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu Telecom Developer"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Les appels ne peuvent pas être pris pendant un appel d\'urgence."</string>
+ <string name="cancel" msgid="6733466216239934756">"Annuler"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index c2a95a2..6fecf5b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestion des appels"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Appels téléphoniques"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Téléphone"</string>
<string name="unknown" msgid="6993977514360123431">"Inconnu"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Appel manqué"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquez les appels provenant de cabines téléphoniques"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Numéros inconnus"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquer les appels provenant de personnes non identifiées"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocage d\'appels"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocage d\'appels désactivé"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Appel d\'urgence"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Le blocage d\'appels a été désactivé pour que les services d\'urgence puissent vous contacter."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu Telecom Developer"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Impossible de prendre un appel au cours d\'un appel d\'urgence."</string>
+ <string name="cancel" msgid="6733466216239934756">"Annuler"</string>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 42c55d6..614a2dd 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Xestión de chamadas"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Chamadas telefónicas"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Teléfono"</string>
<string name="unknown" msgid="6993977514360123431">"Descoñecido"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Chamada perdida"</string>
@@ -88,7 +88,7 @@
<string name="answering_ends_other_managed_call" msgid="4031778317409881805">"Ao responder, finalizará a túa chamada en curso"</string>
<string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"Ao responder, finalizarán as túas chamadas en curso"</string>
<string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Ao responder, finalizarán as túas videochamadas en curso"</string>
- <string name="answer_incoming_call" msgid="2045888814782215326">"Responder"</string>
+ <string name="answer_incoming_call" msgid="2045888814782215326">"Contestar"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"Rexeitar"</string>
<string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Non se pode realizar a chamada porque non hai ningunha conta de chamadas que admita chamadas deste tipo."</string>
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"Non se pode realizar a chamada porque hai unha chamada en curso en <xliff:g id="OTHER_CALL">%1$s</xliff:g>."</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquea as chamadas de teléfonos públicos"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Descoñecido"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear as chamadas de emisores non identificados"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueo de chamadas"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Desactivouse o bloqueo de chamadas"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Realizouse unha chamada de emerxencia"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Desactivouse o bloqueo de chamadas parar permitir que os servizos de emerxencias se poidan poñer en contacto contigo."</string>
<string name="developer_title" msgid="9146088855661672353">"Menú para programadores de telecomunicacións"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Non se pode responder ás chamadas durante unha chamada de emerxencia."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 7455080..10840ec 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -16,13 +16,13 @@
<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="3077225713817780583">"કૉલ સંચાલન"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone Calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ફોન"</string>
<string name="unknown" msgid="6993977514360123431">"અજાણ્યું"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ચૂકી ગયેલો કૉલ"</string>
<string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"ચૂકી ગયેલ કાર્ય કૉલ"</string>
- <string name="notification_missedCallsTitle" msgid="3910479625507893809">"છૂટેલા કૉલ્સ"</string>
- <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> છૂટેલા કૉલ્સ"</string>
+ <string name="notification_missedCallsTitle" msgid="3910479625507893809">"ચૂકી ગયેલા કૉલ"</string>
+ <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ચૂકી ગયેલા કૉલ"</string>
<string name="notification_missedCallTicker" msgid="6731461957487087769">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> નો કૉલ ચૂકી ગયાં"</string>
<string name="notification_missedCall_call_back" msgid="7900333283939789732">"કૉલ બેક"</string>
<string name="notification_missedCall_message" msgid="4054698824390076431">"સંદેશ"</string>
@@ -95,7 +95,7 @@
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"તમારા <xliff:g id="OTHER_CALL">%1$s</xliff:g> કૉલને કારણે કૉલ કરી શકતાં નથી."</string>
<string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"અન્ય ઍપ્લિકેશનમાં કૉલને કારણે કૉલ કરી શકતાં નથી."</string>
<string name="notification_channel_incoming_call" msgid="5245550964701715662">"ઇનકમિંગ કૉલ"</string>
- <string name="notification_channel_missed_call" msgid="7168893015283909012">"છૂટેલા કૉલ"</string>
+ <string name="notification_channel_missed_call" msgid="7168893015283909012">"ચૂકી ગયેલા કૉલ"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"કૉલ બ્લૉક કરી રહ્યાં છીએ"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"બૅકગ્રાઉન્ડ કૉલ"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"ડિસ્કનેક્ટ કરેલા કૉલ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"પે ફોન પરના કૉલ બ્લૉક કરો"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"અજાણ્યા"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"અજાણ્યા કૉલરના કૉલ બ્લૉક કરો"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"કૉલ બ્લૉક કરી રહ્યાં છીએ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"કૉલ બ્લૉક કરવાનું બંધ કરવામાં આવ્યું છે"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"કટોકટીનો કૉલ કર્યો"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"કટોકટીમાં પ્રતિસાદ કરનારાઓ તમારો સંપર્ક કરી શકે તે માટે કૉલ બ્લૉક કરવાનું બંધ કરવામાં આવ્યું છે."</string>
<string name="developer_title" msgid="9146088855661672353">"ટેલિકોમ ડેવલપર મેનૂ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ઇમર્જન્સી કૉલ ચાલુ હોય, ત્યારે બીજા કોઈ કૉલ લઈ શકાતા નથી."</string>
+ <string name="cancel" msgid="6733466216239934756">"રદ કરો"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index ed623b8..5c67aaa 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"कॉल प्रबंधन"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"फ़ोन कॉल"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"फ़ोन"</string>
<string name="unknown" msgid="6993977514360123431">"अज्ञात"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"छूटी कॉल"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फ़ोन से आने वाले कॉल पर रोक लगाएं"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"अज्ञात"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अनजान कॉलर के कॉल पर रोक लगाएं"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"कॉल पर रोक"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"कॉल पर रोक लगाने की सुविधा बंद है"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"आपातकालीन कॉल किया गया"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"आपातकालीन सहायता कर्मचारी आपसे संपर्क कर सकें, इसलिए कॉल पर रोक लगाने की सुविधा बंद कर दी गई है."</string>
<string name="developer_title" msgid="9146088855661672353">"टेलीकॉम डेवलपर मेन्यू"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"आपातकालीन कॉल के दौरान कॉल नहीं उठाया जा सकता."</string>
+ <string name="cancel" msgid="6733466216239934756">"रद्द करें"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index ff38e54..eb40a3c 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Upravljanje pozivom"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonski pozivi"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Nepoznato"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Propušteni poziv"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte pozive s telefonskih govornica"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nepoznato"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokirajte pozive nepoznatih pozivatelja"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje poziva"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje poziva je onemogućeno"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Hitni je poziv upućen"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje poziva onemogućeno je da bi vas mogli kontaktirati djelatnici hitnih službi."</string>
<string name="developer_title" msgid="9146088855661672353">"Izbornik Telecom Developer"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Pozivi se ne mogu primiti tijekom hitnog poziva."</string>
+ <string name="cancel" msgid="6733466216239934756">"Odustani"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 55e5535..012b647 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Híváskezelés"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonhívások"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Ismeretlen"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Nem fogadott hívás"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"A nyilvános telefonokról bejövő hívások letiltása"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ismeretlen"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"A nem azonosított hívók letiltása"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Hívásletiltás"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Hívásletiltás kikapcsolva"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Segélyhívás indítva"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"A hívásletiltás ki van kapcsolva, hogy a segélyszolgálatok kapcsolatba léphessenek Önnel."</string>
<string name="developer_title" msgid="9146088855661672353">"Telekommunikációs fejlesztői menü"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Segélyhívás közben nem lehet hívást fogadni."</string>
+ <string name="cancel" msgid="6733466216239934756">"Mégse"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 6987dab..43c0568 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Զանգերի կառավարում"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Հեռախոսազանգեր"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Հեռախոս"</string>
<string name="unknown" msgid="6993977514360123431">"Անհայտ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Բաց թողնված զանգ"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Արգելափակել ավտոմատ հեռախոսներից եկող զանգերը"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Անհայտ համարներ"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Արգելափակել անհայտ համարներից եկող զանգերը"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Անհասանելի է"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Արգելափակել զանգերը, երբ համարն անհասանելի է"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Զանգերի արգելափակում"</string>
- <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Զանգերի արգելափակումն անջատած է"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Զանգերի արգելափակումն անջատված է"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Կատարվեց շտապ կանչ"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Զանգերի արգելափակումն անջատվել է, որպեսզի արտակարգ ծառայությունները կարողանան ձեզ զանգել:"</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom-ի մշակողի ընտրացանկ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Շտապ կանչի ժամանակ այլ զանգեր չեք կարող ընդւնել։"</string>
+ <string name="cancel" msgid="6733466216239934756">"Չեղարկել"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 23ebb73..897e76c 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Pengelolaan Panggilan Telepon"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Panggilan Telepon"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telepon"</string>
<string name="unknown" msgid="6993977514360123431">"Tidak diketahui"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Panggilan tak terjawab"</string>
@@ -65,13 +65,13 @@
<string name="blocked_numbers" msgid="8322134197039865180">"Nomor yang diblokir"</string>
<string name="blocked_numbers_msg" msgid="2797422132329662697">"Anda tidak akan menerima telepon atau SMS dari nomor yang diblokir."</string>
<string name="block_number" msgid="3784343046852802722">"Tambahkan nomor"</string>
- <string name="unblock_dialog_body" msgid="2723393535797217261">"Batalkan pemblokiran <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
- <string name="unblock_button" msgid="8732021675729981781">"Batalkan pemblokiran"</string>
+ <string name="unblock_dialog_body" msgid="2723393535797217261">"Berhenti memblokir <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+ <string name="unblock_button" msgid="8732021675729981781">"Berhenti memblokir"</string>
<string name="add_blocked_dialog_body" msgid="8599974422407139255">"Blokir panggilan telepon dan SMS dari"</string>
<string name="add_blocked_number_hint" msgid="8769422085658041097">"Nomor telepon"</string>
<string name="block_button" msgid="485080149164258770">"Blokir"</string>
<string name="non_primary_user" msgid="315564589279622098">"Hanya pemilik perangkat yang dapat melihat dan mengelola nomor yang diblokir."</string>
- <string name="delete_icon_description" msgid="5335959254954774373">"Bebaskan"</string>
+ <string name="delete_icon_description" msgid="5335959254954774373">"Berhenti memblokir"</string>
<string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"Blokir dinonaktifkan sementara"</string>
<string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"Setelah Anda menelepon atau mengirim SMS ke nomor gawat darurat, blokir akan dinonaktifkan agar layanan gawat darurat tersebut dapat menghubungi Anda."</string>
<string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Aktifkan lagi sekarang"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokir panggilan dari telepon umum"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tidak dikenal"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokir panggilan dari penelepon yang tidak dikenal"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Pemblokiran Panggilan"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Pemblokiran Panggilan dinonaktifkan"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Panggilan darurat dibuat"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Pemblokiran Panggilan dinonaktifkan untuk mengizinkan penjawab darurat menghubungi Anda."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu Developer Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Panggilan tidak dapat diterima saat sedang melakukan panggilan darurat."</string>
+ <string name="cancel" msgid="6733466216239934756">"Batal"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 442b9d5..50e1c94 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Símtalastjórnun"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Símtöl"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Sími"</string>
<string name="unknown" msgid="6993977514360123431">"Óþekkt"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Ósvarað símtal"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Loka fyrir símtöl úr almenningssímum"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Óþekkt"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Loka fyrir símtöl frá óþekktum hringjendum"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Lokað fyrir símtöl"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Ekki er lokað fyrir símtöl"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Neyðarsímtal var hringt"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Slökkt hefur verið á „Lokað fyrir símtöl“ svo neyðarþjónustuaðilar geti haft samband við þig."</string>
<string name="developer_title" msgid="9146088855661672353">"Forritaravalmynd fyrir fjarskipti"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Ekki er hægt að svara símtölum meðan á neyðarsímtali stendur."</string>
+ <string name="cancel" msgid="6733466216239934756">"Hætta við"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 60f32d7..bc585d5 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestione chiamate"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonate"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefono"</string>
<string name="unknown" msgid="6993977514360123431">"Sconosciuto"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Chiamata persa"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blocca le chiamate dalle cabine telefoniche"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Sconosciuto"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blocca le chiamate da chiamanti non identificati"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocco delle chiamate"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocco delle chiamate disattivato"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Chiamata di emergenza effettuata"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Il blocco delle chiamate è stato disattivato per consentire ai servizi di emergenza di contattarti."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu sviluppatore telecomunicazioni"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Impossibile accettare una chiamata durante una chiamata di emergenza."</string>
+ <string name="cancel" msgid="6733466216239934756">"Annulla"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 30a909b..2f37355 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ניהול השיחות"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"שיחות טלפון"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"טלפון"</string>
<string name="unknown" msgid="6993977514360123431">"לא ידוע"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"שיחה שלא נענתה"</string>
@@ -24,7 +24,7 @@
<string name="notification_missedCallsTitle" msgid="3910479625507893809">"שיחות שלא נענו"</string>
<string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> שיחות שלא נענו"</string>
<string name="notification_missedCallTicker" msgid="6731461957487087769">"שיחה שלא נענתה מאת <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
- <string name="notification_missedCall_call_back" msgid="7900333283939789732">"התקשר חזרה"</string>
+ <string name="notification_missedCall_call_back" msgid="7900333283939789732">"התקשרות בחזרה"</string>
<string name="notification_missedCall_message" msgid="4054698824390076431">"שליחת הודעה"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"השיחה נותקה"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"השיחה עם <xliff:g id="CALLER">%s</xliff:g> נותקה בגלל שיחת חירום."</string>
@@ -37,7 +37,7 @@
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"רמקול מופעל."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"לא נוח לי עכשיו. מה קורה?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"תיכף אחזור אליך."</string>
- <string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"אני אתקשר אליך יותר מאוחר."</string>
+ <string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"אתקשר אליך יותר מאוחר."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"לא נוח לי עכשיו. נדבר אחר כך?"</string>
<string name="respond_via_sms_setting_title" msgid="4762275482898830160">"תגובות מהירות"</string>
<string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"עריכת תגובות מהירות"</string>
@@ -48,15 +48,15 @@
<string name="enable_account_preference_title" msgid="6949224486748457976">"חשבונות לביצוע שיחות"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"ניתן לבצע רק שיחות חירום."</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"לא ניתן להוציא שיחות באמצעות האפליקציה הזו ללא ההרשאה \'טלפון\'."</string>
- <string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"כדי להתקשר, הזן מספר טלפון חוקי."</string>
+ <string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"כדי להתקשר, יש להזין מספר טלפון חוקי."</string>
<string name="duplicate_video_call_not_allowed" msgid="5754746140185781159">"לא ניתן כעת להוסיף את השיחה."</string>
<string name="no_vm_number" msgid="2179959110602180844">"חסר מספר של דואר קולי"</string>
<string name="no_vm_number_msg" msgid="1339245731058529388">"בכרטיס ה-SIM לא מאוחסן מספר של דואר קולי."</string>
- <string name="add_vm_number_str" msgid="5179510133063168998">"הוסף מספר"</string>
+ <string name="add_vm_number_str" msgid="5179510133063168998">"הוספת מספר"</string>
<string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"האם להפוך את <xliff:g id="NEW_APP">%s</xliff:g> לברירת המחדל לאפליקציית \'טלפון\'?"</string>
- <string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"הגדר כברירת מחדל"</string>
+ <string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"הגדרה כברירת מחדל"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"ביטול"</string>
- <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> תוכל להתקשר ולשלוט בכל ההיבטים של השיחות. מומלץ לבחור רק אפליקציות שאתה סומך עליהן כברירת המחדל לאפליקציית \'טלפון\'."</string>
+ <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> תוכל להתקשר ולשלוט בכל ההיבטים של השיחות. מומלץ לבחור רק אפליקציות שסומכים עליהן כברירת המחדל לאפליקציית \'טלפון\'."</string>
<string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"רוצה להפוך את <xliff:g id="NEW_APP">%s</xliff:g> לאפליקציית ברירת המחדל שלך לסינון שיחות?"</string>
<string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"אפליקציית <xliff:g id="OLD_APP">%s</xliff:g> לא תוכל לסנן שיחות עוד."</string>
<string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"אפליקציית <xliff:g id="NEW_APP">%s</xliff:g> תוכל לראות מידע על מתקשרים שאינם באנשי הקשר שלך ולחסום שיחות מהם. מומלץ לבחור רק אפליקציות שסומכים עליהן כברירת המחדל לסינון שיחות."</string>
@@ -74,12 +74,12 @@
<string name="delete_icon_description" msgid="5335959254954774373">"ביטול חסימה"</string>
<string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"החסימה הושבתה זמנית"</string>
<string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"לאחר חיוג או שליחת הודעה למספר חירום, החסימה תושבת כדי ששירותי החירום יוכלו ליצור איתך קשר."</string>
- <string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"הפעל מחדש עכשיו"</string>
+ <string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"הפעלה מחדש עכשיו"</string>
<string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> נחסם"</string>
<string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"החסימה של <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> בוטלה"</string>
<string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"אי אפשר לחסום מספרי חירום."</string>
<string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"המספר <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> כבר חסום."</string>
- <string name="toast_personal_call_msg" msgid="5817631570381795610">"משתמש בחייגן האישי כדי להתקשר"</string>
+ <string name="toast_personal_call_msg" msgid="5817631570381795610">"נעשה שימוש בחייגן האישי כדי להתקשר"</string>
<string name="notification_incoming_call" msgid="1233481138362230894">"<xliff:g id="CALL_FROM">%2$s</xliff:g> מתקשר/ת אליך ב-<xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
<string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_FROM">%2$s</xliff:g> מתקשר/ת אליך בשיחת וידאו ב-<xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
<string name="answering_ends_other_call" msgid="8653544281903986641">"מענה יסיים את השיחה ב-<xliff:g id="CALL_VIA">%1$s</xliff:g>"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"חסימת שיחות מטלפונים ציבוריים"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"מספרים לא ידועים"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"חסימת שיחות ממספרים לא מזוהים"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"מספרים לא ידועים"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"חסימת שיחות ממספרים לא ידועים"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"חסימת שיחות"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"חסימת השיחות הושבתה"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"בוצעה שיחת חירום"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"חסימת השיחות הושבתה כדי לאפשר לצוותי עזרה ראשונה להתקשר אליך."</string>
<string name="developer_title" msgid="9146088855661672353">"תפריט למפתחי מערכות תקשורת"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"אי אפשר לענות לשיחות אחרות בזמן שיחת חירום."</string>
+ <string name="cancel" msgid="6733466216239934756">"ביטול"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index bd87d66..aec2cb9 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"通話管理"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"電話"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"電話"</string>
<string name="unknown" msgid="6993977514360123431">"通知不可能"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"不在着信"</string>
@@ -99,7 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"着信のブロック"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"バックグラウンドでの通話"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"通話の切断"</string>
- <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"スマートフォン アプリがクラッシュしたとき"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"通話アプリがクラッシュしたとき"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"この通話を発信すると、<xliff:g id="OTHER_APP">%1$s</xliff:g> の通話が終了します。"</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"通話の発信方法を選択してください"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"<xliff:g id="OTHER_APP">%1$s</xliff:g> を使用して通話をリダイレクト"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"公衆電話からの着信をブロック"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明な発信者"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"不明な発信者からの着信をブロック"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"着信のブロック"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"着信のブロックを無効にしました"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"緊急通報"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"着信のブロックを無効して、救急隊員などがあなたに連絡できるようにしました。"</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom デベロッパー メニュー"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"緊急通報中は、他の電話を受けることができません。"</string>
+ <string name="cancel" msgid="6733466216239934756">"キャンセル"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index be27e8b..d60a9d5 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ზარების მართვა"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"სატელეფონო ზარები"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ტელეფონი"</string>
<string name="unknown" msgid="6993977514360123431">"უცნობი"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"გამოტოვებული ზარი"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ზარების დაბლოკვა საზოგადოებრივი ტელეფონებიდან"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"უცნობი"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ზარების დაბლოკვა ამოუცნობი აბონენტებისგან"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ზარების დაბლოკვა"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ზარების დაბლოკვა გათიშულია"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"საგანგებო ზარი შესრულდა"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ზარების დაბლოკვა გათიშულია, რათა საგანგებო სიტუაციებში მოპასუხეებმა თქვენთან დაკავშირება შეძლონ"</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom-ის დეველოპერის მენიუ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"გადაუდებელი ზარის დროს ზარების მიღება შეუძლებელია."</string>
+ <string name="cancel" msgid="6733466216239934756">"გაუქმება"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 0bab244..c336e5e 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Қоңырауды басқару"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефон қоңыраулары"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Белгісіз"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Қабылданбаған қоңырау"</string>
@@ -45,7 +45,7 @@
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"Жылдам жауап"</string>
<string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"Хабар <xliff:g id="PHONE_NUMBER">%s</xliff:g> нөміріне жіберілді."</string>
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> нөміріне хабар жіберілмеді."</string>
- <string name="enable_account_preference_title" msgid="6949224486748457976">"Қоңырау шалу есептік жазбалары"</string>
+ <string name="enable_account_preference_title" msgid="6949224486748457976">"Қоңырау шалу аккаунттары"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Құтқару қызметіне ғана қоңырау шалуға рұқсат етілген."</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"\"Телефон\" рұқсатынсыз бұл қолданба шығыс қоңырауларды соға алмайды."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"Қоңырау шалу үшін жарамды нөмірді енгізіңіз."</string>
@@ -90,7 +90,7 @@
<string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Жауап беру қазіргі бейне қоңырауды тоқтатады"</string>
<string name="answer_incoming_call" msgid="2045888814782215326">"Жауап беру"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"Қабылдамау"</string>
- <string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Қоңырау шалу мүмкін емес, себебі бұндай қоңырауларға қолдау көрсететін есептік жазба жоқ."</string>
+ <string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Қоңырау шалу мүмкін емес, себебі бұндай қоңырауларға қолдау көрсететін аккаунт жоқ."</string>
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"Қоңырау шалу мүмкін емес, себебі <xliff:g id="OTHER_CALL">%1$s</xliff:g> қоңырауы белсенді."</string>
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"Қоңырау шалу мүмкін емес, себебі <xliff:g id="OTHER_CALL">%1$s</xliff:g> қоңыраулары белсенді."</string>
<string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"Қоңырау шалу мүмкін емес, себебі басқа қолданбадан қоңырау шалынуда."</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Ақылы телефон қоңырауларын бөгеу"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Белгісіз"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Белгісіз қоңырауларды бөгеу"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Қоңырауды бөгеу"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Қоңырау бөгеу функциясы өшірулі"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Төтенше жағдай қоңырауы шалынды"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Төтенше жағдай қызметтері сізге хабарласа алуы үшін, қоңырау бөгеу функциясы өшірілді."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom Developer мәзірі"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Құтқару қызметімен сөйлесіп жатқанда, басқа қоңырауларды қабылдай алмайсыз."</string>
+ <string name="cancel" msgid="6733466216239934756">"Бас тарту"</string>
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 58b2abf..82deb2a 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"គ្រប់គ្រងការហៅ"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Phone Calls"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ទូរសព្ទ"</string>
<string name="unknown" msgid="6993977514360123431">"មិនស្គាល់"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ខកខានទទួល"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ទប់ស្កាត់ការហៅពីទូរសព្ទដែលបង់ប្រាក់"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"មិនស្គាល់"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ទប់ស្កាត់ការហៅទូរសព្ទពីអ្នកហៅដែលមិនស្គាល់អត្តសញ្ញាណ"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"មិនអាចប្រើបាន"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ទប់ស្កាត់ការហៅទូរសព្ទនៅកន្លែងដែលមិនអាចប្រើលេខនេះបាន"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ការទប់ស្កាត់ការហៅ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"បានបិទការទប់ស្កាត់ការហៅ"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"បានធ្វើការហៅបន្ទាន់"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ការទប់ស្កាត់ការហៅត្រូវបានបិទ ដើម្បីអនុញ្ញាតឲ្យអ្នកឆ្លើយតបបន្ទាន់អាចទាក់ទងអ្នកបាន។"</string>
<string name="developer_title" msgid="9146088855661672353">"ម៉ឺនុយអ្នកអភិវឌ្ឍន៍ទូរគមនាគមន៍"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"មិនអាចទទួលការហៅទូរសព្ទបានទេ ពេលកំពុងហៅទៅលេខសង្គ្រោះបន្ទាន់។"</string>
+ <string name="cancel" msgid="6733466216239934756">"បោះបង់"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 6e0bb59..2362b20 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ಕರೆ ನಿರ್ವಹಣೆ"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ಫೋನ್ ಕರೆಗಳು"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ಫೋನ್"</string>
<string name="unknown" msgid="6993977514360123431">"ಅಪರಿಚಿತ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ಮಿಸ್ಡ್ ಕಾಲ್"</string>
@@ -98,7 +98,7 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"ಮಿಸ್ಡ್ ಕಾಲ್ಗಳು"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"ಕರೆ ನಿರ್ಬಂಧಿಸುವಿಕೆ"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"ಹಿನ್ನೆಲೆ ಕರೆಗಳು"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"ಕರೆಗಳ ಕನೆಕ್ಷನ್ ಅನ್ನು ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಲಾದ ಕರೆಗಳು"</string>
<string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"ಕ್ರ್ಯಾಶ್ ಆಗಿರುವ ಫೋನ್ ಆ್ಯಪ್ಗಳು"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"ಈ ಕರೆಯನ್ನು ಮಾಡುವುದರಿಂದ ನಿಮ್ಮ <xliff:g id="OTHER_APP">%1$s</xliff:g> ಕರೆಯು ಅಂತ್ಯಗೊಳ್ಳುತ್ತದೆ."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"ಈ ಕರೆ ಮಾಡುವುದು ಹೇಗೆ ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ಪಾವತಿ ಫೋನ್ಗಳಿಂದ ಕರೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ಅಪರಿಚಿತ"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ಗುರುತಿಸದ ಕರೆದಾರರಿಂದ ಕರೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ಕರೆ ನಿರ್ಬಂಧಿಸುವಿಕೆ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ಕರೆ ನಿರ್ಬಂಧಿಸುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ತುರ್ತು ಕರೆ ಮಾಡಲಾಗಿದೆ"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ನಿಮ್ಮನ್ನು ಸಂಪರ್ಕಿಸುವುದಕ್ಕಾಗಿ ತುರ್ತಾಗಿ ಪ್ರತಿಕ್ರಿಯಿಸುವವರ ಸಂಖ್ಯೆಯನ್ನು ನಿರ್ಬಂಧಿಸುವುದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="developer_title" msgid="9146088855661672353">"ಟೆಲಿಕಾಂ ಡೆವಲಪರ್ ಮೆನು"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ತುರ್ತು ಕರೆಯಲ್ಲಿರುವಾಗ ಕರೆಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="cancel" msgid="6733466216239934756">"ರದ್ದುಮಾಡಿ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 1a29b2e..30a1ec0 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"통화 관리"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"전화 통화"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"전화"</string>
<string name="unknown" msgid="6993977514360123431">"알 수 없음"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"부재중 전화"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"공중전화에서 걸려 온 통화 차단"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"알 수 없는 발신자"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"신원을 확인할 수 없는 발신자로부터 걸려 온 통화 차단"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"통화 차단"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"통화 차단이 사용 중지됨"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"긴급 통화가 사용됨"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"응급 구조 요원이 연락할 수 있도록 통화 차단이 사용 중지되었습니다."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom 개발자 메뉴"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"긴급 전화 중에는 전화를 받을 수 없습니다."</string>
+ <string name="cancel" msgid="6733466216239934756">"취소"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 83e498e..27fbbdc 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Чалууларды башкаруу"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефон чалуулар"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Белгисиз"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Кабыл алынбаган чалуу"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Телефон-автоматтардан келген чалууларды бөгөттөө"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Белгисиз"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Белгисиз чалуучуларды бөгөттөө"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Чалууну бөгөттөө"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Чалууну бөгөттөө өчүрүлдү"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Шашылыш чалуу аткарылды"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Өзгөчө кырдаалдардагы кызматчылар сиз менен байланышуусу үчүн чалууну бөгөттөө функциясы өчүрүлгөн."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom иштеп чыгуучусунун менюсу"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Шашылыш учурунда чалуулар кабыл алынбайт."</string>
+ <string name="cancel" msgid="6733466216239934756">"Жокко чыгаруу"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 64142ca..15cdb69 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ການຈັດການການໂທ"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ການໂທລະສັບ"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ໂທລະສັບ"</string>
<string name="unknown" msgid="6993977514360123431">"ບໍ່ຮູ້ຈັກ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ສາຍທີ່ບໍ່ໄດ້ຮັບ"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ບລັອກສາຍຈາກຕູ້ໂທ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ບໍ່ຮູ້ຈັກ"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ບລັອກສາຍຈາກຜູ້ໂທທີ່ລະບຸຕົວຕົນບໍ່ໄດ້"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ບໍ່ສາມາດໃຊ້ໄດ້"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ບລັອກການໂທເມື່ອໝາຍເລກບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ການບລັອກສາຍ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ປິດການບລັອກສາຍແລ້ວ"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ໂທສຸກເສີນແລ້ວ"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ປິດການບລັອກສາຍແລ້ວເພື່ອອະນຸຍາດໃຫ້ສາຍສຸກເສີນສາມາດຕິດຕໍ່ຫາທ່ານໄດ້."</string>
<string name="developer_title" msgid="9146088855661672353">"ເມນູນັກພັດທະນາໂທລະຄົມ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ບໍ່ສາມາດໂທໄດ້ໃນຂະນະທີ່ຢູ່ໃນການໂທສຸກເສີນ."</string>
+ <string name="cancel" msgid="6733466216239934756">"ຍົກເລີກ"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 29090d1..fbf22cd 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Skambučių tvarkymas"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefono skambučiai"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefonas"</string>
<string name="unknown" msgid="6993977514360123431">"Nežinomas"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Praleistas skambutis"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokuoti skambučius iš taksofonų"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nežinomas"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokuoti skambučius nuo nenustatytų skambintojų"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Skambučių blokavimas"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Skambučių blokavimas išjungtas"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Atliktas skambutis pagalbos numeriu"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Skambučių blokavimas išjungtas, kad pagalbos numeriu atsiliepusiems žmonėms būtų leidžiama su jumis susisiekti."</string>
<string name="developer_title" msgid="9146088855661672353">"Telekomunikacijų kūrėjų meniu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Atliekant skambutį pagalbos numeriu negalima atsiliepti į kitus skambučius."</string>
+ <string name="cancel" msgid="6733466216239934756">"Atšaukti"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 782777d..b58c43c 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Zvanu pārvaldība"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Tālruņa zvani"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Tālrunis"</string>
<string name="unknown" msgid="6993977514360123431">"Nezināms"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Neatbildēts zvans"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloķēt zvanus no taksofoniem"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nezināms"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloķēt zvanus no neidentificētiem zvanītājiem"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Zvanu bloķēšana"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Zvanu bloķēšana atspējota"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Ārkārtas zvans ir veikts"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Zvanu bloķēšana ir atspējota, lai ļautu ar jums sazināties avārijas dienestu darbiniekiem."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom izstrādātāja izvēlne"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Ārkārtas izsaukuma laikā nevar pieņemt zvanus."</string>
+ <string name="cancel" msgid="6733466216239934756">"Atcelt"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 99e211f..336ded2 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Управување со повици"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефонски повици"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Непознато"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Пропуштен повик"</string>
@@ -98,7 +98,7 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"Пропуштени повици"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Блокирање повици"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Повици во заднина"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Исклучени повици"</string>
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Прекинати повици"</string>
<string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Паднати апликации за телефон"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ако се воспостави повиков, вашиот повик на <xliff:g id="OTHER_APP">%1$s</xliff:g> ќе заврши."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Изберете како да се воспостави повиков"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокирај повици од телефонски говорници"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Непознато"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокирај повици од неидентификувани повикувачи"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокирање повици"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокирањето повици е оневозможено"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Воспоставен е итен повик"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокирањето повици е оневозможено за да им се овозможи на лицата од службите за итни случаи да контактираат со вас."</string>
<string name="developer_title" msgid="9146088855661672353">"Програмерско мени за телекомуникации"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Не може да примате повици во тек на итен повик."</string>
+ <string name="cancel" msgid="6733466216239934756">"Откажи"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 5c64034..47b4aa6c 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"കോൾ മാനേജ്മെന്റ്"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ഫോൺ കോളുകൾ"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ഫോണ്"</string>
<string name="unknown" msgid="6993977514360123431">"അജ്ഞാതം"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"മിസ്ഡ് കോൾ"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"പേ ഫോണുകളിൽ നിന്നുള്ള കോളുകൾ ബ്ലോക്ക് ചെയ്യുക"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"അജ്ഞാതം"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"തിരിച്ചറിയാത്ത കോളർമാരിൽ നിന്നുള്ള കോളുകൾ ബ്ലോക്ക് ചെയ്യുക"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ലഭ്യമല്ല"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"നമ്പർ ലഭ്യമല്ലാത്ത കോളുകൾ ബ്ലോക്ക് ചെയ്യുക"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"കോൾ ബ്ലോക്ക് ചെയ്യൽ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"കോൾ ബ്ലോക്ക് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"അടിയന്തര കോൾ ചെയ്തു"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"അടിയന്തരമായി ബന്ധപ്പെടുന്നവരെ അനുവദിക്കാനായി കോൾ ബ്ലോക്ക് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കി."</string>
<string name="developer_title" msgid="9146088855661672353">"ടെലികോം ഡെവലപ്പര് മെനു"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"അടിയന്തര കോളിലായിരിക്കുമ്പോൾ കോളുകൾ എടുക്കാനാവില്ല."</string>
+ <string name="cancel" msgid="6733466216239934756">"റദ്ദാക്കുക"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index cdef26b..4ba44f3 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Дуудлагын удирдлага"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Утасны дуудлага"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Утас"</string>
<string name="unknown" msgid="6993977514360123431">"Тодорхойгүй"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Аваагүй дуудлага"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Төлбөртэй утаснаас залгасан дуудлагуудыг хориглох"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Тодорхойгүй"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Тодорхойгүй дугаараас ирсэн дуудлагуудыг блоклох"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Боломжгүй"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Дугаар нь боломжгүй дуудлагуудыг блоклох"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Дуудлага хориглох"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Дуудлага хориглохыг идэвхгүй болгосон"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Яаралтай тусламжийн дуудлага хийсэн"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Яаралтай тусламжийнханд тантай холбогдохыг зөвшөөрөхийн тулд дуудлага хориглохыг идэвхгүй болгосон."</string>
<string name="developer_title" msgid="9146088855661672353">"Телеком хөгжүүлэгчийн цэс"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Яаралтай дуудлагын үеэр дуудлага авах боломжгүй."</string>
+ <string name="cancel" msgid="6733466216239934756">"Цуцлах"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 331cf5c..d4ddf6d 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"कॉल व्यवस्थापन"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"फोन कॉल"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"फोन"</string>
<string name="unknown" msgid="6993977514360123431">"अज्ञात"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"सुटलेला कॉल"</string>
@@ -94,7 +94,7 @@
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"आपल्या <xliff:g id="OTHER_CALL">%1$s</xliff:g> कॉलमुळे कॉल केला जाऊ शकत नाही."</string>
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"आपल्या <xliff:g id="OTHER_CALL">%1$s</xliff:g> कॉलमुळे कॉल केला जाऊ शकत नाही."</string>
<string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"दुसर्या ॲपमधील कॉलमुळे कॉल केला जाऊ शकत नाही."</string>
- <string name="notification_channel_incoming_call" msgid="5245550964701715662">"येणारे कॉल"</string>
+ <string name="notification_channel_incoming_call" msgid="5245550964701715662">"इनकमिंग कॉल"</string>
<string name="notification_channel_missed_call" msgid="7168893015283909012">"मिस्ड कॉल"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"कॉल ब्लॉक करणे"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"बॅकग्राउंड कॉल"</string>
@@ -111,13 +111,16 @@
<string name="phone_settings_private_num_txt" msgid="6339272760338475619">"खाजगी"</string>
<string name="phone_settings_private_num_summary_txt" msgid="6755758240544021037">"अशा कॉलरना ब्लॉक करा, जे त्यांचे क्रमांक उघड करत नाहीत"</string>
<string name="phone_settings_payphone_txt" msgid="5003987966052543965">"पे फोन"</string>
- <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फोनवरून येणारे कॉल ब्लॉक करा"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फोनवरून इनकमिंग कॉल ब्लॉक करा"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"अज्ञात"</string>
- <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अनोळखी कॉलरकडून येणारे कॉल ब्लॉक करा"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अनोळखी कॉलरकडून इनकमिंग कॉल ब्लॉक करा"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"उपलब्ध नाही"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"नंबर उपलब्ध नसल्यास, कॉल ब्लॉक करा"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"कॉल ब्लॉक करणे"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"कॉल ब्लॉक करणे बंद केले"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"आणीबाणी कॉल केला"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"आणीबाणीत प्रतिसाद देणार्यांना तुमच्याशी संपर्क साधण्याची अनुमती देण्यासाठी कॉल ब्लॉक करणे बंद केले आहे."</string>
<string name="developer_title" msgid="9146088855661672353">"टेलिकॉम डेव्हलपर मेनू"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"आणीबाणी कॉल दरम्यान कॉल घेतला जाऊ शकत नाही."</string>
+ <string name="cancel" msgid="6733466216239934756">"रद्द करा"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index b43b554..2103037 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Pengurusan Panggilan"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Panggilan Telefon"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Tidak diketahui"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Panggilan tidak dijawab"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Sekat panggilan daripada telefon awam"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tidak diketahui"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Sekat panggilan daripada pemanggil yang tidak dikenal pasti"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Sekatan Panggilan"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Sekatan Panggilan dilumpuhkan"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Panggilan kecemasan dibuat"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Sekatan Panggilan telah dilumpuhkan untuk membolehkan pasukan bantuan kecemasan menghubungi anda."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu Pembangun Telekom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Panggilan tidak boleh dijawab semasa dalam panggilan kecemasan."</string>
+ <string name="cancel" msgid="6733466216239934756">"Batal"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index c1b3124..e6eeaed 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ခေါ်ဆိုမှုစီမံခန့်ခွဲရေး"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ဖုန်းခေါ်ဆိုမှုများ"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ဖုန်း"</string>
<string name="unknown" msgid="6993977514360123431">"မသိပါ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"လွဲသွားသော ဖုန်းခေါ်မှု"</string>
@@ -98,7 +98,7 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"လွတ်သွားသော ဖုန်းခေါ်ဆိုမှုများ"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"ခေါ်ဆိုမှု ပိတ်ထားခြင်း"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"နောက်ခံမှ ခေါ်ဆိုမှုများ"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"ခေါ်ဆိုမှုများကို ဖြတ်တောက်လိုက်သည်"</string>
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"ပြတ်တောက်သွားသည့် ခေါ်ဆိုမှုများ"</string>
<string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"ရပ်တန့်သွားသော ဖုန်းအက်ပ်များ"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"ဤခေါ်ဆိုမှု ပြုလုပ်ပါက <xliff:g id="OTHER_APP">%1$s</xliff:g> သုံးပြီးပြောနေခြင်းကို ဖြတ်ပစ်ပါမည်။"</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"ဤခေါ်ဆိုမှု ပြုလုပ်ပုံကို ရွေးချယ်ပါ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"အများသုံးဖုန်းများမှ ခေါ်ဆိုမှုများကို ပိတ်ပါ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"အမည်မသိ"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"အမည်မသိသော ခေါ်ဆိုသူများကို ပိတ်ပါ"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ခေါ်ဆိုမှု ပိတ်ထားခြင်း"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"\'ခေါ်ဆိုမှု ပိတ်ခြင်း\' ကို ရပ်ထားပါသည်"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"အရေးပေါ် ခေါ်ဆိုမှု ပြုလုပ်ထားပါသည်"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"အရေးပေါ်တုံ့ပြန်သူများက သင့်အား ဆက်သွယ်နိုင်စေရန် \'ခေါ်ဆိုမှု ပိတ်ခြင်း\' ကို ရပ်ထားပါသည်။"</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom ဆော့ဖ်ဝဲအင်ဂျင်နီယာ မီနူး"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"အရေးပေါ်ခေါ်ဆိုမှု ပြုလုပ်နေစဉ် ဖုန်းမခေါ်နိုင်ပါ။"</string>
+ <string name="cancel" msgid="6733466216239934756">"မလုပ်တော့"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 3f65c62..80464ed 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Administrering av samtaler"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonanrop"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Ukjent"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Tapt anrop"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokkér anrop fra telefonkiosker"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ukjent"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokkér anrop fra oppringere som ikke er identifisert"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Anropsblokkering"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Anropsblokkering er slått av"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Nødanrop utført"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Anropsblokkering er slått av for å gjøre det mulig for nødtjenester å kontakte deg."</string>
<string name="developer_title" msgid="9146088855661672353">"Meny for telekommunikasjonsutviklere"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Du kan ikke besvare anrop mens du har et pågående nødanrop."</string>
+ <string name="cancel" msgid="6733466216239934756">"Avbryt"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 1e2b32f..ad2c99d 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -16,13 +16,13 @@
<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="3077225713817780583">"कल व्यवस्थापन"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"फोन कलहरू"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"फोन"</string>
<string name="unknown" msgid="6993977514360123431">"अज्ञात"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"छुटेका कल"</string>
<string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"छुटेको कार्यको कल"</string>
<string name="notification_missedCallsTitle" msgid="3910479625507893809">"छुटेका कल"</string>
- <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> छुटेका कलहरू"</string>
+ <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> मिस कलहरू"</string>
<string name="notification_missedCallTicker" msgid="6731461957487087769">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>बाट छुटेका कल"</string>
<string name="notification_missedCall_call_back" msgid="7900333283939789732">"फेरि कल गर्नुहोस्"</string>
<string name="notification_missedCall_message" msgid="4054698824390076431">"सन्देश"</string>
@@ -30,9 +30,9 @@
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"आपत्कालीन कल गरिएको हुनाले <xliff:g id="CALLER">%s</xliff:g> लाई गरिएको कल विच्छेद गरियो।"</string>
<string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"आपत्कालीन कल जारी रहेको हुनाले तपाईंको कल विच्छेद गरिएको छ।"</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"पृष्ठभूमिको कल"</string>
- <string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ले एउटा कल पृष्ठभूमिमा राखेको छ। कल गरेको बेला यो अनुप्रयोगले अडियोमाथि पहुँच राखेर प्ले गरिरहेको हुन सक्छ।"</string>
+ <string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ले एउटा कल पृष्ठभूमिमा राखेको छ। कल गरेको बेला यो एपले अडियोमाथि पहुँच राखेर प्ले गरिरहेको हुन सक्छ।"</string>
<string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> ले काम गर्न छाड्यो"</string>
- <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"कल गर्नका लागि तपाईंको यन्त्रमा पहिल्यैदेखि रहेको फोन एप प्रयोग गरियो"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"कल गर्नका लागि तपाईंको डिभाइसमा पहिल्यैदेखि रहेको फोन एप प्रयोग गरियो"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"कल म्युट भयो।"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"स्पिकरफोन सक्षम भयो।"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"अहिले कुरा गर्न मिल्दैन। के भइरहेको छ?"</string>
@@ -47,20 +47,20 @@
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> मा सन्देश पठाउन सकिएन।"</string>
<string name="enable_account_preference_title" msgid="6949224486748457976">"कलिङ खाताहरू"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"आपत्कालीन कलहरूलाई मात्र अनुमति दिइएको छ।"</string>
- <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"यो अनुप्रयोगले फोनको अनुमति बिना बहिर्गमन कलहरू गर्न सक्दैन।"</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"यो एपले फोनको अनुमति बिना बहिर्गमन कलहरू गर्न सक्दैन।"</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"एक कल गर्नको लागि, एक वैध नम्बर प्रविष्टि गर्नुहोस्।"</string>
<string name="duplicate_video_call_not_allowed" msgid="5754746140185781159">"यस समयमा कल थप गर्न सकिँदैन।"</string>
<string name="no_vm_number" msgid="2179959110602180844">"भ्वाइसमेल नम्बर हराइरहेको छ"</string>
<string name="no_vm_number_msg" msgid="1339245731058529388">"SIM कार्डमा कुनै पनि भ्वाइसमेल नम्बर भण्डारण भएको छैन।"</string>
<string name="add_vm_number_str" msgid="5179510133063168998">"नम्बर थप्नुहोस्"</string>
- <string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"तपाईंको पूर्वनिर्धारित फोन एप <xliff:g id="NEW_APP">%s</xliff:g> बनाउने हो?"</string>
- <string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"पूर्वनिर्धारित रूपमा सेट गर्नुहोस्"</string>
+ <string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"तपाईंको डिफल्ट फोन एप <xliff:g id="NEW_APP">%s</xliff:g> बनाउने हो?"</string>
+ <string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"डिफल्ट रूपमा सेट गर्नुहोस्"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"रद्द गर्नुहोस्"</string>
- <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> कलका सबै पक्षहरूलाई स्थापित गर्न र नियन्त्रण गर्न सक्षम हुने छ। तपाईंलाई विश्वास लाग्ने एपहरूलाई मात्र फोनमा पूर्वनिर्धारित एपका रूपमा सेट गर्नुपर्छ।"</string>
- <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"तपाईंको पूर्वनिर्धारित कल स्क्रिन एप <xliff:g id="NEW_APP">%s</xliff:g> बनाउने हो?"</string>
+ <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> कलका सबै पक्षहरूलाई स्थापित गर्न र नियन्त्रण गर्न सक्षम हुने छ। तपाईंलाई विश्वास लाग्ने एपहरूलाई मात्र फोनमा डिफल्ट एपका रूपमा सेट गर्नुपर्छ।"</string>
+ <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"तपाईंको डिफल्ट कल स्क्रिन एप <xliff:g id="NEW_APP">%s</xliff:g> बनाउने हो?"</string>
<string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> ले अब उप्रान्त कलहरू स्क्रिन गर्न सक्ने छैनन्।"</string>
- <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> ले तपाईंको सम्पर्कमा नभएका कल गर्ने व्यक्तिका जानकारी हेर्न सक्छ र तिनीहरूमाथि रोक लगाउन सक्छ। तपाईंलाई विश्वास लाग्ने एपहरूलाई मात्र कल स्क्रिन पूर्वनिर्धारित एपका रूपमा सेट गर्नुपर्छ।"</string>
- <string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"पूर्वनिर्धारित रूपमा सेट गर्नुहोस्"</string>
+ <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> ले तपाईंको सम्पर्कमा नभएका कल गर्ने व्यक्तिका जानकारी हेर्न सक्छ र तिनीहरूमाथि रोक लगाउन सक्छ। तपाईंलाई विश्वास लाग्ने एपहरूलाई मात्र कल स्क्रिन डिफल्ट एपका रूपमा सेट गर्नुपर्छ।"</string>
+ <string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"डिफल्ट रूपमा सेट गर्नुहोस्"</string>
<string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"रद्द गर्नुहोस्"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"रोकिएका नम्बरहरू"</string>
<string name="blocked_numbers_msg" msgid="2797422132329662697">"तपाईँले रोक लगाइएका नम्बरहरूबाट फोन वा टेक्स्ट म्यासेजहरू प्राप्त गर्नुहुने छैन।"</string>
@@ -73,7 +73,7 @@
<string name="non_primary_user" msgid="315564589279622098">"यन्त्रको मालिकले रोकिएका नम्बरहरूलाई हेर्न र व्यवस्थापन गर्न सक्छ।"</string>
<string name="delete_icon_description" msgid="5335959254954774373">"अनब्लक गर्नुहोस्"</string>
<string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"रोक लगाउने काम अस्थायी रूपमा निष्क्रिय छ"</string>
- <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"तपाईँले आपत्कालीन नम्बरमा डायल गरेपछि वा पाठ सन्देश पठाएपछि आपत्कालीन सेवाहरूले तपाईँलाई सम्पर्क गर्न सकून् भन्ने कुरा सुनिश्चित गर्न कलमाथिको अवरोध निष्क्रिय गरिन्छ।"</string>
+ <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"तपाईँले आपत्कालीन नम्बरमा डायल गरेपछि वा टेक्स्ट म्यासेज पठाएपछि आपत्कालीन सेवाहरूले तपाईँलाई सम्पर्क गर्न सकून् भन्ने कुरा सुनिश्चित गर्न कलमाथिको अवरोध निष्क्रिय गरिन्छ।"</string>
<string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"अब पुन:-सक्रिय गर्नुहोस्"</string>
<string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> माथि रोक लगाइयो"</string>
<string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> माथिको रोक हटाइयो"</string>
@@ -93,13 +93,13 @@
<string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"यस प्रकारका कलहरूलाई समर्थन गर्ने कुनै पनि कल गर्ने खाता नभएकाले कल गर्न सकिँदैन।"</string>
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"तपाईंको <xliff:g id="OTHER_CALL">%1$s</xliff:g> कलका कारण कल गर्न सकिँदैन।"</string>
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"तपाईंका <xliff:g id="OTHER_CALL">%1$s</xliff:g> कलहरूका कारण कल गर्न सकिँदैन।"</string>
- <string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"अर्को अनुप्रयोगमा जारी कलका कारण कल गर्न सकिँदैन।"</string>
+ <string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"अर्को एपमा जारी कलका कारण कल गर्न सकिँदैन।"</string>
<string name="notification_channel_incoming_call" msgid="5245550964701715662">"आगमन कलहरू"</string>
- <string name="notification_channel_missed_call" msgid="7168893015283909012">"छुटेका कलहरू"</string>
+ <string name="notification_channel_missed_call" msgid="7168893015283909012">"मिस कलहरू"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"कलमाथि रोक लगाउने सुविधा"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"ब्याकग्राउन्डका कलहरू"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"विच्छेद गरिएका कल"</string>
- <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"क्र्यास भएका फोन एपहरू"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"फोनमा रहेका क्र्यास भएका एपहरू"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"यो कल गर्नुले तपाईंको <xliff:g id="OTHER_APP">%1$s</xliff:g> कल अन्त्य गर्दछ।"</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"यो कल गर्ने तरिका छनौट गर्नुहोस्"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"<xliff:g id="OTHER_APP">%1$s</xliff:g> प्रयोग गरी कल रिडाइरेक्ट गर्नुहोस्"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फोनहरूबाट आउने कलहरूमाथि रोक लगाउनुहोस्"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"अज्ञात"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अज्ञात कल गर्ने व्यक्तिहरूको कलमाथि रोक लगाउनुहोस्"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"कलमाथि रोक लगाउने सुविधा"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"कलमाथि रोक लगाउने सुविधालाई असक्षम पारियो"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"आपत्कालीन कल गरियो"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"आपत्कालीन अवस्थामा उद्दार गर्ने मान्छेहरूलाई तपाईंलाई सम्पर्क गर्न दिन कलमाथि रोक लगाउने सुविधा असक्षम पारिएको छ।"</string>
<string name="developer_title" msgid="9146088855661672353">"टेलिकमको विकासकर्ताको मेनु"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"आपत्कालीन कल चलिराखेको बेलामा अरु कल स्वीकार गर्न सकिँदैन।"</string>
+ <string name="cancel" msgid="6733466216239934756">"रद्द गर्नुहोस्"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 166e95d..eea3a6f 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Oproepbeheer"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefoongesprekken"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefoon"</string>
<string name="unknown" msgid="6993977514360123431">"Onbekend"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Gemist gesprek"</string>
@@ -72,9 +72,9 @@
<string name="block_button" msgid="485080149164258770">"Blokkeren"</string>
<string name="non_primary_user" msgid="315564589279622098">"Alleen de eigenaar van het apparaat kan geblokkeerd nummers bekijken en beheren."</string>
<string name="delete_icon_description" msgid="5335959254954774373">"Blokkering opheffen"</string>
- <string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"Blokkering tijdelijk uitgeschakeld"</string>
+ <string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"Blokkering tijdelijk uitgezet"</string>
<string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"Als je een noodnummer belt of er een sms naartoe stuurt, wordt de blokkering uitgeschakeld om te zorgen dat hulpdiensten contact met je kunnen opnemen."</string>
- <string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Nu opnieuw inschakelen"</string>
+ <string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Nu opnieuw aanzetten"</string>
<string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> geblokkeerd"</string>
<string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"Blokkering van <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> opgeheven"</string>
<string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"Kan alarmnummer niet blokkeren."</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Gesprekken van betaaltelefoons blokkeren"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Onbekend"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Gesprekken van onbekende bellers blokkeren"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Niet beschikbaar"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Gesprekken blokkeren waarvoor het nummer niet beschikbaar is"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Gesprekken blokkeren"</string>
- <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Gesprekken blokkeren uitgeschakeld"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Gesprekken blokkeren staat uit"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Noodoproep geplaatst"</string>
- <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Gesprekken blokkeren is uitgeschakeld zodat nooddiensten je kunnen bereiken."</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Gesprekken blokkeren is uitgezet zodat nooddiensten je kunnen bereiken."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecomontwikkelaarsmenu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Gesprekken kunnen niet worden aangenomen tijdens een noodoproep."</string>
+ <string name="cancel" msgid="6733466216239934756">"Annuleren"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index e0061a7..b62be44 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"କଲ୍ ପରିଚାଳନା"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ଫୋନ୍ କଲଗୁଡ଼ିକ"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ଫୋନ୍ କରନ୍ତୁ"</string>
<string name="unknown" msgid="6993977514360123431">"ଅଜଣା"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ମିସଡ୍ କଲ୍"</string>
@@ -55,7 +55,7 @@
<string name="add_vm_number_str" msgid="5179510133063168998">"ନମ୍ବର୍ ଯୋଡ଼ନ୍ତୁ"</string>
<string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"<xliff:g id="NEW_APP">%s</xliff:g>କୁ ଆପଣଙ୍କ ଫୋନ୍ର ଡିଫଲ୍ଟ ଆପ୍ କରିବେ?"</string>
<string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"ଡିଫଲ୍ଟ ସେଟ୍ କରନ୍ତୁ"</string>
- <string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> କଲ୍ କରିବା ଏବଂ କଲ୍ର ସମସ୍ତ ଦିଗକୁ ନିୟନ୍ତ୍ରଣ କରିବାରେ ସକ୍ଷମ ହେବ। କେବଳ ନିଜର ଭରସାଯୋଗ୍ୟ ଆପ୍କୁ ଡିଫଲ୍ଟ ଫୋନ୍ ଆପ୍ ଭାବେ ସେଟ୍ କରିବା ଉଚିତ୍।"</string>
<string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"<xliff:g id="NEW_APP">%s</xliff:g>କୁ ଆପଣଙ୍କ ଡିଫଲ୍ଟ କଲ୍ ସ୍କ୍ରିନିଂ ଆପ୍ କରିବେ?"</string>
<string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> କଲ୍ ସ୍କ୍ରିନ୍ କରିପାରିରିବେ ନାହିଁ।"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ପେ-ଫୋନ୍ରୁ କଲ୍କୁ ଅବରୋଧ କରନ୍ତୁ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ଅଜଣା"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ଅଜଣା କଲରର କଲ୍କୁ ବ୍ଲକ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"କଲ୍ ବ୍ଲକିଂ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"କଲ୍ ବ୍ଲକିଂକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ଜରୁରିକାଳୀନ କଲ୍ କରାଗଲା"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ଜରୁରିକାଳୀନ ସହାୟତା କର୍ମଚାରୀମାନେ ଆପଣଙ୍କୁ ଯୋଗଯୋଗ କରିବା ପାଇଁ କଲ୍ ଅବରୋଧକୁ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
<string name="developer_title" msgid="9146088855661672353">"ଟେଲେକମ୍ ଡେଭେଲପର୍ ମେନୁ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ଜରୁରୀକାଳୀନ କଲ୍ ବେଳେ ଅନ୍ୟ କଲ୍ ଉଠାଇ ପାରିବେ ନାହିଁ।"</string>
+ <string name="cancel" msgid="6733466216239934756">"ବାତିଲ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 2b94316..2acb72a 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ਕਾਲ ਪ੍ਰਬੰਧਨ"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ਫ਼ੋਨ ਕਾਲਾਂ"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ਫ਼ੋਨ"</string>
<string name="unknown" msgid="6993977514360123431">"ਅਗਿਆਤ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"ਮਿਸਡ ਕਾਲ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ਜਨਤਕ ਫ਼ੋਨਾਂ ਵਾਲੀਆਂ ਕਾਲਾਂ ਬਲਾਕ ਕਰੋ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ਅਗਿਆਤ"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ਅਣਪਛਾਤੇ ਕਾਲਰਾਂ ਵਾਲੀਆਂ ਕਾਲਾਂ ਬਲਾਕ ਕਰੋ"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ਕਾਲ ਬਲਾਕ ਕਰਨਾ"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ਕਾਲ ਬਲਾਕਿੰਗ ਵਿਕਲਪ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕੀਤੀ ਗਈ"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ਸੰਕਟਕਾਲੀਨ ਸਥਿਤੀ ਵਿੱਚ ਮਦਦ ਕਰਨ ਵਾਲੇ ਵਿਅਕਤੀ ਨੂੰ ਤੁਹਾਨੂੰ ਸੰਪਰਕ ਕਰਨ ਦੇਣ ਲਈ ਕਾਲ ਬਲਾਕਿੰਗ ਵਿਕਲਪ ਬੰਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ।"</string>
<string name="developer_title" msgid="9146088855661672353">"ਟੈਲੀਕੋਮ ਵਿਕਾਸਕਾਰ ਮੀਨੂ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ਕਿਸੇ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਦੌਰਾਨ ਹੋਰ ਕਾਲਾਂ ਨਹੀਂ ਲਈਆਂ ਜਾ ਸਕਦੀਆਂ।"</string>
+ <string name="cancel" msgid="6733466216239934756">"ਰੱਦ ਕਰੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 9cb1980..8c144e6 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Zarządzanie połączeniami"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Połączenia telefoniczne"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Nieznany"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Nieodebrane połączenie"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokuj połączenia z budek telefonicznych"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nieznane"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokuj połączenia z nieznanych numerów"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokowanie połączeń"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokowanie połączeń wyłączone"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Wykonano połączenie alarmowe"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokowanie połączeń zostało wyłączone, aby służby ratownicze mogły się z Tobą skontaktować."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu programisty Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Nie można odbierać rozmów przy nawiązanym połączeniu alarmowym."</string>
+ <string name="cancel" msgid="6733466216239934756">"Anuluj"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index bb5213e..10e3a96 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestão de chamadas"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Chamadas telefónicas"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefone"</string>
<string name="unknown" msgid="6993977514360123431">"Desconhecido"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Chamada não atendida"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquear chamadas de telefones públicos"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconhecidas"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear chamadas não identificadas"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueio de chamadas"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Bloqueio de chamadas desativado"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Chamada de emergência efetuada"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"O bloqueio de chamadas foi desativado para permitir a receção de contactos de resposta a emergências."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu do programador de telecomunicações"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Não é possível atender chamadas durante uma chamada de emergência."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 5d88619..96ff25b 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gerenciamento de chamadas"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Chamadas telefônicas"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefone"</string>
<string name="unknown" msgid="6993977514360123431">"Desconhecido"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Chamada perdida"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquear chamadas de orelhão"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconhecido"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear chamadas de autores não identificados"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueio de chamadas"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Bloqueio de chamadas desativado"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"A chamada de emergência foi feita"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"O bloqueio de chamadas foi desativado para permitir que a equipe de emergência entre em contato com você."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu do desenvolvedor de telecomunicação"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Durante uma chamada de emergência, não é possível transferir chamadas para o dispositivo."</string>
+ <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index a95d4a4..75f87a2 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Gestionarea apelurilor"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Apeluri telefonice"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Necunoscut"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Apel nepreluat"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blocați apelurile de la telefoane publice"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Necunoscut"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blocați apelurile de la apelanți neidentificați"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocarea apelurilor"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocarea apelurilor este dezactivată."</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"S-a efectuat un apel de urgență."</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blocarea apelurilor a fost dezactivată pentru a permite serviciilor de urgență să vă contacteze."</string>
<string name="developer_title" msgid="9146088855661672353">"Meniu pentru dezvoltatori de telecomunicații"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Nu puteți răspunde la apeluri în timpul unui apel de urgență."</string>
+ <string name="cancel" msgid="6733466216239934756">"Anulați"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index a50907a..6382c7b 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Управление звонками"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефонные звонки"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Неизвестный абонент"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Пропущенный вызов"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокировать вызовы с телефонов-автоматов"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Неизвестные номера"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокировать вызовы с неопределяемых номеров"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Неизвестный номер"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блокировать звонки, если номер неизвестен"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокировка вызовов"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокировка вызовов отключена"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Выполнен экстренный вызов"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокировка вызовов отключена, чтобы у экстренных служб была возможность позвонить вам."</string>
<string name="developer_title" msgid="9146088855661672353">"Меню разработчика Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Невозможно принять вызов, когда уже выполняется экстренный вызов."</string>
+ <string name="cancel" msgid="6733466216239934756">"Отмена"</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index b73272b..4c211cf 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"ඇමතුම් කළමනාකරණය"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"දුරකථන ඇමතුම්"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"දුරකථනය"</string>
<string name="unknown" msgid="6993977514360123431">"නොදනී"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"මඟ හැරුණු ඇමතුම"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ගෙවුම් දුරකථන වෙතින් වන ඇමතුම් අවහිර කරන්න"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"නොදනී"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"නොහඳුනන අමතන්නන් වෙතින් වන ඇමතුම් අවහිර කරන්න"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ඇමතුම් අවහිර කිරීම"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ඇමතුම් අවහිර කිරීම අබල කර ඇත"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"හදිසි ඇමතුම් ගැනීම"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"හදිසි අමතන්නන්ට ඔබව සම්බන්ධ කර ගැනීමට ඉඩ දීමට ඇමතුම් අවහිර කිරීම අබල කර ඇත."</string>
<string name="developer_title" msgid="9146088855661672353">"ටෙලිකොම් සංවර්ධක මෙනුව"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"හදිසි ඇමතුමක් අතරතුර ඇමතුම් ගත නොහැකිය."</string>
+ <string name="cancel" msgid="6733466216239934756">"අවලංගු කරන්න"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 0d79f1a..bddeeef 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Správa hovorov"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonické hovory"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefón"</string>
<string name="unknown" msgid="6993977514360123431">"Neznáme"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Zmeškaný hovor"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokovať hovory z verejných telefónov"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Neznáme číslo"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokovať hovory od nerozpoznaných volajúcich"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokovanie hovorov"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokovanie hovorov je vypnuté"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Bolo uskutočnené tiesňové volanie"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokovanie hovorov bolo vypnuté, aby vás mohli kontaktovať pracovníci tiesňových služieb."</string>
<string name="developer_title" msgid="9146088855661672353">"Ponuka pre vývojárov Telecomu"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Počas tiesňového volania nie je možné prijímať hovory."</string>
+ <string name="cancel" msgid="6733466216239934756">"Zrušiť"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 5595c40..5bc9d83 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Upravljanje klicev"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonski klici"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Neznano"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Neodgovorjeni klic"</string>
@@ -57,9 +57,9 @@
<string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"Nastavi za privzeto"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"Prekliči"</string>
<string name="change_default_dialer_warning_message" msgid="8461963987376916114">"V aplikaciji <xliff:g id="NEW_APP">%s</xliff:g> bo mogoče opravljati klice in nadzirati vse vidike klicev. Kot privzeto aplikacijo za klicanje nastavite samo aplikacije, ki jim zaupate."</string>
- <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Želite, da je <xliff:g id="NEW_APP">%s</xliff:g> privzeta aplikacija za pregled klicev?"</string>
+ <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Želite, da je <xliff:g id="NEW_APP">%s</xliff:g> privzeta aplikacija za preverjanje klicev?"</string>
<string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"V aplikaciji <xliff:g id="OLD_APP">%s</xliff:g> ne bo več mogoč predhodni pregled klicev."</string>
- <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"V aplikaciji <xliff:g id="NEW_APP">%s</xliff:g> si bo mogoče ogledati podatke o klicateljih, ki niso na vašem seznamu stikov, in bo mogoče blokirati te klice. Kot privzeto aplikacijo za predhodni pregled klicev nastavite samo aplikacije, ki jim zaupate."</string>
+ <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"V aplikaciji <xliff:g id="NEW_APP">%s</xliff:g> si bo mogoče ogledati podatke o klicateljih, ki niso na vašem seznamu stikov, in bo mogoče blokirati te klice. Kot privzeto aplikacijo za predhodno preverjanje klicev nastavite samo aplikacije, ki jim zaupate."</string>
<string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"Nastavi za privzeto"</string>
<string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"Prekliči"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"Blokirane številke"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte klice iz telefonskih govorilnic"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Neznano"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokiranje klicev neznanih klicateljev"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Ni na voljo"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokirajte klice, pri katerih številka ni na voljo."</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje klicev"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje klicev je onemogočeno"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Opravljen je klic v sili"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje klicev je onemogočeno, da lahko stik z vami vzpostavijo uslužbenci služb za klic v sili."</string>
<string name="developer_title" msgid="9146088855661672353">"Meni za razvijalce Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Med klicem v sili ni mogoče sprejeti klicev."</string>
+ <string name="cancel" msgid="6733466216239934756">"Prekliči"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 53f4efc..9ef0eeb 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Menaxhimi i thirrjes"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonatat"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefoni"</string>
<string name="unknown" msgid="6993977514360123431">"I panjohur"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Telefonatë e humbur"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blloko telefonatat nga telefonat me pagesë"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"E panjohur"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blloko telefonatat nga telefonuesit e paidentifikuar"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bllokimi i telefonatave"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Bllokimi i telefonatave u çaktivizua"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Telefonata e urgjencës u krye"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Bllokimi i telefonatave është çaktivizuar për të lejuar që personat që përgjigjen në rast urgjence të kontaktojnë me ty."</string>
<string name="developer_title" msgid="9146088855661672353">"Menyja e zhvilluesit të telekomunikimit"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Nuk mund të marrësh telefonata kur je në një telefonatë urgjence."</string>
+ <string name="cancel" msgid="6733466216239934756">"Anulo"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index adfece0..0027094 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Управљање позивима"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефонски позиви"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Непознато"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Пропуштен позив"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокирајте позиве са телефонских говорница"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Непознати бројеви"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокирајте позиве неидентификованих позивалаца"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокирање позива"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокирање позива је онемогућено"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Упућен је хитни позив"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокирање позива је онемогућено да би хитне службе могле да вас контактирају."</string>
<string name="developer_title" msgid="9146088855661672353">"Мени за програмере Telecom-а"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"За време хитног позива није могуће преузимати друге позиве."</string>
+ <string name="cancel" msgid="6733466216239934756">"Откажи"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 70c4566..34a3b6d 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Samtalshantering"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefonsamtal"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Okänd"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Missat samtal"</string>
@@ -75,7 +75,7 @@
<string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"Blockeringen har inaktiverats tillfälligt"</string>
<string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"När du ringer eller sms:ar ett nödnummer inaktiveras blockering för att säkerställa att räddningstjänsten kan kontakta dig."</string>
<string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Återaktivera nu"</string>
- <string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> blockerade"</string>
+ <string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> har blockerats"</string>
<string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> avblockerat"</string>
<string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"Det går inte att blockera nödnummer."</string>
<string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> är redan blockerat."</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blockera samtal från telefonautomater"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Okänd"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blockera samtal från oidentifierade uppringare"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Inte tillgängligt"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blockera samtal med ej tillgängligt nummer"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Samtalsblockering"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Samtalsblockering inaktiverad"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Nödsamtal ringt"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Samtalsblockering har inaktiverats för att tillåta att räddningstjänsten kontaktar dig."</string>
<string name="developer_title" msgid="9146088855661672353">"Meny för telekomutvecklare"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Det går inte att besvara samtal medan ett nödsamtal pågår."</string>
+ <string name="cancel" msgid="6733466216239934756">"Avbryt"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 8b8a40c..c4301dc 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Kudhibiti Simu"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Simu"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Simu"</string>
<string name="unknown" msgid="6993977514360123431">"Haijulikani"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Simu uliyokosa"</string>
@@ -43,7 +43,7 @@
<string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"Hariri majibu ya haraka"</string>
<string name="respond_via_sms_setting_summary" msgid="8054571501085436868"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"Majibu ya haraka"</string>
- <string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"Ujumbe uliotumwa kwa <xliff:g id="PHONE_NUMBER">%s</xliff:g> ."</string>
+ <string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"Ujumbe umetumwa kwa <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"Imeshindwa kutuma SMS kwa <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
<string name="enable_account_preference_title" msgid="6949224486748457976">"Akaunti za simu"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Piga simu za dharura pekee."</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Zuia simu kutoka kwa nambari ya simu za kulipia"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Zisizojulikani"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Zuia simu kutoka kwa wapigaji wasiojulikana"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Kuzuia Simu"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Kipengele cha Kuzuia Simu kimezimwa"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Simu ya dharura imepigwa"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Kipengele cha Kuzuia Simu kimezimwa ili kuruhusu wapigaji simu za dharura kuwasiliana nawe."</string>
<string name="developer_title" msgid="9146088855661672353">"Menyu ya Msanidi programu wa Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Huwezi kupokea simu nyingine wakati unashiriki katika simu ya dharura."</string>
+ <string name="cancel" msgid="6733466216239934756">"Ghairi"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index ee48214..a0ecb41 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"அழைப்பு நிர்வாகம்"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ஃபோன் அழைப்புகள்"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ஃபோன்"</string>
<string name="unknown" msgid="6993977514360123431">"தெரியாதவர்"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"தவறிய அழைப்பு"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"கட்டண ஃபோன்களில் இருந்து வரும் அழைப்புகளைத் தடுக்கும்"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"தெரியாத அழைப்புகள்"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"அடையாளம் தெரியாத அழைப்பாளர்களின் அழைப்புகளைத் தடுக்கும்"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"அழைப்புத் தடுப்பு"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"அழைப்புத் தடுப்பு முடக்கப்பட்டுள்ளது"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"அவசர அழைப்பு செய்யப்பட்டது"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"அவசரநிலையில் பதிலளிப்பவர்களை உங்களைத் தொடர்புகொள்வதற்கு அனுமதிக்க, அழைப்புத் தடுப்பு முடக்கப்பட்டுள்ளது."</string>
<string name="developer_title" msgid="9146088855661672353">"டெலிகாம் டெவெலப்பர் மெனு"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"அவசர அழைப்பின்போது அழைப்புகளை ஏற்க முடியாது."</string>
+ <string name="cancel" msgid="6733466216239934756">"ரத்துசெய்"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 58eb225..b904115 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -16,16 +16,16 @@
<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="3077225713817780583">"కాల్ నిర్వహణ"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ఫోన్ కాల్స్"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ఫోన్"</string>
<string name="unknown" msgid="6993977514360123431">"తెలియదు"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"సమాధానం ఇవ్వని కాల్"</string>
<string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"మిస్డ్ కార్యాలయ కాల్"</string>
<string name="notification_missedCallsTitle" msgid="3910479625507893809">"సమాధానం ఇవ్వని కాల్స్"</string>
- <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> సమాధానం ఇవ్వని కాల్లు"</string>
+ <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> సమాధానం ఇవ్వని కాల్స్"</string>
<string name="notification_missedCallTicker" msgid="6731461957487087769">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> నుండి సమాధానం ఇవ్వని కాల్"</string>
<string name="notification_missedCall_call_back" msgid="7900333283939789732">"కాల్ చేయి"</string>
- <string name="notification_missedCall_message" msgid="4054698824390076431">"సందేశం"</string>
+ <string name="notification_missedCall_message" msgid="4054698824390076431">"మెసేజ్"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"కాల్ డిస్కనెక్ట్ చేయబడింది"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"అత్యవసర కాల్ చేయబడినందున <xliff:g id="CALLER">%s</xliff:g>తో కాల్ డిస్కనెక్ట్ చేయబడింది."</string>
<string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"అత్యవసర కాల్ చేయబడినందున మీ కాల్ డిస్కనెక్ట్ చేయబడింది."</string>
@@ -40,40 +40,40 @@
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"నేను మీకు తర్వాత కాల్ చేస్తాను."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"ఇప్పుడు మాట్లాడలేను. నాకు తర్వాత కాల్ చేస్తారా?"</string>
<string name="respond_via_sms_setting_title" msgid="4762275482898830160">"శీఘ్ర ప్రతిస్పందనలు"</string>
- <string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"శీఘ్ర ప్రతిస్పందనల సవరణ"</string>
+ <string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"క్విక్ రెస్పాన్స్లను ఎడిట్ చేయండి"</string>
<string name="respond_via_sms_setting_summary" msgid="8054571501085436868"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"శీఘ్ర ప్రతిస్పందన"</string>
- <string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>కు సందేశం పంపబడింది."</string>
- <string name="respond_via_sms_failure_format" msgid="5198680980054596391">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>కు సందేశాన్ని పంపడం విఫలమైంది."</string>
+ <string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>కు మెసేజ్ పంపబడింది."</string>
+ <string name="respond_via_sms_failure_format" msgid="5198680980054596391">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>కు మెసేజ్ను పంపడం విఫలమైంది."</string>
<string name="enable_account_preference_title" msgid="6949224486748457976">"కాలింగ్ ఖాతాలు"</string>
- <string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"కేవలం అత్యవసర కాల్లు మాత్రమే అనుమతించబడతాయి."</string>
- <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"ఈ అనువర్తనం ఫోన్ అనుమతి లేకుండా అవుట్గోయింగ్ కాల్లను చేయలేదు."</string>
+ <string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"కేవలం అత్యవసర కాల్స్ మాత్రమే అనుమతించబడతాయి."</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"ఈ యాప్ ఫోన్ అనుమతి లేకుండా అవుట్గోయింగ్ కాల్స్ను చేయలేదు."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"కాల్ చేయడానికి, చెల్లుబాటు అయ్యే నంబర్ను నమోదు చేయండి."</string>
<string name="duplicate_video_call_not_allowed" msgid="5754746140185781159">"ఈ సమయంలో కాల్ను జోడించడం సాధ్యపడదు."</string>
<string name="no_vm_number" msgid="2179959110602180844">"వాయిస్ మెయిల్ నంబర్ లేదు"</string>
<string name="no_vm_number_msg" msgid="1339245731058529388">"సిమ్ కార్డులో వాయిస్ మెయిల్ నంబర్ ఏదీ నిల్వ చేయబడలేదు."</string>
<string name="add_vm_number_str" msgid="5179510133063168998">"నంబర్ను జోడించు"</string>
- <string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"<xliff:g id="NEW_APP">%s</xliff:g>ని మీ డిఫాల్ట్ ఫోన్ అనువర్తనంగా చేయాలా?"</string>
- <string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"డిఫాల్ట్గా సెట్ చేయండి"</string>
+ <string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"<xliff:g id="NEW_APP">%s</xliff:g>ను మీ ఆటోమేటిక్ ఫోన్ యాప్గా చేయాలా?"</string>
+ <string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"ఆటోమేటిక్గా సెట్ చేయండి"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"రద్దు చేయి"</string>
- <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> అన్ని రకాల కాల్లను చేయగలదు మరియు సంబంధిత అన్ని అంశాలను నియంత్రించగలదు. మీరు విశ్వసించే అనువర్తనాలను మాత్రమే డిఫాల్ట్ ఫోన్ అనువర్తనంగా సెట్ చేయాలి."</string>
- <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"<xliff:g id="NEW_APP">%s</xliff:g>ని మీ డిఫాల్ట్ కాల్ స్క్రీనింగ్ యాప్గా సెట్ చేయాలా?"</string>
- <string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> ఇకపై స్క్రీన్ కాల్లను చేయలేదు."</string>
- <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> మీ పరిచయాలలో లేని కాలర్ల గురించిన సమాచారాన్ని చూడగలుగుతుంది మరియు ఈ కాల్లను బ్లాక్ చేయగలుగుతుంది. మీరు విశ్వసించే యాప్లను మాత్రమే డిఫాల్ట్ కాల్ స్క్రీన్ యాప్గా సెట్ చేయాలి."</string>
- <string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"డిఫాల్ట్గా సెట్ చేయి"</string>
+ <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> అన్ని రకాల కాల్స్ను చేయగలదు, సంబంధిత అన్ని అంశాలను కంట్రోల్ చేయగలదు. మీరు విశ్వసించే యాప్లను మాత్రమే ఆటోమేటిక్ ఫోన్ యాప్గా సెట్ చేయాలి."</string>
+ <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"<xliff:g id="NEW_APP">%s</xliff:g>ను మీ ఆటోమేటిక్ కాల్ స్క్రీనింగ్ యాప్గా సెట్ చేయాలా?"</string>
+ <string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> ఇకపై స్క్రీన్ కాల్స్ను చేయలేదు."</string>
+ <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> మీ కాంటాక్టుల్లో లేని కాలర్ల సమాచారాన్ని చూడగలుగుతుంది, అలాగే ఈ కాల్స్ను బ్లాక్ చేయగలుగుతుంది. మీరు విశ్వసించే యాప్లను మాత్రమే ఆటోమేటిక్ కాల్ స్క్రీనింగ్ యాప్గా సెట్ చేయాలి."</string>
+ <string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"ఆటోమేటిక్గా సెట్ చేయండి"</string>
<string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"రద్దు చేయి"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"బ్లాక్ చేయబడిన నంబర్లు"</string>
- <string name="blocked_numbers_msg" msgid="2797422132329662697">"మీరు బ్లాక్ చేయబడిన నంబర్ల నుండి కాల్లు లేదా వచన సందేశాలను స్వీకరించరు."</string>
+ <string name="blocked_numbers_msg" msgid="2797422132329662697">"మీరు బ్లాక్ చేయబడిన నంబర్ల నుండి కాల్స్ లేదా వచన మెసేజ్లను స్వీకరించరు."</string>
<string name="block_number" msgid="3784343046852802722">"నంబర్ను జోడించండి"</string>
<string name="unblock_dialog_body" msgid="2723393535797217261">"<xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>ని అన్బ్లాక్ చేయాలా?"</string>
<string name="unblock_button" msgid="8732021675729981781">"అన్బ్లాక్ చేయి"</string>
- <string name="add_blocked_dialog_body" msgid="8599974422407139255">"దీని నుండి కాల్లు మరియు సందేశాలను బ్లాక్ చేయండి"</string>
+ <string name="add_blocked_dialog_body" msgid="8599974422407139255">"దీని నుండి కాల్స్ మరియు మెసేజ్లను బ్లాక్ చేయండి"</string>
<string name="add_blocked_number_hint" msgid="8769422085658041097">"ఫోన్ నంబర్"</string>
<string name="block_button" msgid="485080149164258770">"బ్లాక్ చేయి"</string>
<string name="non_primary_user" msgid="315564589279622098">"కేవలం పరికర యజమాని మాత్రమే బ్లాక్ చేసిన నంబర్లను వీక్షించగలరు మరియు నిర్వహించగలరు."</string>
<string name="delete_icon_description" msgid="5335959254954774373">"అన్బ్లాక్ చేస్తుంది"</string>
<string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"బ్లాకింగ్ తాత్కాలికంగా ఆఫ్ చేయబడింది"</string>
- <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"మీరు అత్యవసర నంబర్కి డయల్ చేసాక లేదా వచన సందేశం పంపాక, అత్యవసర సేవలు తిరిగి మిమ్మల్ని సంప్రదించగలిగేలా చేయడానికి బ్లాకింగ్ ఆఫ్ చేయబడుతుంది."</string>
+ <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"మీరు అత్యవసర నంబర్కి డయల్ చేసాక లేదా వచన మెసేజ్ పంపాక, అత్యవసర సేవలు తిరిగి మిమ్మల్ని సంప్రదించగలిగేలా చేయడానికి బ్లాకింగ్ ఆఫ్ చేయబడుతుంది."</string>
<string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"ఇప్పుడే మళ్లీ ప్రారంభించు"</string>
<string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> బ్లాక్ చేయబడింది"</string>
<string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> అన్బ్లాక్ చేయబడింది"</string>
@@ -83,17 +83,17 @@
<string name="notification_incoming_call" msgid="1233481138362230894">"<xliff:g id="CALL_FROM">%2$s</xliff:g> నుండి <xliff:g id="CALL_VIA">%1$s</xliff:g> కాల్"</string>
<string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_FROM">%2$s</xliff:g> నుండి <xliff:g id="CALL_VIA">%1$s</xliff:g> వీడియో కాల్"</string>
<string name="answering_ends_other_call" msgid="8653544281903986641">"సమాధానమివ్వడం వలన మీ <xliff:g id="CALL_VIA">%1$s</xliff:g> కాల్ ముగుస్తుంది"</string>
- <string name="answering_ends_other_calls" msgid="3702302838456922535">"సమాధానమివ్వడం వలన మీ <xliff:g id="CALL_VIA">%1$s</xliff:g> కాల్లు ముగుస్తాయి"</string>
+ <string name="answering_ends_other_calls" msgid="3702302838456922535">"సమాధానమివ్వడం వలన మీ <xliff:g id="CALL_VIA">%1$s</xliff:g> కాల్స్ ముగుస్తాయి"</string>
<string name="answering_ends_other_video_call" msgid="8572022039304239958">"సమాధానమివ్వడం వలన మీ <xliff:g id="CALL_VIA">%1$s</xliff:g> వీడియో కాల్ ముగుస్తుంది"</string>
<string name="answering_ends_other_managed_call" msgid="4031778317409881805">"సమాధానమివ్వడం వలన మీ కొనసాగుతున్న కాల్ ముగుస్తుంది"</string>
- <string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"సమాధానమివ్వడం వలన మీ కొనసాగుతున్న కాల్లు ముగుస్తాయి"</string>
+ <string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"సమాధానమివ్వడం వలన మీ కొనసాగుతున్న కాల్స్ ముగుస్తాయి"</string>
<string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"సమాధానమివ్వడం వలన మీ కొనసాగుతున్న వీడియో కాల్ ముగుస్తుంది"</string>
<string name="answer_incoming_call" msgid="2045888814782215326">"సమాధానమివ్వండి"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"తిరస్కరించు"</string>
- <string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"కాల్ చేయడం సాధ్యపడదు ఎందుకంటే, ఈ రకమైన కాల్లకు మద్దతిచ్చే కాల్ చేయడానికి ఉపయోగించే ఖాతాలు లేవు."</string>
+ <string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"కాల్ చేయడం సాధ్యపడదు ఎందుకంటే, ఈ రకమైన కాల్స్కు మద్దతిచ్చే కాల్ చేయడానికి ఉపయోగించే ఖాతాలు లేవు."</string>
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"మీ <xliff:g id="OTHER_CALL">%1$s</xliff:g> కాల్ కొనసాగుతున్నందున కాల్ చేయడం సాధ్యపడదు."</string>
- <string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"మీ <xliff:g id="OTHER_CALL">%1$s</xliff:g> కాల్లు కొనసాగుతున్నందున కాల్ చేయడం సాధ్యపడదు."</string>
- <string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"వేరొక అనువర్తనంలో కాల్ కొనసాగుతున్నందున కాల్ చేయడం సాధ్యపడదు."</string>
+ <string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"మీ <xliff:g id="OTHER_CALL">%1$s</xliff:g> కాల్స్ కొనసాగుతున్నందున కాల్ చేయడం సాధ్యపడదు."</string>
+ <string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"వేరొక యాప్లో కాల్ కొనసాగుతున్నందున కాల్ చేయడం సాధ్యపడదు."</string>
<string name="notification_channel_incoming_call" msgid="5245550964701715662">"ఇన్కమింగ్ కాల్స్"</string>
<string name="notification_channel_missed_call" msgid="7168893015283909012">"సమాధానం ఇవ్వని కాల్స్"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"కాల్ బ్లాక్ చేయడం"</string>
@@ -106,18 +106,21 @@
<string name="alert_place_unredirect_outgoing_call" msgid="2467608535225764006">"నా ఫోన్ నంబర్ ఉపయోగించి కాల్ చేయి"</string>
<string name="alert_redirect_outgoing_call_timeout" msgid="5568101425637373060">"<xliff:g id="OTHER_APP">%1$s</xliff:g> ద్వారా కాల్ చేయలేము. వేరే కాల్ మళ్లింపు యాప్ ఉపయోగించండి లేదా సహాయం కోసం డెవలపర్ను సంప్రదించడానికి ప్రయత్నించండి."</string>
<string name="phone_settings_call_blocking_txt" msgid="7311523114822507178">"కాల్ బ్లాక్ చేయడం"</string>
- <string name="phone_settings_number_not_in_contact_txt" msgid="2602249106007265757">"పరిచయాలలో లేని నంబర్లు"</string>
- <string name="phone_settings_number_not_in_contact_summary_txt" msgid="963327038085718969">"మీ పరిచయాలలో లేని నంబర్లను బ్లాక్ చేయండి"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="2602249106007265757">"కాంటాక్ట్లలో లేని నంబర్లు"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="963327038085718969">"మీ కాంటాక్ట్ల్లో లేని నంబర్లను బ్లాక్ చేయండి"</string>
<string name="phone_settings_private_num_txt" msgid="6339272760338475619">"ప్రైవేట్"</string>
<string name="phone_settings_private_num_summary_txt" msgid="6755758240544021037">"తమ నంబర్ను కనిపించకుండా చేసే కాలర్లను బ్లాక్ చేయండి"</string>
<string name="phone_settings_payphone_txt" msgid="5003987966052543965">"పే ఫోన్"</string>
- <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"పే ఫోన్ల నుండి కాల్లను బ్లాక్ చేయండి"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"పే ఫోన్ల నుండి కాల్స్ను బ్లాక్ చేయండి"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"తెలియని"</string>
- <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"తెలియని కాలర్ల నుండి కాల్లను బ్లాక్ చేయండి"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"తెలియని కాలర్ల నుండి కాల్స్ను బ్లాక్ చేయండి"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"అందుబాటులో లేని నంబర్లు"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"నంబర్ అందుబాటులో లేనప్పుడు కాల్స్ను బ్లాక్ చేయండి"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"కాల్ బ్లాక్ చేయడం"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"కాల్ బ్లాక్ చేయడం నిలిపివేయబడింది"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"అత్యవసర కాల్ చేయబడింది"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"మిమ్మల్ని సంప్రదించడానికి అత్యవసర ప్రతిస్పందనదారులను అనుమతించడానికి కాల్ బ్లాక్ చేయడం నిలిపివేయబడింది."</string>
<string name="developer_title" msgid="9146088855661672353">"టెలికామ్ డెవలపర్ మెనూ"</string>
- <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"అత్యవసర కాల్లో వున్నప్పుడు కాల్లను స్వీకరించడానికి వీలుపడదు."</string>
+ <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"అత్యవసర కాల్లో వున్నప్పుడు కాల్స్ను స్వీకరించడానికి వీలుపడదు."</string>
+ <string name="cancel" msgid="6733466216239934756">"రద్దు చేయండి"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 615abb9..4f1c825 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"การจัดการการโทร"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"โทรศัพท์"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"โทรศัพท์"</string>
<string name="unknown" msgid="6993977514360123431">"ไม่ทราบ"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"สายที่ไม่ได้รับ"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"บล็อกสายจากโทรศัพท์สาธารณะ"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ไม่รู้จัก"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"บล็อกสายจากผู้โทรที่ไม่สามารถระบุได้"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ไม่ได้บันทึก"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"บล็อกสายที่ไม่ได้บันทึกหมายเลขไว้"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"การบล็อกสาย"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ปิดใช้การบล็อกสาย"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"โทรหมายเลขฉุกเฉินแล้ว"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ปิดใช้การบล็อกสายแล้วเพื่อให้ทีมฉุกเฉินติดต่อคุณ"</string>
<string name="developer_title" msgid="9146088855661672353">"เมนูนักพัฒนาโทรคมนาคม"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"การโทรนั้นจะทำขณะอยู่ในการโทรฉุกเฉินไม่ได้"</string>
+ <string name="cancel" msgid="6733466216239934756">"ยกเลิก"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 998abef..ece24c0 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Pamamahala sa Tawag"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Mga Tawag sa Telepono"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telepono"</string>
<string name="unknown" msgid="6993977514360123431">"Di-kilala"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Hindi nasagot na tawag"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bina-block ang mga tawag mula sa mga pay phone"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Hindi Alam"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bina-block ang mga tumatawag mula sa mga hindi kilalang tumatawag"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Pag-block ng Tawag"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Naka-disable ang Pag-block ng Tawag"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Ginawang emergency na tawag"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Na-disable ang Pag-block ng Tawag para payagan ang mga tumutugon sa emergency na kontakin ka."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu ng Telecom Developer"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Hindi puwedeng sumagot ng mga tawag habang nasa emergency na tawag."</string>
+ <string name="cancel" msgid="6733466216239934756">"Kanselahin"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 2e02f8c..cfd4164 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Çağrı Yönetimi"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefon Aramaları"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Bilinmiyor"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Cevapsız çağrı"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Ankesörlü telefonlardan gelen çağrılar engellenir"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Bilinmeyen numaralar"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Tanımlanamayan arayanlardan gelen aramaları engelle"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Çağrı Engelleme"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Çağrı Engelleme devre dışı bırakıldı"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Acil durum çağrısı yapıldı"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Acil durum müdahale ekibinin sizinle iletişime geçmesine olanak tanımak için Çağrı Engelleme devre dışı bırakıldı."</string>
<string name="developer_title" msgid="9146088855661672353">"Telekomünikasyon Geliştirici Menüsü"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Acil durum araması sırasında arama alınamaz."</string>
+ <string name="cancel" msgid="6733466216239934756">"İptal"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index d86b3eb..9e70561 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Керування дзвінками"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Телефонні виклики"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Невідомий"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Пропущений виклик"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокування викликів із таксофонів"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Невідомі"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокувати виклики від невизначених абонентів"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокування викликів"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокування викликів вимкнено"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Здійснено екстрений виклик"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокування викликів вимкнено, щоб ви могли отримувати екстрені сповіщення."</string>
<string name="developer_title" msgid="9146088855661672353">"Меню розробника Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Під час екстрених викликів не можна приймати інші."</string>
+ <string name="cancel" msgid="6733466216239934756">"Скасувати"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 20cca1b..b9708bb 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"کال مینجمنٹ"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"فون کالز"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"فون"</string>
<string name="unknown" msgid="6993977514360123431">"نامعلوم"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"چھوٹی ہوئی کال"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"پے فونز سے آنے والی کالز کو مسدود کریں"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"نامعلوم"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"غیر شناخت کردہ کالرز سے آنے والی کالز کو مسدود کریں"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"کال مسدود کرنا"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"کال مسدود کرنا غیر فعال ہو گیا ہے"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ہنگامی کال کی گئی"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ہنگامی حالت میں جواب دہندگان کو آپ سے رابطہ کرنے کی اجازت دینے کیلئے کال مسدود کرنا غیر فعال ہو گیا ہے۔"</string>
<string name="developer_title" msgid="9146088855661672353">"ٹیلی کام ڈویلپر مینو"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ہنگامی کال کے دوران کالز نہیں لی جائیں گی۔"</string>
+ <string name="cancel" msgid="6733466216239934756">"منسوخ کریں"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 3271245..5597a21 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Chaqiruvlar boshqaruvi"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Telefon chaqiruvlari"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Telefon"</string>
<string name="unknown" msgid="6993977514360123431">"Noma’lum"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Javobsiz chaqiruv"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Taksofondan keluvchi chaqiruvlarni bloklash"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Notanish raqamlar"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Aniqlanmagan raqamlardan keluvchi chaqiruvlarni bloklash"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Chaqiruvlarni bloklash"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Chaqiruvlarni bloklash funksiyasi yoqilmagan"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Favqulodda chaqiruv qilindi"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Sizga favqulodda chiqiruv qilish imkoni bo‘lishi uchun chaqiruvlarni bloklash funksiyasi o‘chirib qo‘yilgan."</string>
<string name="developer_title" msgid="9146088855661672353">"Telecom dasturchisi menyusi"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Favqulodda chaqiruv vaqtida boshqa chaqiruvlarni qabul qilish imkonsiz."</string>
+ <string name="cancel" msgid="6733466216239934756">"Bekor qilish"</string>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index c6fe44a..10a6b9d 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Quản lý cuộc gọi"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Cuộc gọi điện thoại"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Điện thoại"</string>
<string name="unknown" msgid="6993977514360123431">"Không xác định"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Cuộc gọi nhỡ"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Chặn các cuộc gọi từ điện thoại công cộng"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Không xác định"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Chặn cuộc gọi từ người gọi không xác định"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Chặn cuộc gọi"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Đã tắt tính năng Chặn cuộc gọi"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Đã thực hiện cuộc gọi khẩn cấp"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Đã tắt tính năng Chặn cuộc gọi để cho phép người trả lời khẩn cấp liên hệ với bạn."</string>
<string name="developer_title" msgid="9146088855661672353">"Menu nhà phát triển dịch vụ viễn thông"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Bạn không thể gọi điện trong khi thực hiện cuộc gọi khẩn cấp."</string>
+ <string name="cancel" msgid="6733466216239934756">"Hủy"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index bbda818..33870e8 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"通话管理"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"电话"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"电话"</string>
<string name="unknown" msgid="6993977514360123431">"未知"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"未接电话"</string>
@@ -26,7 +26,7 @@
<string name="notification_missedCallTicker" msgid="6731461957487087769">"来自<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>的未接电话"</string>
<string name="notification_missedCall_call_back" msgid="7900333283939789732">"回拨"</string>
<string name="notification_missedCall_message" msgid="4054698824390076431">"发短信"</string>
- <string name="notification_disconnectedCall_title" msgid="1790131923692416928">"已中断的通话"</string>
+ <string name="notification_disconnectedCall_title" msgid="1790131923692416928">"通话中断"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"由于要进行紧急呼叫,与 <xliff:g id="CALLER">%s</xliff:g> 的通话已中断。"</string>
<string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"由于要进行紧急呼叫,您的通话已中断。"</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"后台通话"</string>
@@ -98,8 +98,8 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"未接电话"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"来电屏蔽"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"后台通话"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"已中断的通话"</string>
- <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"崩溃的手机应用"</string>
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"通话中断"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"手机应用崩溃"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"拨打此电话将导致<xliff:g id="OTHER_APP">%1$s</xliff:g>通话结束。"</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"选择拨打此电话的方式"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"使用<xliff:g id="OTHER_APP">%1$s</xliff:g>转移呼叫"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"屏蔽公用电话来电"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"未知"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"屏蔽不明身份人员的来电"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"来电屏蔽"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"来电屏蔽功能已停用"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"已拨打紧急呼救电话"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"系统已停用来电屏蔽功能,以便急救人员与您联系。"</string>
<string name="developer_title" msgid="9146088855661672353">"电信开发者菜单"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"紧急呼叫时无法接听来电。"</string>
+ <string name="cancel" msgid="6733466216239934756">"取消"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 0f26c9d..517b4f8 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"通話管理"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"電話通話"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"電話"</string>
<string name="unknown" msgid="6993977514360123431">"未知"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"未接來電"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"封鎖公共電話來電"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"封鎖不明來電者的來電"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"來電封鎖"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"已停用來電封鎖功能"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"已撥緊急電話"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"已停用來電封鎖功能,以便救援人員與您聯絡。"</string>
<string name="developer_title" msgid="9146088855661672353">"電信開發商選單"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"使用緊急電話期間無法接聽電話。"</string>
+ <string name="cancel" msgid="6733466216239934756">"取消"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 7c98928..5492645 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"通話管理"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"電話"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"電話"</string>
<string name="unknown" msgid="6993977514360123431">"不明"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"未接來電"</string>
@@ -114,10 +114,15 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"封鎖公共電話來電"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"封鎖不明來電者的來電"</string>
+ <!-- no translation found for phone_settings_unavailable_txt (825918186053980858) -->
+ <skip />
+ <!-- no translation found for phone_settings_unavailable_summary_txt (8221686031038282633) -->
+ <skip />
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"來電封鎖"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"已停用來電封鎖"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"已撥打緊急電話"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"系統已停用來電封鎖功能,以便緊急應變人員與你聯絡。"</string>
<string name="developer_title" msgid="9146088855661672353">"電信開發人員選單"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"如果裝置已撥打緊急電話,就無法進行其他通話。"</string>
+ <string name="cancel" msgid="6733466216239934756">"取消"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 30c147d..a98e4f0 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -16,7 +16,7 @@
<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="3077225713817780583">"Ukuphathwa kwekholi"</string>
+ <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"Amakholi Wefoni"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Ifoni"</string>
<string name="unknown" msgid="6993977514360123431">"Akwaziwa"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Ikholi ekulahlekele"</string>
@@ -114,10 +114,13 @@
<string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Vimbela amakholi kusukela kumafoni akhokhelwayo"</string>
<string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Akwaziwa"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Vimbela amakholi kusukela kwabashayayo abangaziwa"</string>
+ <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Akutholakali"</string>
+ <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Vimba amakholi lapho inombolo ingatholakali"</string>
<string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Ukuvimbela ikholi"</string>
<string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Ukuvimbela ikholi kukhutshaziwe"</string>
<string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Ikholi ephuthumayo yenziwe"</string>
<string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Ukuvimbela ikholi kukhutshaziwe ukuze kuvunyelwe abaphenduli besimo esiphuthumayo ukuthi baxhumane nawe."</string>
<string name="developer_title" msgid="9146088855661672353">"Imenyu yonjiniyela we-Telecom"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Amakholi awakwazi ukuthathwa ngesikhathi ukukholi yesimo esiphuthumayo."</string>
+ <string name="cancel" msgid="6733466216239934756">"Khansela"</string>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 9cbbf46..b0e50b0 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -69,4 +69,8 @@
<!-- When true, the options in the call blocking settings to block restricted and unknown
callers are combined into a single toggle. -->
<bool name="combine_options_to_block_restricted_and_unknown_callers">true</bool>
+
+ <!-- When set, Telecom will attempt to bind to the {@link CallDiagnosticService} implementation
+ defined by the app with this package name. -->
+ <string name="call_diagnostic_service_package_name"></string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index df08d7c..6b8c0b2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -17,8 +17,10 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Official label of the Telecomm/Phone app, as seen in "Manage Applications"
and other settings UIs. This is the "app name" used in notification, recents,
- and app info screens. -->
- <string name="telecommAppLabel" product="default">Call Management</string>
+ and app info screens. The term "phone calls" is used since an end user would more commonly
+ think of the stuff the Telecom framework deals with as having to do with "phone calls",
+ not "call management" (even though that is technically more accurate). -->
+ <string name="telecommAppLabel" product="default">Phone Calls</string>
<!-- Title used for the activity for placing a call. This name appears
in activity disambig dialogs -->
@@ -354,6 +356,10 @@
<string name="phone_settings_unknown_txt">Unknown</string>
<!-- Explanatory text under the call type "phone_settings_unknown_txt". This occurs when no caller ID information unavailable (e.g., international calls, IP phones that operators cannot identify the caller) -->
<string name="phone_settings_unknown_summary_txt">Block calls from unidentified callers</string>
+ <!-- Call type to be blocked. See the explanatory text "phone_settings_unavailable_summary_txt". -->
+ <string name="phone_settings_unavailable_txt">Unavailable</string>
+ <!-- Explanatory text under the call type "phone_settings_unavailable_txt". -->
+ <string name="phone_settings_unavailable_summary_txt">Block calls where the number is unavailable</string>
<!-- Notification. Make this translation consistent with "phone_settings_call_blocking_txt". -->
<string name="phone_strings_call_blocking_turned_off_notification_title_txt">Call Blocking</string>
<!-- Notification that appears when the feature Call Blocking has been disabled. -->
@@ -373,4 +379,6 @@
blocking functionality (for test purposes).
DO NOT TRANSLATE -->
<string name="developer_enhanced_call_blocking" translatable="false">Enhanced Call Blocking</string>
+ <!-- Button label for generic cancel action [CHAR LIMIT=20] -->
+ <string name="cancel">Cancel</string>
</resources>
diff --git a/res/xml/activity_blocked_numbers.xml b/res/xml/activity_blocked_numbers.xml
index df1a759..f884ec9 100644
--- a/res/xml/activity_blocked_numbers.xml
+++ b/res/xml/activity_blocked_numbers.xml
@@ -75,7 +75,7 @@
<TextView
android:id="@+id/add_blocked"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:text="@string/block_number"
android:layout_marginBottom="@dimen/blocked_numbers_button_bottom_margin"
android:paddingTop="@dimen/blocked_numbers_button_large_padding"
diff --git a/res/xml/enhanced_call_blocking_settings.xml b/res/xml/enhanced_call_blocking_settings.xml
index 73ed2af..50c9b36 100644
--- a/res/xml/enhanced_call_blocking_settings.xml
+++ b/res/xml/enhanced_call_blocking_settings.xml
@@ -40,5 +40,11 @@
android:summary="@string/phone_settings_unknown_summary_txt"
android:persistent="false"
android:defaultValue="false"/>
+ <SwitchPreference
+ android:key="block_unavailable_calls_setting"
+ android:title="@string/phone_settings_unavailable_txt"
+ android:summary="@string/phone_settings_unavailable_summary_txt"
+ android:persistent="false"
+ android:defaultValue="false"/>
<!--Add divider to separate this enhanced call blocking settings from other settings-->
</PreferenceScreen>
\ No newline at end of file
diff --git a/scripts/aosp_tag_preupload.py b/scripts/aosp_tag_preupload.py
index 77a9714..bfcdbd6 100755
--- a/scripts/aosp_tag_preupload.py
+++ b/scripts/aosp_tag_preupload.py
@@ -41,15 +41,18 @@
commit_msg = subprocess.check_output(["git", "show",
sys.argv[1], "--no-notes"])
for commit_line in commit_msg.splitlines():
- if re.search(AOSP_COMMIT_TAG_REGEX, commit_line, re.IGNORECASE):
- _check_aosp_message(commit_line)
+ # Some lines in the commit message will be given to us as bytes
+ commit_line_str = str(commit_line)
+ if re.search(AOSP_COMMIT_TAG_REGEX, str(commit_line_str), re.IGNORECASE):
+ _check_aosp_message(commit_line_str)
print(ERROR_MESSAGE)
- sys.exit(0)
+ # Print the warning, but do not fail the presubmit check.
+ sys.exit(77)
def _is_in_aosp():
branch_info = subprocess.check_output(["git", "branch", "-vv"])
- return re.search(AOSP_BRANCH_REGEX, branch_info) is not None
+ return re.search(AOSP_BRANCH_REGEX, str(branch_info)) is not None
def _check_aosp_message(aosp_line):
if re.search(AOSP_COMMIT_LINK_REGEX, aosp_line):
@@ -59,7 +62,8 @@
sys.exit(0)
print(ERROR_MESSAGE)
- sys.exit(0)
+ # Print the warning, but do not fail the presubmit check.
+ sys.exit(77)
if __name__ == '__main__':
main()
diff --git a/src/com/android/server/telecom/BluetoothAdapterProxy.java b/src/com/android/server/telecom/BluetoothAdapterProxy.java
deleted file mode 100644
index ee9cde3..0000000
--- a/src/com/android/server/telecom/BluetoothAdapterProxy.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 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.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
-import android.content.Context;
-
-/**
- * Proxy class used so that BluetoothAdapter can be mocked for testing.
- */
-public class BluetoothAdapterProxy {
- private BluetoothAdapter mBluetoothAdapter;
-
- public BluetoothAdapterProxy() {
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- }
-
- public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
- int profile) {
- if (mBluetoothAdapter == null) {
- return false;
- }
- return mBluetoothAdapter.getProfileProxy(context, listener, profile);
- }
-
- public boolean setActiveDevice(BluetoothDevice device, int profiles) {
- if (mBluetoothAdapter == null) {
- return false;
- }
- if (device != null) {
- return mBluetoothAdapter.setActiveDevice(device, profiles);
- } else {
- return mBluetoothAdapter.removeActiveDevice(profiles);
- }
- }
-}
diff --git a/src/com/android/server/telecom/BluetoothHeadsetProxy.java b/src/com/android/server/telecom/BluetoothHeadsetProxy.java
deleted file mode 100644
index e4eed87..0000000
--- a/src/com/android/server/telecom/BluetoothHeadsetProxy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2015 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.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-
-import java.util.List;
-
-/**
- * A proxy class that facilitates testing of the BluetoothPhoneServiceImpl class.
- *
- * This is necessary due to the "final" attribute of the BluetoothHeadset class. In order to
- * test the correct functioning of the BluetoothPhoneServiceImpl class, the final class must be put
- * into a container that can be mocked correctly.
- */
-public class BluetoothHeadsetProxy {
-
- private BluetoothHeadset mBluetoothHeadset;
-
- public BluetoothHeadsetProxy(BluetoothHeadset headset) {
- mBluetoothHeadset = headset;
- }
-
- public List<BluetoothDevice> getConnectedDevices() {
- return mBluetoothHeadset.getConnectedDevices();
- }
-
- public int getConnectionState(BluetoothDevice device) {
- return mBluetoothHeadset.getConnectionState(device);
- }
-
- public int getAudioState(BluetoothDevice device) {
- return mBluetoothHeadset.getAudioState(device);
- }
-
- public boolean connectAudio() {
- return mBluetoothHeadset.connectAudio();
- }
-
- public boolean setActiveDevice(BluetoothDevice device) {
- return mBluetoothHeadset.setActiveDevice(device);
- }
-
- public BluetoothDevice getActiveDevice() {
- return mBluetoothHeadset.getActiveDevice();
- }
-
- public boolean isAudioOn() {
- return mBluetoothHeadset.isAudioOn();
- }
-
- public boolean disconnectAudio() {
- return mBluetoothHeadset.disconnectAudio();
- }
-
- public boolean isInbandRingingEnabled() {
- return mBluetoothHeadset.isInbandRingingEnabled();
- }
-}
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index c5f3bde..746ab57 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -37,14 +37,16 @@
import android.os.UserHandle;
import android.provider.CallLog;
import android.provider.ContactsContract.Contacts;
+import android.telecom.BluetoothCallQualityReport;
import android.telecom.CallAudioState;
+import android.telecom.CallDiagnosticService;
+import android.telecom.CallDiagnostics;
import android.telecom.CallerInfo;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.ConnectionService;
import android.telecom.DisconnectCause;
import android.telecom.GatewayInfo;
-import android.telecom.InCallService;
import android.telecom.Log;
import android.telecom.Logging.EventManager;
import android.telecom.ParcelableConference;
@@ -55,11 +57,12 @@
import android.telecom.StatusHints;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
+import android.telephony.CallQuality;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsReasonInfo;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
@@ -79,7 +82,10 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
/**
* Encapsulates all aspects of a given phone call throughout its lifecycle, starting
@@ -156,6 +162,10 @@
Bundle extras, boolean isLegacy);
void onHandoverFailed(Call call, int error);
void onHandoverComplete(Call call);
+ void onBluetoothCallQualityReport(Call call, BluetoothCallQualityReport report);
+ void onReceivedDeviceToDeviceMessage(Call call, int messageType, int messageValue);
+ void onReceivedCallQualityReport(Call call, CallQuality callQuality);
+ void onCallerNumberVerificationStatusChanged(Call call, int callerNumberVerificationStatus);
}
public abstract static class ListenerBase implements Listener {
@@ -244,6 +254,15 @@
public void onHandoverFailed(Call call, int error) {}
@Override
public void onHandoverComplete(Call call) {}
+ @Override
+ public void onBluetoothCallQualityReport(Call call, BluetoothCallQualityReport report) {}
+ @Override
+ public void onReceivedDeviceToDeviceMessage(Call call, int messageType, int messageValue) {}
+ @Override
+ public void onReceivedCallQualityReport(Call call, CallQuality callQuality) {}
+ @Override
+ public void onCallerNumberVerificationStatusChanged(Call call,
+ int callerNumberVerificationStatus) {}
}
private final CallerInfoLookupHelper.OnQueryCompleteListener mCallerInfoQueryListener =
@@ -647,6 +666,29 @@
private String mCallScreeningComponentName;
/**
+ * When {@code true} indicates this call originated from a SIM-based {@link PhoneAccount}.
+ * A sim-based {@link PhoneAccount} is one with {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION}
+ * set.
+ */
+ private boolean mIsSimCall;
+
+ /**
+ * Set to {@code true} if we received a valid response ({@code null} or otherwise) from
+ * the {@link CallDiagnostics#onCallDisconnected(ImsReasonInfo)} or
+ * {@link CallDiagnostics#onCallDisconnected(int, int)} calls. This is used to detect a timeout
+ * when awaiting a response from the call diagnostic service.
+ */
+ private boolean mReceivedCallDiagnosticPostCallResponse = false;
+
+ /**
+ * {@link CompletableFuture} used to delay posting disconnection and removal to a call until
+ * after a {@link CallDiagnosticService} is able to handle the disconnection and provide a
+ * disconnect message via {@link CallDiagnostics#onCallDisconnected(ImsReasonInfo)} or
+ * {@link CallDiagnostics#onCallDisconnected(int, int)}.
+ */
+ private CompletableFuture<Boolean> mDisconnectFuture;
+
+ /**
* Persists the specified parameters and initializes the new instance.
* @param context The context.
* @param repository The connection service repository.
@@ -789,10 +831,10 @@
}
public void initAnalytics() {
- initAnalytics(null);
+ initAnalytics(null, null);
}
- public void initAnalytics(String callingPackage) {
+ public void initAnalytics(String callingPackage, String extraCreationLogs) {
int analyticsDirection;
switch (mCallDirection) {
case CALL_DIRECTION_OUTGOING:
@@ -808,7 +850,7 @@
}
mAnalytics = Analytics.initiateCallAnalytics(mId, analyticsDirection);
mAnalytics.setCallIsEmergency(mIsEmergencyCall);
- Log.addEvent(this, LogUtils.Events.CREATED, callingPackage);
+ Log.addEvent(this, LogUtils.Events.CREATED, callingPackage + ";" + extraCreationLogs);
}
public Analytics.CallInfo getAnalytics() {
@@ -956,6 +998,9 @@
case TelecomManager.PRESENTATION_UNKNOWN:
s.append("Unknown");
break;
+ case TelecomManager.PRESENTATION_UNAVAILABLE:
+ s.append("Unavailable");
+ break;
default:
s.append("<undefined>");
}
@@ -1078,6 +1123,31 @@
}
/**
+ * Handles an incoming overridden disconnect message for this call.
+ *
+ * We only care if the disconnect is handled via a future.
+ * @param message the overridden disconnect message.
+ */
+ public void handleOverrideDisconnectMessage(@Nullable CharSequence message) {
+ Log.i(this, "handleOverrideDisconnectMessage; callid=%s, msg=%s", getId(), message);
+
+ if (isDisconnectHandledViaFuture()) {
+ mReceivedCallDiagnosticPostCallResponse = true;
+ if (message != null) {
+ Log.addEvent(this, LogUtils.Events.OVERRIDE_DISCONNECT_MESSAGE, message);
+ // Replace the existing disconnect cause in this call
+ setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.ERROR, message,
+ message, null));
+ }
+
+ mDisconnectFuture.complete(true);
+ } else {
+ Log.w(this, "handleOverrideDisconnectMessage; callid=%s - got override when unbound",
+ getId());
+ }
+ }
+
+ /**
* Sets the call state. Although there exists the notion of appropriate state transitions
* (see {@link CallState}), in practice those expectations break down when cellular systems
* misbehave and they do this very often. The result is that we do not enforce state transitions
@@ -1261,6 +1331,8 @@
public void setCallerNumberVerificationStatus(
@Connection.VerificationStatus int callerNumberVerificationStatus) {
mCallerNumberVerificationStatus = callerNumberVerificationStatus;
+ mListeners.forEach(l -> l.onCallerNumberVerificationStatusChanged(this,
+ callerNumberVerificationStatus));
}
public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
@@ -1297,6 +1369,9 @@
} catch (IllegalStateException ise) {
Log.e(this, ise, "setHandle: can't determine if number is emergency");
mIsEmergencyCall = false;
+ } catch (RuntimeException r) {
+ Log.e(this, r, "setHandle: can't determine if number is emergency");
+ mIsEmergencyCall = false;
}
mAnalytics.setCallIsEmergency(mIsEmergencyCall);
}
@@ -1321,6 +1396,8 @@
number.equals(eNumber.getNumber()));
} catch (IllegalStateException ise) {
return false;
+ } catch (RuntimeException r) {
+ return false;
}
}
@@ -1703,6 +1780,7 @@
PhoneAccountRegistrar phoneAccountRegistrar = mCallsManager.getPhoneAccountRegistrar();
boolean isWorkCall = false;
boolean isCallRecordingToneSupported = false;
+ boolean isSimCall = false;
PhoneAccount phoneAccount =
phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle);
if (phoneAccount != null) {
@@ -1720,9 +1798,11 @@
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && phoneAccount.getExtras() != null
&& phoneAccount.getExtras().getBoolean(
PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, false));
+ isSimCall = phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
}
mIsWorkCall = isWorkCall;
mUseCallRecordingTone = isCallRecordingToneSupported;
+ mIsSimCall = isSimCall;
}
/**
@@ -1903,6 +1983,13 @@
if (didRttChange) {
if ((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
Connection.PROPERTY_IS_RTT) {
+ // If we already had RTT streams up, that means that either the call started
+ // with RTT or the user previously requested to start RTT. Either way, don't
+ // play the alert tone.
+ if (!areRttStreamsInitialized()) {
+ mCallsManager.playRttUpgradeToneForCall(this);
+ }
+
createRttStreams();
// Call startRtt to pass the RTT pipes down to the connection service.
// They already turned on the RTT property so no request should be sent.
@@ -1944,6 +2031,16 @@
}
}
+ boolean wasDowngradedConference =
+ (previousProperties & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
+ boolean isDowngradedConference =
+ (connectionProperties & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
+ if (wasDowngradedConference && !isDowngradedConference) {
+ Log.i(this, "DOWNGRADED_CONFERENCE property removed; setting"
+ + " conference state to false");
+ setConferenceState(false);
+ }
+
mAnalytics.addCallProperties(mConnectionProperties);
int xorProps = previousProperties ^ mConnectionProperties;
@@ -2626,7 +2723,8 @@
return mState == CallState.ACTIVE;
}
- Bundle getExtras() {
+ @VisibleForTesting
+ public Bundle getExtras() {
return mExtras;
}
@@ -2666,6 +2764,16 @@
setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
}
+ if (extras.containsKey(Connection.EXTRA_CALLER_NUMBER_VERIFICATION_STATUS)
+ && source == SOURCE_CONNECTION_SERVICE) {
+ int callerNumberVerificationStatus =
+ extras.getInt(Connection.EXTRA_CALLER_NUMBER_VERIFICATION_STATUS);
+ if (mCallerNumberVerificationStatus != callerNumberVerificationStatus) {
+ Log.addEvent(this, LogUtils.Events.VERSTAT_CHANGED, callerNumberVerificationStatus);
+ setCallerNumberVerificationStatus(callerNumberVerificationStatus);
+ }
+ }
+
// The remote connection service API can track the phone account which was originally
// requested to create a connection via the remote connection service API; we store that so
// we have some visibility into how a call was actually placed.
@@ -2952,6 +3060,14 @@
}
requestHandover(phoneAccountHandle, videoState, handoverExtrasBundle, true);
} else {
+ // Relay bluetooth call quality reports to the call diagnostic service.
+ if (BluetoothCallQualityReport.EVENT_BLUETOOTH_CALL_QUALITY_REPORT.equals(event)
+ && extras.containsKey(
+ BluetoothCallQualityReport.EXTRA_BLUETOOTH_CALL_QUALITY_REPORT)) {
+ notifyBluetoothCallQualityReport(extras.getParcelable(
+ BluetoothCallQualityReport.EXTRA_BLUETOOTH_CALL_QUALITY_REPORT
+ ));
+ }
Log.addEvent(this, LogUtils.Events.CALL_EVENT, event);
mConnectionService.sendCallEvent(this, event, extras);
}
@@ -2962,6 +3078,17 @@
}
/**
+ * Notifies listeners when a bluetooth quality report is received.
+ * @param report The bluetooth quality report.
+ */
+ void notifyBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport report) {
+ Log.addEvent(this, LogUtils.Events.BT_QUALITY_REPORT, "choppy=" + report.isChoppyVoice());
+ for (Listener l : mListeners) {
+ l.onBluetoothCallQualityReport(this, report);
+ }
+ }
+
+ /**
* Initiates a handover of this Call to the {@link ConnectionService} identified
* by destAcct.
* @param destAcct ConnectionService to which the call should be handed over.
@@ -3037,6 +3164,13 @@
void setConferenceableCalls(List<Call> conferenceableCalls) {
mConferenceableCalls.clear();
mConferenceableCalls.addAll(conferenceableCalls);
+ String confCallIds = "";
+ if (!conferenceableCalls.isEmpty()) {
+ confCallIds = conferenceableCalls.stream()
+ .map(c -> c.getId())
+ .collect(Collectors.joining(","));
+ }
+ Log.addEvent(this, LogUtils.Events.CONF_CALLS_CHANGED, confCallIds);
for (Listener l : mListeners) {
l.onConferenceableCallsChanged(this);
@@ -3668,7 +3802,10 @@
* @param extras The extras.
*/
public void onConnectionEvent(String event, Bundle extras) {
- Log.addEvent(this, LogUtils.Events.CONNECTION_EVENT, event);
+ // Don't log call quality reports; they're quite frequent and will clog the log.
+ if (!Connection.EVENT_CALL_QUALITY_REPORT.equals(event)) {
+ Log.addEvent(this, LogUtils.Events.CONNECTION_EVENT, event);
+ }
if (Connection.EVENT_ON_HOLD_TONE_START.equals(event)) {
mIsRemotelyHeld = true;
Log.addEvent(this, LogUtils.Events.REMOTELY_HELD);
@@ -3691,6 +3828,23 @@
for (Listener l : mListeners) {
l.onCallSwitchFailed(this);
}
+ } else if (Connection.EVENT_DEVICE_TO_DEVICE_MESSAGE.equals(event)
+ && extras != null && extras.containsKey(
+ Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE)
+ && extras.containsKey(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE)) {
+ // Relay an incoming D2D message to interested listeners; most notably the
+ // CallDiagnosticService.
+ int messageType = extras.getInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE);
+ int messageValue = extras.getInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE);
+ for (Listener l : mListeners) {
+ l.onReceivedDeviceToDeviceMessage(this, messageType, messageValue);
+ }
+ } else if (Connection.EVENT_CALL_QUALITY_REPORT.equals(event)
+ && extras != null && extras.containsKey(Connection.EXTRA_CALL_QUALITY_REPORT)) {
+ CallQuality callQuality = extras.getParcelable(Connection.EXTRA_CALL_QUALITY_REPORT);
+ for (Listener l : mListeners) {
+ l.onReceivedCallQualityReport(this, callQuality);
+ }
} else {
for (Listener l : mListeners) {
l.onConnectionEvent(this, event, extras);
@@ -3856,6 +4010,10 @@
mIsUsingCallFiltering = isUsingCallFiltering;
}
+ public boolean isUsingCallFiltering() {
+ return mIsUsingCallFiltering;
+ }
+
/**
* Returns whether or not Volte call was used.
*
@@ -3892,6 +4050,44 @@
}
/**
+ * Sends a device to device message to the other part of the call.
+ * @param message the message type to send.
+ * @param value the value for the message.
+ */
+ public void sendDeviceToDeviceMessage(@CallDiagnostics.MessageType int message, int value) {
+ Log.i(this, "sendDeviceToDeviceMessage; callId=%s, msg=%d/%d", getId(), message, value);
+ Bundle extras = new Bundle();
+ extras.putInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE, message);
+ extras.putInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE, value);
+ // Send to the connection service.
+ sendCallEvent(Connection.EVENT_DEVICE_TO_DEVICE_MESSAGE, extras);
+ }
+
+ /**
+ * Signals to the Dialer app to start displaying a diagnostic message.
+ * @param messageId a unique ID for the message to display.
+ * @param message the message to display.
+ */
+ public void displayDiagnosticMessage(int messageId, @NonNull CharSequence message) {
+ Bundle extras = new Bundle();
+ extras.putInt(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE_ID, messageId);
+ extras.putCharSequence(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE, message);
+ // Send to the dialer.
+ onConnectionEvent(android.telecom.Call.EVENT_DISPLAY_DIAGNOSTIC_MESSAGE, extras);
+ }
+
+ /**
+ * Signals to the Dialer app to stop displaying a diagnostic message.
+ * @param messageId a unique ID for the message to clear.
+ */
+ public void clearDiagnosticMessage(int messageId) {
+ Bundle extras = new Bundle();
+ extras.putInt(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE_ID, messageId);
+ // Send to the dialer.
+ onConnectionEvent(android.telecom.Call.EVENT_CLEAR_DIAGNOSTIC_MESSAGE, extras);
+ }
+
+ /**
* Remaps the call direction as indicated by an {@link android.telecom.Call.Details} direction
* constant to the constants (e.g. {@link #CALL_DIRECTION_INCOMING}) used in this call class.
* @param direction The android.telecom.Call direction.
@@ -3977,4 +4173,78 @@
}
}
}
+
+ /**
+ * @return {@code true} when this call originated from a SIM-based {@link PhoneAccount}.
+ * A sim-based {@link PhoneAccount} is one with {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION}
+ * set.
+ */
+ public boolean isSimCall() {
+ return mIsSimCall;
+ }
+
+ /**
+ * Sets whether this is a sim call or not.
+ * @param isSimCall {@code true} if this is a SIM call, {@code false} otherwise.
+ */
+ public void setIsSimCall(boolean isSimCall) {
+ mIsSimCall = isSimCall;
+ }
+
+ /**
+ * Initializes a disconnect future which is used to chain up pending operations which take
+ * place when the {@link CallDiagnosticService} returns the result of the
+ * {@link CallDiagnostics#onCallDisconnected(int, int)} or
+ * {@link CallDiagnostics#onCallDisconnected(ImsReasonInfo)} invocation via
+ * {@link CallDiagnosticServiceAdapter}. If no {@link CallDiagnosticService} is in use, we
+ * would not try to make a disconnect future.
+ * @param timeoutMillis Timeout we use for waiting for the response.
+ * @return the {@link CompletableFuture}.
+ */
+ public CompletableFuture<Boolean> initializeDisconnectFuture(long timeoutMillis) {
+ if (mDisconnectFuture == null) {
+ mDisconnectFuture = new CompletableFuture<Boolean>()
+ .completeOnTimeout(false, timeoutMillis, TimeUnit.MILLISECONDS);
+ // After all the chained stuff we will report where the CDS timed out.
+ mDisconnectFuture.thenRunAsync(() -> {
+ if (!mReceivedCallDiagnosticPostCallResponse) {
+ Log.addEvent(this, LogUtils.Events.CALL_DIAGNOSTIC_SERVICE_TIMEOUT);
+ }
+ // Clear the future as a final step.
+ mDisconnectFuture = null;
+ },
+ new LoggedHandlerExecutor(mHandler, "C.iDF", mLock))
+ .exceptionally((throwable) -> {
+ Log.e(this, throwable, "Error while executing disconnect future");
+ return null;
+ });
+ }
+ return mDisconnectFuture;
+ }
+
+ /**
+ * @return the disconnect future, if initialized. Used for chaining operations after creation.
+ */
+ public CompletableFuture<Boolean> getDisconnectFuture() {
+ return mDisconnectFuture;
+ }
+
+ /**
+ * @return {@code true} if disconnection and removal is handled via a future, or {@code false}
+ * if this is handled immediately.
+ */
+ public boolean isDisconnectHandledViaFuture() {
+ return mDisconnectFuture != null;
+ }
+
+ /**
+ * Perform any cleanup on this call as a result of a {@link TelecomServiceImpl}
+ * {@code cleanupStuckCalls} request.
+ */
+ public void cleanup() {
+ if (mDisconnectFuture != null) {
+ mDisconnectFuture.complete(false);
+ mDisconnectFuture = null;
+ }
+ }
}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index a6509b4..6a7261e 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -264,6 +264,14 @@
}
}
+ public void playRttUpgradeTone(Call call) {
+ if (call != mForegroundCall) {
+ // We only play tones for foreground calls.
+ return;
+ }
+ mPlayerFactory.createPlayer(InCallTonePlayer.TONE_RTT_REQUEST).startTone();
+ }
+
/**
* Play or stop a call hold tone for a call. Triggered via
* {@link Connection#sendConnectionEvent(String)} when the
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index bcfdedf..e5a6ecc 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -493,6 +493,8 @@
case SWITCH_FOCUS:
if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
transitionTo(mActiveEarpieceRoute);
+ } else {
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
default:
@@ -695,6 +697,8 @@
case SWITCH_FOCUS:
if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
transitionTo(mActiveHeadsetRoute);
+ } else {
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
default:
@@ -1051,6 +1055,8 @@
} else {
transitionTo(mRingingBluetoothRoute);
}
+ } else {
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
case BT_AUDIO_DISCONNECTED:
@@ -1274,6 +1280,8 @@
if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
setSpeakerphoneOn(true);
transitionTo(mActiveSpeakerRoute);
+ } else {
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
default:
@@ -1339,6 +1347,15 @@
} else {
sendInternalMessage(MUTE_EXTERNALLY_CHANGED);
}
+ } else if (AudioManager.STREAM_MUTE_CHANGED_ACTION.equals(intent.getAction())) {
+ int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+ boolean isStreamMuted = intent.getBooleanExtra(
+ AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
+
+ if (streamType == AudioManager.STREAM_RING && !isStreamMuted) {
+ Log.i(this, "Ring stream was un-muted.");
+ mCallAudioManager.onRingerModeChange();
+ }
} else {
Log.w(this, "Received non-mute-change intent");
}
@@ -1522,6 +1539,8 @@
mWasOnSpeaker = false;
mContext.registerReceiver(mMuteChangeReceiver,
new IntentFilter(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED));
+ mContext.registerReceiver(mMuteChangeReceiver,
+ new IntentFilter(AudioManager.STREAM_MUTE_CHANGED_ACTION));
mContext.registerReceiver(mSpeakerPhoneChangeReceiver,
new IntentFilter(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED));
diff --git a/src/com/android/server/telecom/CallDiagnosticServiceAdapter.java b/src/com/android/server/telecom/CallDiagnosticServiceAdapter.java
new file mode 100644
index 0000000..8623866
--- /dev/null
+++ b/src/com/android/server/telecom/CallDiagnosticServiceAdapter.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 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.annotation.NonNull;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.telecom.CallDiagnosticService;
+import android.telecom.CallDiagnostics;
+import android.telecom.Log;
+
+import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
+
+/**
+ * Adapter class used to provide a path for messages FROM a {@link CallDiagnosticService} back to
+ * the telecom stack.
+ */
+public class CallDiagnosticServiceAdapter extends ICallDiagnosticServiceAdapter.Stub {
+ public interface TelecomAdapter {
+ void displayDiagnosticMessage(String callId, int messageId, CharSequence message);
+ void clearDiagnosticMessage(String callId, int messageId);
+ void sendDeviceToDeviceMessage(String callId, @CallDiagnostics.MessageType int message,
+ int value);
+ void overrideDisconnectMessage(String callId, CharSequence message);
+ }
+
+ private final TelecomAdapter mTelecomAdapter;
+ private final String mOwnerPackageName;
+ private final String mOwnerPackageAbbreviation;
+ private final TelecomSystem.SyncRoot mLock;
+
+ CallDiagnosticServiceAdapter(@NonNull TelecomAdapter telecomAdapter,
+ @NonNull String ownerPackageName, @NonNull TelecomSystem.SyncRoot lock) {
+ mTelecomAdapter = telecomAdapter;
+ mOwnerPackageName = ownerPackageName;
+ mOwnerPackageAbbreviation = Log.getPackageAbbreviation(ownerPackageName);
+ mLock = lock;
+ }
+
+ @Override
+ public void displayDiagnosticMessage(String callId, int messageId, CharSequence message)
+ throws RemoteException {
+ try {
+ Log.startSession("CDSA.dDM", mOwnerPackageAbbreviation);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.i(this, "displayDiagnosticMessage; callId=%s, msg=%d/%s", callId, messageId,
+ message);
+ mTelecomAdapter.displayDiagnosticMessage(callId, messageId, message);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void clearDiagnosticMessage(String callId, int messageId) throws RemoteException {
+ try {
+ Log.startSession("CDSA.cDM", mOwnerPackageAbbreviation);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.i(this, "clearDiagnosticMessage; callId=%s, msg=%d", callId, messageId);
+ mTelecomAdapter.clearDiagnosticMessage(callId, messageId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void sendDeviceToDeviceMessage(String callId, @CallDiagnostics.MessageType int message,
+ int value)
+ throws RemoteException {
+ try {
+ Log.startSession("CDSA.sDTDM", mOwnerPackageAbbreviation);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.i(this, "sendDeviceToDeviceMessage; callId=%s, msg=%d/%d", callId, message,
+ value);
+ mTelecomAdapter.sendDeviceToDeviceMessage(callId, message, value);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void overrideDisconnectMessage(String callId, CharSequence message)
+ throws RemoteException {
+ try {
+ Log.startSession("CDSA.oDM", mOwnerPackageAbbreviation);
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Log.i(this, "overrideDisconnectMessage; callId=%s, msg=%s", callId, message);
+ mTelecomAdapter.overrideDisconnectMessage(callId, message);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+}
diff --git a/src/com/android/server/telecom/CallDiagnosticServiceController.java b/src/com/android/server/telecom/CallDiagnosticServiceController.java
new file mode 100644
index 0000000..7bd7288
--- /dev/null
+++ b/src/com/android/server/telecom/CallDiagnosticServiceController.java
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2021 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.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.telecom.BluetoothCallQualityReport;
+import android.telecom.CallAudioState;
+import android.telecom.CallDiagnosticService;
+import android.telecom.ConnectionService;
+import android.telecom.CallDiagnostics;
+import android.telecom.DisconnectCause;
+import android.telecom.InCallService;
+import android.telecom.Log;
+import android.telecom.ParcelableCall;
+import android.telephony.CallQuality;
+import android.telephony.ims.ImsReasonInfo;
+import android.text.TextUtils;
+
+import com.android.internal.telecom.ICallDiagnosticService;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.util.List;
+
+/**
+ * Responsible for maintaining binding to the {@link CallDiagnosticService} defined by the
+ * {@code call_diagnostic_service_package_name} key in the
+ * {@code packages/services/Telecomm/res/values/config.xml} file.
+ */
+public class CallDiagnosticServiceController extends CallsManagerListenerBase {
+ /**
+ * Context dependencies for the {@link CallDiagnosticServiceController}.
+ */
+ public interface ContextProxy {
+ List<ResolveInfo> queryIntentServicesAsUser(@NonNull Intent intent,
+ int resolveInfoFlags, @UserIdInt int userId);
+ boolean bindServiceAsUser(@NonNull @RequiresPermission Intent service,
+ @NonNull ServiceConnection conn, int flags, @NonNull UserHandle user);
+ void unbindService(@NonNull ServiceConnection conn);
+ UserHandle getCurrentUserHandle();
+ }
+
+ /**
+ * Listener for {@link Call} events; used to propagate these changes to the
+ * {@link CallDiagnosticService}.
+ */
+ private final Call.Listener mCallListener = new Call.ListenerBase() {
+ @Override
+ public void onConnectionCapabilitiesChanged(Call call) {
+ updateCall(call);
+ }
+
+ @Override
+ public void onConnectionPropertiesChanged(Call call, boolean didRttChange) {
+ updateCall(call);
+ }
+
+ /**
+ * Listens for changes to extras reported by a Telecom {@link Call}.
+ *
+ * Extras changes can originate from a {@link ConnectionService} or an {@link InCallService}
+ * so we will only trigger an update of the call information if the source of the extras
+ * change was a {@link ConnectionService}.
+ *
+ * @param call The call.
+ * @param source The source of the extras change ({@link Call#SOURCE_CONNECTION_SERVICE} or
+ * {@link Call#SOURCE_INCALL_SERVICE}).
+ * @param extras The extras.
+ */
+ @Override
+ public void onExtrasChanged(Call call, int source, Bundle extras) {
+ // Do not inform InCallServices of changes which originated there.
+ if (source == Call.SOURCE_INCALL_SERVICE) {
+ return;
+ }
+ updateCall(call);
+ }
+
+ /**
+ * Listens for changes to extras reported by a Telecom {@link Call}.
+ *
+ * Extras changes can originate from a {@link ConnectionService} or an {@link InCallService}
+ * so we will only trigger an update of the call information if the source of the extras
+ * change was a {@link ConnectionService}.
+ * @param call The call.
+ * @param source The source of the extras change ({@link Call#SOURCE_CONNECTION_SERVICE} or
+ * {@link Call#SOURCE_INCALL_SERVICE}).
+ * @param keys The extra key removed
+ */
+ @Override
+ public void onExtrasRemoved(Call call, int source, List<String> keys) {
+ // Do not inform InCallServices of changes which originated there.
+ if (source == Call.SOURCE_INCALL_SERVICE) {
+ return;
+ }
+ updateCall(call);
+ }
+
+ /**
+ * Handles changes to the video state of a call.
+ * @param call
+ * @param previousVideoState
+ * @param newVideoState
+ */
+ @Override
+ public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
+ updateCall(call);
+ }
+
+ /**
+ * Relays a bluetooth call quality report received from the Bluetooth stack to the
+ * CallDiagnosticService.
+ * @param call The call.
+ * @param report The received report.
+ */
+ @Override
+ public void onBluetoothCallQualityReport(Call call, BluetoothCallQualityReport report) {
+ handleBluetoothCallQualityReport(call, report);
+ }
+
+ /**
+ * Relays a device to device message received from Telephony to the CallDiagnosticService.
+ * @param call
+ * @param messageType
+ * @param messageValue
+ */
+ @Override
+ public void onReceivedDeviceToDeviceMessage(Call call, int messageType, int messageValue) {
+ handleReceivedDeviceToDeviceMessage(call, messageType, messageValue);
+ }
+
+ /**
+ * Handles an incoming {@link CallQuality} report from a {@link android.telecom.Connection}.
+ * @param call The call.
+ * @param callQualityReport The call quality report.
+ */
+ @Override
+ public void onReceivedCallQualityReport(Call call, CallQuality callQualityReport) {
+ handleCallQualityReport(call, callQualityReport);
+ }
+ };
+
+ /**
+ * {@link ServiceConnection} handling changes to binding of the {@link CallDiagnosticService}.
+ */
+ private class CallDiagnosticServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.startSession("CDSC.oSC", Log.getPackageAbbreviation(name));
+ try {
+ synchronized (mLock) {
+ mCallDiagnosticService = ICallDiagnosticService.Stub.asInterface(service);
+
+ handleConnectionComplete(mCallDiagnosticService);
+ }
+ Log.i(CallDiagnosticServiceController.this, "onServiceConnected: cmp=%s", name);
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.startSession("CDSC.oSD", Log.getPackageAbbreviation(name));
+ try {
+ synchronized (mLock) {
+ mCallDiagnosticService = null;
+ mConnection = null;
+ }
+ Log.i(CallDiagnosticServiceController.this, "onServiceDisconnected: cmp=%s", name);
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ Log.startSession("CDSC.oBD", Log.getPackageAbbreviation(name));
+ try {
+ synchronized (mLock) {
+ mCallDiagnosticService = null;
+ mConnection = null;
+ }
+ Log.w(CallDiagnosticServiceController.this, "onBindingDied: cmp=%s", name);
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ Log.startSession("CDSC.oNB", Log.getPackageAbbreviation(name));
+ try {
+ synchronized (mLock) {
+ maybeUnbindCallScreeningService();
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+ }
+
+ private final String mPackageName;
+ private final ContextProxy mContextProxy;
+ private InCallTonePlayer.Factory mPlayerFactory;
+ private String mTestPackageName;
+ private CallDiagnosticServiceConnection mConnection;
+ private CallDiagnosticServiceAdapter mAdapter;
+ private final TelecomSystem.SyncRoot mLock;
+ private ICallDiagnosticService mCallDiagnosticService;
+ private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getId);
+
+ public CallDiagnosticServiceController(@NonNull ContextProxy contextProxy,
+ @Nullable String packageName, @NonNull TelecomSystem.SyncRoot lock) {
+ mContextProxy = contextProxy;
+ mPackageName = packageName;
+ mLock = lock;
+ }
+
+ /**
+ * Sets the current {@link InCallTonePlayer.Factory} for this instance.
+ * @param factory the factory.
+ */
+ public void setInCallTonePlayerFactory(InCallTonePlayer.Factory factory) {
+ mPlayerFactory = factory;
+ }
+
+ /**
+ * Handles Telecom adding new calls. Will bind to the call diagnostic service if needed and
+ * send the calls, or send to an already bound service.
+ * @param call The call to add.
+ */
+ @Override
+ public void onCallAdded(@NonNull Call call) {
+ if (!call.isSimCall() || call.isExternalCall()) {
+ Log.i(this, "onCallAdded: skipping call %s as non-sim or external.", call.getId());
+ return;
+ }
+ if (mCallIdMapper.getCallId(call) == null) {
+ mCallIdMapper.addCall(call);
+ call.addListener(mCallListener);
+ }
+ if (isConnected()) {
+ sendCallToBoundService(call, mCallDiagnosticService);
+ } else {
+ maybeBindCallDiagnosticService();
+ }
+ }
+
+ /**
+ * Handles a newly disconnected call signalled from {@link CallsManager}.
+ * @param call The call
+ * @param disconnectCause The disconnect cause
+ * @return {@code true} if the {@link CallDiagnosticService} was sent the call, {@code false}
+ * if the call was not applicable to the CDS or if there was an issue sending it.
+ */
+ public boolean onCallDisconnected(@NonNull Call call,
+ @NonNull DisconnectCause disconnectCause) {
+ if (!call.isSimCall() || call.isExternalCall()) {
+ Log.i(this, "onCallDisconnected: skipping call %s as non-sim or external.",
+ call.getId());
+ return false;
+ }
+ String callId = mCallIdMapper.getCallId(call);
+ try {
+ if (isConnected()) {
+ mCallDiagnosticService.notifyCallDisconnected(callId, disconnectCause);
+ return true;
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "onCallDisconnected: callId=%s, exception=%s", call.getId(), e);
+ }
+ return false;
+ }
+
+ /**
+ * Handles Telecom removal of calls; will remove the call from the bound service and if the
+ * number of tracked calls falls to zero, unbind from the service.
+ * @param call The call to remove from the bound CDS.
+ */
+ @Override
+ public void onCallRemoved(@NonNull Call call) {
+ if (!call.isSimCall() || call.isExternalCall()) {
+ Log.i(this, "onCallRemoved: skipping call %s as non-sim or external.", call.getId());
+ return;
+ }
+ mCallIdMapper.removeCall(call);
+ call.removeListener(mCallListener);
+ removeCallFromBoundService(call, mCallDiagnosticService);
+
+ if (mCallIdMapper.getCalls().size() == 0) {
+ maybeUnbindCallScreeningService();
+ }
+ }
+
+ @Override
+ public void onCallStateChanged(Call call, int oldState, int newState) {
+ updateCall(call);
+ }
+
+ @Override
+ public void onCallAudioStateChanged(CallAudioState oldCallAudioState,
+ CallAudioState newCallAudioState) {
+ if (mCallDiagnosticService != null) {
+ try {
+ mCallDiagnosticService.updateCallAudioState(newCallAudioState);
+ } catch (RemoteException e) {
+ Log.w(this, "onCallAudioStateChanged: failed %s", e);
+ }
+ }
+ }
+
+ /**
+ * Sets the test call diagnostic service; used by the telecom command line command to override
+ * the {@link CallDiagnosticService} to bind to for CTS test purposes.
+ * @param packageName The package name to set to.
+ */
+ public void setTestCallDiagnosticService(@Nullable String packageName) {
+ if (TextUtils.isEmpty(packageName)) {
+ mTestPackageName = null;
+ } else {
+ mTestPackageName = packageName;
+ }
+
+ Log.i(this, "setTestCallDiagnosticService: packageName=%s", packageName);
+ }
+
+ /**
+ * Determines the active call diagnostic service, taking into account the test override.
+ * @return The package name of the active call diagnostic service.
+ */
+ private @Nullable String getActiveCallDiagnosticService() {
+ if (mTestPackageName != null) {
+ return mTestPackageName;
+ }
+
+ return mPackageName;
+ }
+
+ /**
+ * If we are not already bound to the {@link CallDiagnosticService}, attempts to initiate a
+ * binding tho that service.
+ * @return {@code true} if we bound, {@code false} otherwise.
+ */
+ private boolean maybeBindCallDiagnosticService() {
+ if (mConnection != null) {
+ return false;
+ }
+
+ mConnection = new CallDiagnosticServiceConnection();
+ boolean bound = bindCallDiagnosticService(mContextProxy.getCurrentUserHandle(),
+ getActiveCallDiagnosticService(), mConnection);
+ if (!bound) {
+ mConnection = null;
+ }
+ return bound;
+ }
+
+ /**
+ * Performs binding to the {@link CallDiagnosticService}.
+ * @param userHandle user name to bind via.
+ * @param packageName package name of the CDS.
+ * @param serviceConnection The service connection to be notified of bind events.
+ * @return
+ */
+ private boolean bindCallDiagnosticService(UserHandle userHandle,
+ String packageName, CallDiagnosticServiceConnection serviceConnection) {
+
+ if (TextUtils.isEmpty(packageName)) {
+ Log.i(this, "bindCallDiagnosticService: no package; skip binding.");
+ return false;
+ }
+
+ Intent intent = new Intent(CallDiagnosticService.SERVICE_INTERFACE)
+ .setPackage(packageName);
+ Log.i(this, "bindCallDiagnosticService: user %d.", userHandle.getIdentifier());
+ List<ResolveInfo> entries = mContextProxy.queryIntentServicesAsUser(intent, 0,
+ userHandle.getIdentifier());
+ if (entries.isEmpty()) {
+ Log.i(this, "bindCallDiagnosticService: %s has no service.", packageName);
+ return false;
+ }
+
+ ResolveInfo entry = entries.get(0);
+ if (entry.serviceInfo == null) {
+ Log.i(this, "bindCallDiagnosticService: %s has no service info.", packageName);
+ return false;
+ }
+
+ if (entry.serviceInfo.permission == null || !entry.serviceInfo.permission.equals(
+ Manifest.permission.BIND_CALL_DIAGNOSTIC_SERVICE)) {
+ Log.i(this, "bindCallDiagnosticService: %s doesn't require "
+ + "BIND_CALL_DIAGNOSTIC_SERVICE.", packageName);
+ return false;
+ }
+
+ ComponentName componentName =
+ new ComponentName(entry.serviceInfo.packageName, entry.serviceInfo.name);
+ intent.setComponent(componentName);
+ if (mContextProxy.bindServiceAsUser(
+ intent,
+ serviceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ UserHandle.CURRENT)) {
+ Log.d(this, "bindCallDiagnosticService, found service, waiting for it to connect");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * If we are bound to a {@link CallDiagnosticService}, unbind from it.
+ */
+ public void maybeUnbindCallScreeningService() {
+ if (mConnection != null) {
+ Log.i(this, "maybeUnbindCallScreeningService - unbinding from %s",
+ getActiveCallDiagnosticService());
+ try {
+ mContextProxy.unbindService(mConnection);
+ mCallDiagnosticService = null;
+ mConnection = null;
+ } catch (IllegalArgumentException e) {
+ Log.i(this, "maybeUnbindCallScreeningService: Exception when unbind %s : %s",
+ getActiveCallDiagnosticService(), e.getMessage());
+ }
+ } else {
+ Log.w(this, "maybeUnbindCallScreeningService - already unbound");
+ }
+ }
+
+ /**
+ * Implements the abstracted Telecom functionality the {@link CallDiagnosticServiceAdapter}
+ * depends on.
+ */
+ private CallDiagnosticServiceAdapter.TelecomAdapter mTelecomAdapter =
+ new CallDiagnosticServiceAdapter.TelecomAdapter() {
+
+ @Override
+ public void displayDiagnosticMessage(String callId, int messageId, CharSequence message) {
+ handleDisplayDiagnosticMessage(callId, messageId, message);
+ }
+
+ @Override
+ public void clearDiagnosticMessage(String callId, int messageId) {
+ handleClearDiagnosticMessage(callId, messageId);
+ }
+
+ @Override
+ public void sendDeviceToDeviceMessage(String callId,
+ @CallDiagnostics.MessageType int message, int value) {
+ handleSendD2DMessage(callId, message, value);
+ }
+
+ @Override
+ public void overrideDisconnectMessage(String callId, CharSequence message) {
+ handleOverrideDisconnectMessage(callId, message);
+ }
+ };
+
+ /**
+ * Sends all calls to the specified {@link CallDiagnosticService}.
+ * @param callDiagnosticService the CDS to send calls to.
+ */
+ private void handleConnectionComplete(@NonNull ICallDiagnosticService callDiagnosticService) {
+ mAdapter = new CallDiagnosticServiceAdapter(mTelecomAdapter,
+ getActiveCallDiagnosticService(), mLock);
+ try {
+ // Add adapter for communication back from the call diagnostic service to Telecom.
+ callDiagnosticService.setAdapter(mAdapter);
+
+ // Loop through all the calls we've got ready to send since binding.
+ for (Call call : mCallIdMapper.getCalls()) {
+ sendCallToBoundService(call, callDiagnosticService);
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "handleConnectionComplete: error=%s", e);
+ }
+ }
+
+ /**
+ * Handles a request from a {@link CallDiagnosticService} to display a diagnostic message.
+ * @param callId the ID of the call to display the message for.
+ * @param message the message.
+ */
+ private void handleDisplayDiagnosticMessage(@NonNull String callId, int messageId,
+ @Nullable CharSequence message) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call == null) {
+ Log.w(this, "handleDisplayDiagnosticMessage: callId=%s; msg=%d/%s; invalid call",
+ callId, messageId, message);
+ return;
+ }
+ Log.i(this, "handleDisplayDiagnosticMessage: callId=%s; msg=%d/%s",
+ callId, messageId, message);
+ if (mPlayerFactory != null) {
+ // Play that tone!
+ mPlayerFactory.createPlayer(InCallTonePlayer.TONE_IN_CALL_QUALITY_NOTIFICATION)
+ .startTone();
+ }
+ call.displayDiagnosticMessage(messageId, message);
+ }
+
+ /**
+ * Handles a request from a {@link CallDiagnosticService} to clear a previously displayed
+ * diagnostic message.
+ * @param callId the ID of the call to display the message for.
+ * @param messageId the message ID which was previous posted.
+ */
+ private void handleClearDiagnosticMessage(@NonNull String callId, int messageId) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call == null) {
+ Log.w(this, "handleClearDiagnosticMessage: callId=%s; msg=%d; invalid call",
+ callId, messageId);
+ return;
+ }
+ Log.i(this, "handleClearDiagnosticMessage: callId=%s; msg=%d; invalid call",
+ callId, messageId);
+ call.clearDiagnosticMessage(messageId);
+ }
+
+ /**
+ * Handles a request from a {@link CallDiagnosticService} to send a device to device message.
+ * @param callId The ID of the call to send the D2D message for.
+ * @param message The message type.
+ * @param value The message value.
+ */
+ private void handleSendD2DMessage(@NonNull String callId,
+ @CallDiagnostics.MessageType int message, int value) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call == null) {
+ Log.w(this, "handleSendD2DMessage: callId=%s; msg=%d/%d; invalid call", callId,
+ message, value);
+ return;
+ }
+ Log.i(this, "handleSendD2DMessage: callId=%s; msg=%d/%d", callId, message, value);
+ call.sendDeviceToDeviceMessage(message, value);
+ }
+
+ /**
+ * Handles a request from a {@link CallDiagnosticService} to override the disconnect message
+ * for a call. This is the response path from a previous call into the
+ * {@link CallDiagnosticService} via {@link CallDiagnostics#onCallDisconnected(ImsReasonInfo)}.
+ * @param callId The telecom call ID the disconnect override is pending for.
+ * @param message The new disconnect message, or {@code null} if no override.
+ */
+ private void handleOverrideDisconnectMessage(@NonNull String callId,
+ @Nullable CharSequence message) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call == null) {
+ Log.w(this, "handleOverrideDisconnectMessage: callId=%s; msg=%s; invalid call", callId,
+ message);
+ return;
+ }
+ Log.i(this, "handleOverrideDisconnectMessage: callId=%s; msg=%s", callId, message);
+ call.handleOverrideDisconnectMessage(message);
+ }
+
+ /**
+ * Sends a single call to the bound {@link CallDiagnosticService}.
+ * @param call The call to send.
+ * @param callDiagnosticService The CDS to send it to.
+ */
+ private void sendCallToBoundService(@NonNull Call call,
+ @NonNull ICallDiagnosticService callDiagnosticService) {
+ try {
+ if (isConnected()) {
+ Log.w(this, "sendCallToBoundService: initializing %s", call.getId());
+ callDiagnosticService.initializeDiagnosticCall(getParceledCall(call));
+ } else {
+ Log.w(this, "sendCallToBoundService: not bound, skipping %s", call.getId());
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "sendCallToBoundService: callId=%s, exception=%s", call.getId(), e);
+ }
+ }
+
+ /**
+ * Removes a call from a bound {@link CallDiagnosticService}.
+ * @param call The call to remove.
+ * @param callDiagnosticService The CDS to remove it from.
+ */
+ private void removeCallFromBoundService(@NonNull Call call,
+ @NonNull ICallDiagnosticService callDiagnosticService) {
+ try {
+ if (isConnected()) {
+ callDiagnosticService.removeDiagnosticCall(call.getId());
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "removeCallFromBoundService: callId=%s, exception=%s", call.getId(), e);
+ }
+ }
+
+ /**
+ * @return {@code true} if the call diagnostic service is bound/connected.
+ */
+ public boolean isConnected() {
+ return mCallDiagnosticService != null;
+ }
+
+ /**
+ * Updates the Call diagnostic service with changes to a call.
+ * @param call The updated call.
+ */
+ private void updateCall(@NonNull Call call) {
+ try {
+ if (isConnected()) {
+ mCallDiagnosticService.updateCall(getParceledCall(call));
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "updateCall: callId=%s, exception=%s", call.getId(), e);
+ }
+ }
+
+ /**
+ * Updates the call diagnostic service with a received bluetooth quality report.
+ * @param call The call.
+ * @param report The bluetooth call quality report.
+ */
+ private void handleBluetoothCallQualityReport(@NonNull Call call,
+ @NonNull BluetoothCallQualityReport report) {
+ try {
+ if (isConnected()) {
+ mCallDiagnosticService.receiveBluetoothCallQualityReport(report);
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "handleBluetoothCallQualityReport: callId=%s, exception=%s", call.getId(),
+ e);
+ }
+ }
+
+ /**
+ * Informs a CallDiagnosticService of an incoming device to device message which was received
+ * via the carrier network.
+ * @param call the call the message was received via.
+ * @param messageType The message type.
+ * @param messageValue The message value.
+ */
+ private void handleReceivedDeviceToDeviceMessage(@NonNull Call call, int messageType,
+ int messageValue) {
+ try {
+ if (isConnected()) {
+ mCallDiagnosticService.receiveDeviceToDeviceMessage(call.getId(), messageType,
+ messageValue);
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "handleReceivedDeviceToDeviceMessage: callId=%s, exception=%s",
+ call.getId(), e);
+ }
+ }
+
+ /**
+ * Handles a reported {@link CallQuality} report from a {@link android.telecom.Connection}.
+ * @param call The call the report originated from.
+ * @param callQualityReport The {@link CallQuality} report.
+ */
+ private void handleCallQualityReport(@NonNull Call call,
+ @NonNull CallQuality callQualityReport) {
+ try {
+ if (isConnected()) {
+ mCallDiagnosticService.callQualityChanged(call.getId(), callQualityReport);
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "handleCallQualityReport: callId=%s, exception=%s",
+ call.getId(), e);
+ }
+ }
+
+ /**
+ * Get a parcelled representation of a call for transport to the service.
+ * @param call The call.
+ * @return The parcelled call.
+ */
+ private @NonNull ParcelableCall getParceledCall(@NonNull Call call) {
+ return ParcelableCallUtils.toParcelableCall(
+ call,
+ false /* includeVideoProvider */,
+ null /* phoneAcctRegistrar */,
+ false /* supportsExternalCalls */,
+ false /* includeRttCall */,
+ false /* isForSystemDialer */
+ );
+ }
+
+ /**
+ * Dumps the state of the {@link CallDiagnosticServiceController}.
+ *
+ * @param pw The {@code IndentingPrintWriter} to write the state to.
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.print("activeCallDiagnosticService: ");
+ pw.println(getActiveCallDiagnosticService());
+ pw.print("isConnected: ");
+ pw.println(isConnected());
+ }
+}
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 3cec618..0ec2362 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -16,7 +16,7 @@
package com.android.server.telecom;
-import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+import static android.provider.CallLog.Calls.BLOCK_REASON_NOT_BLOCKED;
import static android.telephony.CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL;
import android.annotation.Nullable;
@@ -24,25 +24,26 @@
import android.content.Intent;
import android.location.Country;
import android.location.CountryDetector;
+import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Looper;
import android.os.UserHandle;
import android.os.PersistableBundle;
+import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.Log;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionManager;
-// TODO: Needed for move to system service: import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import android.telecom.CallerInfo;
import com.android.server.telecom.callfiltering.CallFilteringResult;
import java.util.Arrays;
@@ -66,71 +67,19 @@
* Parameter object to hold the arguments to add a call in the call log DB.
*/
private static class AddCallArgs {
- /**
- * @param callerInfo Caller details.
- * @param number The phone number to be logged.
- * @param presentation Number presentation of the phone number to be logged.
- * @param callType The type of call (e.g INCOMING_TYPE). @see
- * {@link android.provider.CallLog} for the list of values.
- * @param features The features of the call (e.g. FEATURES_VIDEO). @see
- * {@link android.provider.CallLog} for the list of values.
- * @param creationDate Time when the call was created (milliseconds since epoch).
- * @param durationInMillis Duration of the call (milliseconds).
- * @param dataUsage Data usage in bytes, or null if not applicable.
- * @param isRead Indicates if the entry has been read or not.
- * @param logCallCompletedListener optional callback called after the call is logged.
- */
- public AddCallArgs(Context context, CallerInfo callerInfo, String number,
- String postDialDigits, String viaNumber, int presentation, int callType,
- int features, PhoneAccountHandle accountHandle, long creationDate,
- long durationInMillis, Long dataUsage, UserHandle initiatingUser, boolean isRead,
- @Nullable LogCallCompletedListener logCallCompletedListener, int callBlockReason,
- CharSequence callScreeningAppName, String callScreeningComponentName,
- long missedReason) {
+ public AddCallArgs(Context context, CallLog.AddCallParams params,
+ @Nullable LogCallCompletedListener logCallCompletedListener) {
this.context = context;
- this.callerInfo = callerInfo;
- this.number = number;
- this.postDialDigits = postDialDigits;
- this.viaNumber = viaNumber;
- this.presentation = presentation;
- this.callType = callType;
- this.features = features;
- this.accountHandle = accountHandle;
- this.timestamp = creationDate;
- this.durationInSec = (int)(durationInMillis / 1000);
- this.dataUsage = dataUsage;
- this.initiatingUser = initiatingUser;
- this.isRead = isRead;
+ this.params = params;
this.logCallCompletedListener = logCallCompletedListener;
- this.callBockReason = callBlockReason;
- this.callScreeningAppName = callScreeningAppName;
- this.callScreeningComponentName = callScreeningComponentName;
- this.missedReason = missedReason;
+
}
// Since the members are accessed directly, we don't use the
// mXxxx notation.
public final Context context;
- public final CallerInfo callerInfo;
- public final String number;
- public final String postDialDigits;
- public final String viaNumber;
- public final int presentation;
- public final int callType;
- public final int features;
- public final PhoneAccountHandle accountHandle;
- public final long timestamp;
- public final int durationInSec;
- public final Long dataUsage;
- public final UserHandle initiatingUser;
- public final boolean isRead;
-
+ public final CallLog.AddCallParams params;
@Nullable
public final LogCallCompletedListener logCallCompletedListener;
-
- public final int callBockReason;
- public final CharSequence callScreeningAppName;
- public final String callScreeningComponentName;
- public final long missedReason;
}
private static final String TAG = CallLogManager.class.getSimpleName();
@@ -315,47 +264,50 @@
*/
void logCall(Call call, int callLogType,
@Nullable LogCallCompletedListener logCallCompletedListener, CallFilteringResult result) {
- long creationTime;
+ CallLog.AddCallParams.AddCallParametersBuilder paramBuilder =
+ new CallLog.AddCallParams.AddCallParametersBuilder();
if (call.getConnectTimeMillis() != 0
&& call.getConnectTimeMillis() < call.getCreationTimeMillis()) {
// If connected time is available, use connected time. The connected time might be
// earlier than created time since it might come from carrier sent special SMS to
// notifier user earlier missed call.
- creationTime = call.getConnectTimeMillis();
+ paramBuilder.setStart(call.getConnectTimeMillis());
} else {
- creationTime = call.getCreationTimeMillis();
+ paramBuilder.setStart(call.getCreationTimeMillis());
}
- final long age = call.getAgeMillis();
+ paramBuilder.setDuration((int) (call.getAgeMillis() / 1000));
- final String logNumber = getLogNumber(call);
+ String logNumber = getLogNumber(call);
+ paramBuilder.setNumber(logNumber);
Log.d(TAG, "logNumber set to: %s", Log.pii(logNumber));
- final PhoneAccountHandle emergencyAccountHandle =
- TelephonyUtil.getDefaultEmergencyPhoneAccount().getAccountHandle();
-
String formattedViaNumber = PhoneNumberUtils.formatNumber(call.getViaNumber(),
getCountryIso());
formattedViaNumber = (formattedViaNumber != null) ?
formattedViaNumber : call.getViaNumber();
+ paramBuilder.setViaNumber(formattedViaNumber);
+ final PhoneAccountHandle emergencyAccountHandle =
+ TelephonyUtil.getDefaultEmergencyPhoneAccount().getAccountHandle();
PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();
if (emergencyAccountHandle.equals(accountHandle)) {
accountHandle = null;
}
+ paramBuilder.setAccountHandle(accountHandle);
- Long callDataUsage = call.getCallDataUsage() == Call.DATA_USAGE_NOT_SET ? null :
- call.getCallDataUsage();
+ paramBuilder.setDataUsage(call.getCallDataUsage() == Call.DATA_USAGE_NOT_SET
+ ? Long.MIN_VALUE : call.getCallDataUsage());
- int callFeatures = getCallFeatures(call.getVideoStateHistory(),
+ paramBuilder.setFeatures(getCallFeatures(call.getVideoStateHistory(),
call.getDisconnectCause().getCode() == DisconnectCause.CALL_PULLED,
call.wasHighDefAudio(), call.wasWifi(),
(call.getConnectionProperties() & Connection.PROPERTY_ASSISTED_DIALING) ==
Connection.PROPERTY_ASSISTED_DIALING,
call.wasEverRttCall(),
- call.wasVolte());
+ call.wasVolte()));
if (result == null) {
result = new CallFilteringResult.Builder()
@@ -363,67 +315,82 @@
.setCallScreeningComponentName(call.getCallScreeningComponentName())
.build();
}
-
if (callLogType == Calls.BLOCKED_TYPE || callLogType == Calls.MISSED_TYPE) {
- logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
- call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
- creationTime, age, callDataUsage, call.isEmergencyCall(),
- call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
- result.mCallBlockReason, result.mCallScreeningAppName,
- result.mCallScreeningComponentName, call.getMissedReason());
+ paramBuilder.setCallBlockReason(result.mCallBlockReason);
+ paramBuilder.setCallScreeningComponentName(result.mCallScreeningComponentName);
+ paramBuilder.setCallScreeningAppName(result.mCallScreeningAppName);
} else {
- logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
- call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
- creationTime, age, callDataUsage, call.isEmergencyCall(),
- call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
- Calls.BLOCK_REASON_NOT_BLOCKED, null /*callScreeningAppName*/,
- null /*callScreeningComponentName*/, call.getMissedReason());
+ paramBuilder.setCallBlockReason(BLOCK_REASON_NOT_BLOCKED);
+ }
+
+ PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(accountHandle);
+ UserHandle initiatingUser = call.getInitiatingUser();
+ if (phoneAccount != null &&
+ phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
+ if (initiatingUser != null &&
+ UserUtil.isManagedProfile(mContext, initiatingUser)) {
+ paramBuilder.setUserToBeInsertedTo(initiatingUser);
+ paramBuilder.setAddForAllUsers(false);
+ } else {
+ paramBuilder.setAddForAllUsers(true);
+ }
+ } else {
+ if (accountHandle == null) {
+ paramBuilder.setAddForAllUsers(true);
+ } else {
+ paramBuilder.setUserToBeInsertedTo(accountHandle.getUserHandle());
+ paramBuilder.setAddForAllUsers(accountHandle.getUserHandle() == null);
+ }
+ }
+ if (call.getIntentExtras() != null) {
+ if (call.getIntentExtras().containsKey(TelecomManager.EXTRA_PRIORITY)) {
+ paramBuilder.setPriority(call.getIntentExtras()
+ .getInt(TelecomManager.EXTRA_PRIORITY));
+ }
+ if (call.getIntentExtras().containsKey(TelecomManager.EXTRA_CALL_SUBJECT)) {
+ paramBuilder.setSubject(call.getIntentExtras()
+ .getString(TelecomManager.EXTRA_CALL_SUBJECT));
+ }
+ if (call.getIntentExtras().containsKey(TelecomManager.EXTRA_PICTURE_URI)) {
+ paramBuilder.setPictureUri(call.getIntentExtras()
+ .getParcelable(TelecomManager.EXTRA_PICTURE_URI));
+ }
+ // The picture uri can end up either in extras or in intent extras due to how these
+ // two bundles are set. For incoming calls they're in extras, but for outgoing calls
+ // they're in intentExtras.
+ if (call.getExtras() != null
+ && call.getExtras().containsKey(TelecomManager.EXTRA_PICTURE_URI)) {
+ paramBuilder.setPictureUri(call.getExtras()
+ .getParcelable(TelecomManager.EXTRA_PICTURE_URI));
+ }
+ if (call.getIntentExtras().containsKey(TelecomManager.EXTRA_LOCATION)) {
+ Location l = call.getIntentExtras().getParcelable(TelecomManager.EXTRA_LOCATION);
+ if (l != null) {
+ paramBuilder.setLatitude(l.getLatitude());
+ paramBuilder.setLongitude(l.getLongitude());
+ }
+ }
+ }
+
+ paramBuilder.setCallerInfo(call.getCallerInfo());
+ paramBuilder.setPostDialDigits(call.getPostDialDigits());
+ paramBuilder.setPresentation(call.getHandlePresentation());
+ paramBuilder.setCallType(callLogType);
+ paramBuilder.setIsRead(call.isSelfManaged());
+ paramBuilder.setMissedReason(call.getMissedReason());
+
+ sendAddCallBroadcast(callLogType, call.getAgeMillis());
+
+ boolean okayToLog =
+ okayToLogCall(accountHandle, logNumber, call.isEmergencyCall());
+ if (okayToLog) {
+ AddCallArgs args = new AddCallArgs(mContext, paramBuilder.build(),
+ logCallCompletedListener);
+ logCallAsync(args);
}
}
- /**
- * Inserts a call into the call log, based on the parameters passed in.
- *
- * @param callerInfo Caller details.
- * @param number The number the call was made to or from.
- * @param postDialDigits The post-dial digits that were dialed after the number,
- * if it was an outgoing call. Otherwise ''.
- * @param presentation
- * @param callType The type of call.
- * @param features The features of the call.
- * @param start The start time of the call, in milliseconds.
- * @param duration The duration of the call, in milliseconds.
- * @param dataUsage The data usage for the call, null if not applicable.
- * @param isEmergency {@code true} if this is an emergency call, {@code false} otherwise.
- * @param logCallCompletedListener optional callback called after the call is logged.
- * @param initiatingUser The user the call was initiated under.
- * @param isSelfManaged {@code true} if this is a self-managed call, {@code false} otherwise.
- * @param callBlockReason The reason why the call is blocked.
- * @param callScreeningAppName The call screening application name which block the call.
- * @param callScreeningComponentName The call screening component name which block the call.
- * @param missedReason The encoded information about reasons for missed call.
- */
- private void logCall(
- CallerInfo callerInfo,
- String number,
- String postDialDigits,
- String viaNumber,
- int presentation,
- int callType,
- int features,
- PhoneAccountHandle accountHandle,
- long start,
- long duration,
- Long dataUsage,
- boolean isEmergency,
- UserHandle initiatingUser,
- boolean isSelfManaged,
- @Nullable LogCallCompletedListener logCallCompletedListener,
- int callBlockReason,
- CharSequence callScreeningAppName,
- String callScreeningComponentName,
- long missedReason) {
-
+ boolean okayToLogCall(PhoneAccountHandle accountHandle, String number, boolean isEmergency) {
// On some devices, to avoid accidental redialing of emergency numbers, we *never* log
// emergency calls to the Call Log. (This behavior is set on a per-product basis, based
// on carrier requirements.)
@@ -438,29 +405,8 @@
}
// Don't log emergency numbers if the device doesn't allow it.
- final boolean isOkToLogThisCall = (!isEmergency || okToLogEmergencyNumber)
+ return (!isEmergency || okToLogEmergencyNumber)
&& !isUnloggableNumber(number, configBundle);
-
- sendAddCallBroadcast(callType, duration);
-
- if (isOkToLogThisCall) {
- Log.d(TAG, "Logging Call log entry: " + callerInfo + ", "
- + Log.pii(number) + "," + presentation + ", " + callType
- + ", " + start + ", " + duration);
- boolean isRead = false;
- if (isSelfManaged) {
- // Mark self-managed calls are read since they're being handled by their own app.
- // Their inclusion in the call log is informational only.
- isRead = true;
- }
- AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
- viaNumber, presentation, callType, features, accountHandle, start, duration,
- dataUsage, initiatingUser, isRead, logCallCompletedListener, callBlockReason,
- callScreeningAppName, callScreeningComponentName, missedReason);
- logCallAsync(args);
- } else {
- Log.d(TAG, "Not adding emergency call to call log.");
- }
}
private boolean isUnloggableNumber(String callNumber, PersistableBundle carrierConfig) {
@@ -566,7 +512,7 @@
mListeners[i] = c.logCallCompletedListener;
try {
// May block.
- result[i] = addCall(c);
+ result[i] = Calls.addCall(c.context, c.params);
} catch (Exception e) {
// This is very rare but may happen in legitimate cases.
// E.g. If the phone is encrypted and thus write request fails, it may cause
@@ -582,37 +528,6 @@
return result;
}
- private Uri addCall(AddCallArgs c) {
- PhoneAccount phoneAccount = mPhoneAccountRegistrar
- .getPhoneAccountUnchecked(c.accountHandle);
- if (phoneAccount != null &&
- phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
- if (c.initiatingUser != null &&
- UserUtil.isManagedProfile(mContext, c.initiatingUser)) {
- return addCall(c, c.initiatingUser);
- } else {
- return addCall(c, null);
- }
- } else {
- return addCall(c, c.accountHandle == null ? null : c.accountHandle.getUserHandle());
- }
- }
-
- /**
- * Insert the call to a specific user or all users except managed profile.
- * @param c context
- * @param userToBeInserted user handle of user that the call going be inserted to. null
- * if insert to all users except managed profile.
- */
- private Uri addCall(AddCallArgs c, UserHandle userToBeInserted) {
- return Calls.addCall(c.callerInfo, c.context, c.number, c.postDialDigits, c.viaNumber,
- c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
- c.durationInSec, c.dataUsage, userToBeInserted == null,
- userToBeInserted, c.isRead, c.callBockReason, c.callScreeningAppName,
- c.callScreeningComponentName, c.missedReason);
- }
-
-
@Override
protected void onPostExecute(Uri[] result) {
for (int i = 0; i < result.length; i++) {
diff --git a/src/com/android/server/telecom/CallScreeningServiceHelper.java b/src/com/android/server/telecom/CallScreeningServiceHelper.java
index f02b924..9435250 100644
--- a/src/com/android/server/telecom/CallScreeningServiceHelper.java
+++ b/src/com/android/server/telecom/CallScreeningServiceHelper.java
@@ -55,23 +55,8 @@
}
@Override
- public void allowCall(String s) throws RemoteException {
- unbindCallScreeningService();
- }
-
- @Override
- public void silenceCall(String s) throws RemoteException {
- unbindCallScreeningService();
- }
-
- @Override
- public void screenCallFurther(String callId) throws RemoteException {
- unbindCallScreeningService();
- }
-
- @Override
- public void disallowCall(String s, boolean b, boolean b1, boolean b2,
- ComponentName componentName) throws RemoteException {
+ public void onScreeningResponse(String callId, ComponentName componentName,
+ CallScreeningService.ParcelableCallResponse callResponse) {
unbindCallScreeningService();
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 5b3c2f7..6873e42 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -72,6 +72,7 @@
import android.provider.Settings;
import android.sysprop.TelephonyProperties;
import android.telecom.CallAudioState;
+import android.telecom.CallScreeningService;
import android.telecom.CallerInfo;
import android.telecom.Conference;
import android.telecom.Connection;
@@ -332,6 +333,7 @@
private final ConnectionServiceRepository mConnectionServiceRepository;
private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
private final InCallController mInCallController;
+ private final CallDiagnosticServiceController mCallDiagnosticServiceController;
private final CallAudioManager mCallAudioManager;
private final CallRecordingTonePlayer mCallRecordingTonePlayer;
private RespondViaSmsManager mRespondViaSmsManager;
@@ -487,6 +489,7 @@
CallAudioRouteStateMachine.Factory callAudioRouteStateMachineFactory,
CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory,
InCallControllerFactory inCallControllerFactory,
+ CallDiagnosticServiceController callDiagnosticServiceController,
RoleManagerAdapter roleManagerAdapter,
ToastFactory toastFactory) {
mContext = context;
@@ -543,6 +546,8 @@
mInCallController = inCallControllerFactory.create(context, mLock, this,
systemStateHelper, defaultDialerCache, mTimeoutsAdapter,
emergencyCallHelper);
+ mCallDiagnosticServiceController = callDiagnosticServiceController;
+ mCallDiagnosticServiceController.setInCallTonePlayerFactory(playerFactory);
mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
ringtoneFactory, systemVibrator,
new Ringer.VibrationEffectProxy(), mInCallController);
@@ -572,6 +577,7 @@
mListeners.add(mCallLogManager);
mListeners.add(mPhoneStateBroadcaster);
mListeners.add(mInCallController);
+ mListeners.add(mCallDiagnosticServiceController);
mListeners.add(mCallAudioManager);
mListeners.add(mCallRecordingTonePlayer);
mListeners.add(missedCallNotifier);
@@ -590,7 +596,7 @@
IntentFilter intentFilter = new IntentFilter(
CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intentFilter.addAction(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED);
- context.registerReceiver(mReceiver, intentFilter);
+ context.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_EXPORTED);
mGraphHandlerThreads = new LinkedList<>();
}
@@ -622,6 +628,10 @@
return mRoleManagerAdapter;
}
+ public CallDiagnosticServiceController getCallDiagnosticServiceController() {
+ return mCallDiagnosticServiceController;
+ }
+
@Override
public void onSuccessfulOutgoingCall(Call call, int callState) {
Log.v(this, "onSuccessfulOutgoingCall, %s", call);
@@ -759,6 +769,42 @@
return;
}
+ // Inform our connection service that call filtering is done (if it was performed at all).
+ if (incomingCall.isUsingCallFiltering()) {
+ boolean isInContacts = incomingCall.getCallerInfo() != null
+ && incomingCall.getCallerInfo().contactExists;
+ Connection.CallFilteringCompletionInfo completionInfo =
+ new Connection.CallFilteringCompletionInfo(!result.shouldAllowCall,
+ isInContacts,
+ result.mCallScreeningResponse == null
+ ? null : result.mCallScreeningResponse.toCallResponse(),
+ result.mCallScreeningComponentName == null ? null
+ : ComponentName.unflattenFromString(
+ result.mCallScreeningComponentName));
+ incomingCall.getConnectionService().onCallFilteringCompleted(incomingCall,
+ completionInfo);
+ }
+
+ // Get rid of the call composer attachments that aren't wanted
+ if (result.mIsResponseFromSystemDialer && result.mCallScreeningResponse != null
+ && result.mCallScreeningResponse.getCallComposerAttachmentsToShow() >= 0) {
+ int attachmentMask = result.mCallScreeningResponse.getCallComposerAttachmentsToShow();
+ if ((attachmentMask
+ & CallScreeningService.CallResponse.CALL_COMPOSER_ATTACHMENT_LOCATION) == 0) {
+ incomingCall.getIntentExtras().remove(TelecomManager.EXTRA_LOCATION);
+ }
+
+ if ((attachmentMask
+ & CallScreeningService.CallResponse.CALL_COMPOSER_ATTACHMENT_SUBJECT) == 0) {
+ incomingCall.getIntentExtras().remove(TelecomManager.EXTRA_CALL_SUBJECT);
+ }
+
+ if ((attachmentMask
+ & CallScreeningService.CallResponse.CALL_COMPOSER_ATTACHMENT_PRIORITY) == 0) {
+ incomingCall.getIntentExtras().remove(TelecomManager.EXTRA_PRIORITY);
+ }
+ }
+
if (result.shouldAllowCall) {
incomingCall.setPostCallPackageName(
getRoleManagerAdapter().getDefaultCallScreeningApp());
@@ -1242,8 +1288,8 @@
if (call.isSelfManaged()) {
// Self managed calls will always be voip audio mode.
call.setIsVoipAudioMode(true);
- call.setVisibleToInCallService(phoneAccountExtras != null
- && phoneAccountExtras.getBoolean(
+ call.setVisibleToInCallService(phoneAccountExtras == null
+ || phoneAccountExtras.getBoolean(
PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true));
} else {
// Incoming call is managed, the active call is self-managed and can't be held.
@@ -1480,6 +1526,16 @@
Bundle phoneAccountExtra = account != null ? account.getExtras() : null;
boolean isSelfManaged = account != null && account.isSelfManaged();
+ StringBuffer creationLogs = new StringBuffer();
+ creationLogs.append("requestedAcct:");
+ if (requestedAccountHandle == null) {
+ creationLogs.append("none");
+ } else {
+ creationLogs.append(requestedAccountHandle);
+ }
+ creationLogs.append(", selfMgd:");
+ creationLogs.append(isSelfManaged);
+
// Create a call with original handle. The handle may be changed when the call is attached
// to a connection service, but in most cases will remain the same.
if (call == null) {
@@ -1498,7 +1554,7 @@
isConference, /* isConference */
mClockProxy,
mToastFactory);
- call.initAnalytics(callingPackage);
+ call.initAnalytics(callingPackage, creationLogs.toString());
// 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,
@@ -1508,8 +1564,8 @@
if (isSelfManaged) {
// Self-managed calls will ALWAYS use voip audio mode.
call.setIsVoipAudioMode(true);
- call.setVisibleToInCallService(phoneAccountExtra != null
- && phoneAccountExtra.getBoolean(
+ call.setVisibleToInCallService(phoneAccountExtra == null
+ || phoneAccountExtra.getBoolean(
PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true));
}
call.setInitiatingUser(initiatingUser);
@@ -1570,7 +1626,8 @@
// retrieved.
CompletableFuture<List<PhoneAccountHandle>> setAccountHandle =
accountsForCall.whenCompleteAsync((potentialPhoneAccounts, exception) -> {
- Log.i(CallsManager.this, "set outgoing call phone acct stage");
+ Log.i(CallsManager.this, "set outgoing call phone acct; potentialAccts=%s",
+ potentialPhoneAccounts);
PhoneAccountHandle phoneAccountHandle;
if (potentialPhoneAccounts.size() == 1) {
phoneAccountHandle = potentialPhoneAccounts.get(0);
@@ -1629,6 +1686,21 @@
}
}
+ if (!finalCall.isEmergencyCall() && isInEmergencyCall()) {
+ Log.i(CallsManager.this, "Aborting call since there's an"
+ + " ongoing emergency call");
+ // If the ongoing call is a managed call, we will prevent the outgoing
+ // call from dialing.
+ if (isConference) {
+ notifyCreateConferenceFailed(finalCall.getTargetPhoneAccount(),
+ finalCall);
+ } else {
+ notifyCreateConnectionFailed(
+ finalCall.getTargetPhoneAccount(), finalCall);
+ }
+ return CompletableFuture.completedFuture(null);
+ }
+
// If we can not supportany more active calls, our options are to move a call
// to hold, disconnect a call, or cancel this call altogether.
boolean isRoomForCall = finalCall.isEmergencyCall() ?
@@ -1971,6 +2043,8 @@
return userPreferredAccountForContact.thenApply(phoneAccountHandle -> {
if (phoneAccountHandle != null) {
+ Log.i(CallsManager.this, "findOutgoingCallPhoneAccount; contactPrefAcct=%s",
+ phoneAccountHandle);
return Collections.singletonList(phoneAccountHandle);
}
// No preset account, check if default exists that supports the URI scheme for the
@@ -1980,6 +2054,8 @@
handle.getScheme(), initiatingUser);
if (defaultPhoneAccountHandle != null &&
possibleAccounts.contains(defaultPhoneAccountHandle)) {
+ Log.i(CallsManager.this, "findOutgoingCallPhoneAccount; defaultAcctForScheme=%s",
+ defaultPhoneAccountHandle);
return Collections.singletonList(defaultPhoneAccountHandle);
}
return possibleAccounts;
@@ -2018,6 +2094,8 @@
handle.getSchemeSpecificPart());
} catch (IllegalStateException ise) {
isPotentialEmergencyNumber = false;
+ } catch (RuntimeException r) {
+ isPotentialEmergencyNumber = false;
}
if (shouldCancelCall) {
@@ -2115,7 +2193,7 @@
* @param callId The ID of the call to show the redirection dialog for.
*/
private void showRedirectionDialog(@NonNull String callId, @NonNull CharSequence appName) {
- AlertDialog confirmDialog = new AlertDialog.Builder(mContext).create();
+ AlertDialog confirmDialog = FrameworksUtils.makeAlertDialogBuilder(mContext).create();
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
View dialogView = layoutInflater.inflate(R.layout.call_redirection_confirm_dialog, null);
@@ -2195,8 +2273,16 @@
public void processRedirectedOutgoingCallAfterUserInteraction(String callId, String action) {
Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for Call ID %s, action=%s",
callId, action);
- if (mPendingRedirectedOutgoingCall != null && mPendingRedirectedOutgoingCall.getId()
- .equals(callId)) {
+ if (mPendingRedirectedOutgoingCall != null) {
+ String pendingCallId = mPendingRedirectedOutgoingCall.getId();
+ if (!pendingCallId.equals(callId)) {
+ Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for new Call ID %s, "
+ + "cancel the previous pending Call with ID %s", callId, pendingCallId);
+ mPendingRedirectedOutgoingCall.disconnect("Another call redirection requested");
+ mPendingRedirectedOutgoingCallInfo.remove(pendingCallId);
+ mPendingUnredirectedOutgoingCallInfo.remove(pendingCallId);
+ }
+
if (action.equals(TelecomBroadcastIntentProcessor.ACTION_PLACE_REDIRECTED_CALL)) {
mHandler.post(mPendingRedirectedOutgoingCallInfo.get(callId).prepare());
} else if (action.equals(
@@ -2736,6 +2822,16 @@
updateCanAddCall();
}
+ @Override
+ public void onRemoteRttRequest(Call call, int requestId) {
+ Log.i(this, "onRemoteRttRequest: call %s", call.getId());
+ playRttUpgradeToneForCall(call);
+ }
+
+ public void playRttUpgradeToneForCall(Call call) {
+ mCallAudioManager.playRttUpgradeTone(call);
+ }
+
// Construct the list of possible PhoneAccounts that the outgoing call can use based on the
// active calls in CallsManager. If any of the active calls are on a SIM based PhoneAccount,
// then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP.
@@ -2859,8 +2955,8 @@
}
private boolean isRttSettingOn(PhoneAccountHandle handle) {
- boolean isRttModeSettingOn = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.RTT_CALLING_MODE, 0) != 0;
+ boolean isRttModeSettingOn = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.RTT_CALLING_MODE, 0, mContext.getUserId()) != 0;
// If the carrier config says that we should ignore the RTT mode setting from the user,
// assume that it's off (i.e. only make an RTT call if it's requested through the extra).
boolean shouldIgnoreRttModeSetting = getCarrierConfigForPhoneAccount(handle)
@@ -2938,6 +3034,7 @@
*/
boolean holdActiveCallForNewCall(Call call) {
Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall();
+ Log.i(this, "holdActiveCallForNewCall, newCall: %s, activeCall: %s", call, activeCall);
if (activeCall != null && activeCall != call) {
if (canHold(activeCall)) {
activeCall.hold();
@@ -2993,6 +3090,7 @@
@VisibleForTesting
public void markCallAsActive(Call call) {
+ Log.i(this, "markCallAsActive, isSelfManaged: " + call.isSelfManaged());
if (call.isSelfManaged()) {
// backward compatibility, the self-managed connection service will set the call state
// to active directly. We should hold or disconnect the current active call based on the
@@ -3044,27 +3142,83 @@
// be marked as missed.
call.setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.MISSED));
}
- call.setDisconnectCause(disconnectCause);
- setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
- if(oldState == CallState.NEW && disconnectCause.getCode() == DisconnectCause.MISSED) {
+ // If a call diagnostic service is in use, we will log the original telephony-provided
+ // disconnect cause, inform the CDS of the disconnection, and then chain the update of the
+ // call state until AFTER the CDS reports it's result back.
+ if ((oldState == CallState.ACTIVE || oldState == CallState.DIALING)
+ && disconnectCause.getCode() != DisconnectCause.MISSED
+ && mCallDiagnosticServiceController.isConnected()
+ && mCallDiagnosticServiceController.onCallDisconnected(call, disconnectCause)) {
+ Log.i(this, "markCallAsDisconnected; callid=%s, postingToFuture.", call.getId());
+
+ // Log the original disconnect reason prior to calling into the
+ // CallDiagnosticService.
+ Log.addEvent(call, LogUtils.Events.SET_DISCONNECTED_ORIG, disconnectCause);
+
+ // Setup the future with a timeout so that the CDS is time boxed.
+ CompletableFuture<Boolean> future = call.initializeDisconnectFuture(
+ mTimeoutsAdapter.getCallDiagnosticServiceTimeoutMillis(
+ mContext.getContentResolver()));
+
+ // Post the disconnection updates to the future for completion once the CDS returns
+ // with it's overridden disconnect message.
+ future.thenRunAsync(() -> {
+ call.setDisconnectCause(disconnectCause);
+ setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
+ }, new LoggedHandlerExecutor(mHandler, "CM.mCAD", mLock))
+ .exceptionally((throwable) -> {
+ Log.e(TAG, throwable, "Error while executing disconnect future.");
+ return null;
+ });
+ } else {
+ // No CallDiagnosticService, or it doesn't handle this call, so just do this
+ // synchronously as always.
+ call.setDisconnectCause(disconnectCause);
+ setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
+ }
+
+ if (oldState == CallState.NEW && disconnectCause.getCode() == DisconnectCause.MISSED) {
Log.i(this, "markCallAsDisconnected: logging missed call ");
mCallLogManager.logCall(call, Calls.MISSED_TYPE, true, null);
}
-
}
/**
* Removes an existing disconnected call, and notifies the in-call app.
*/
void markCallAsRemoved(Call call) {
+ if (call.isDisconnectHandledViaFuture()) {
+ Log.i(this, "markCallAsRemoved; callid=%s, postingToFuture.", call.getId());
+ // A future is being used due to a CallDiagnosticService handling the call. We will
+ // chain the removal operation to the end of any outstanding disconnect work.
+ call.getDisconnectFuture().thenRunAsync(() -> {
+ performRemoval(call);
+ }, new LoggedHandlerExecutor(mHandler, "CM.mCAR", mLock))
+ .exceptionally((throwable) -> {
+ Log.e(TAG, throwable, "Error while executing disconnect future");
+ return null;
+ });
+
+ } else {
+ Log.i(this, "markCallAsRemoved; callid=%s, immediate.", call.getId());
+ performRemoval(call);
+ }
+ }
+
+ /**
+ * Work which is completed when a call is to be removed. Can either be be run synchronously or
+ * posted to a {@link Call#getDisconnectFuture()}.
+ * @param call The call.
+ */
+ private void performRemoval(Call call) {
mInCallController.getBindingFuture().thenRunAsync(() -> {
call.maybeCleanupHandover();
removeCall(call);
Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
if (mLocallyDisconnectingCalls.contains(call)) {
boolean isDisconnectingChildCall = call.isDisconnectingChildCall();
- Log.v(this, "markCallAsRemoved: isDisconnectingChildCall = "
+ Log.v(this, "performRemoval: isDisconnectingChildCall = "
+ isDisconnectingChildCall + "call -> %s", call);
mLocallyDisconnectingCalls.remove(call);
// Auto-unhold the foreground call due to a locally disconnected call, except if the
@@ -3081,10 +3235,15 @@
// The new foreground call is on hold, however the carrier does not display the hold
// button in the UI. Therefore, we need to auto unhold the held call since the user
// has no means of unholding it themselves.
- Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)");
+ Log.i(this, "performRemoval: Auto-unholding held foreground call (call doesn't "
+ + "support hold)");
foregroundCall.unhold();
}
- }, new LoggedHandlerExecutor(mHandler, "CM.mCAR", mLock));
+ }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock))
+ .exceptionally((throwable) -> {
+ Log.e(TAG, throwable, "Error while executing call removal");
+ return null;
+ });
}
/**
@@ -3631,22 +3790,8 @@
Trace.beginSection("onCallStateChanged");
maybeHandleHandover(call, newState);
+ notifyCallStateChanged(call, oldState, newState);
- // Only broadcast state change for calls that are being tracked.
- if (mCalls.contains(call)) {
- updateCanAddCall();
- updateHasActiveRttCall();
- for (CallsManagerListener listener : mListeners) {
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.beginSection(listener.getClass().toString() +
- " onCallStateChanged");
- }
- listener.onCallStateChanged(call, oldState, newState);
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.endSection();
- }
- }
- }
Trace.endSection();
} else {
Log.i(this, "failed in setting the state to new state");
@@ -3654,6 +3799,24 @@
}
}
+ private void notifyCallStateChanged(Call call, int oldState, int newState) {
+ // Only broadcast state change for calls that are being tracked.
+ if (mCalls.contains(call)) {
+ updateCanAddCall();
+ updateHasActiveRttCall();
+ for (CallsManagerListener listener : mListeners) {
+ if (LogUtils.SYSTRACE_DEBUG) {
+ Trace.beginSection(listener.getClass().toString() +
+ " onCallStateChanged");
+ }
+ listener.onCallStateChanged(call, oldState, newState);
+ if (LogUtils.SYSTRACE_DEBUG) {
+ Trace.endSection();
+ }
+ }
+ }
+ }
+
/**
* Identifies call state transitions for a call which trigger handover events.
* - If this call has a handover to it which just started and this call goes active, treat
@@ -4154,7 +4317,8 @@
return false;
}
- private boolean makeRoomForOutgoingCall(Call call) {
+ @VisibleForTesting
+ public boolean makeRoomForOutgoingCall(Call call) {
// Already room!
if (!hasMaximumLiveCalls(call)) return true;
@@ -4171,6 +4335,13 @@
return true;
}
+ // If the live call is stuck in a connecting state, then we should disconnect it in favor
+ // of the new outgoing call.
+ if (liveCall.getState() == CallState.CONNECTING) {
+ liveCall.disconnect("Force disconnect CONNECTING call.");
+ return true;
+ }
+
if (hasMaximumOutgoingCalls(call)) {
Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
@@ -4691,6 +4862,13 @@
pw.decreaseIndent();
}
+ if (mCallDiagnosticServiceController != null) {
+ pw.println("mCallDiagnosticServiceController:");
+ pw.increaseIndent();
+ mCallDiagnosticServiceController.dump(pw);
+ pw.decreaseIndent();
+ }
+
if (mDefaultDialerCache != null) {
pw.println("mDefaultDialerCache:");
pw.increaseIndent();
@@ -5399,4 +5577,10 @@
public void addToPendingCallsToDisconnect(Call call) {
mPendingCallsToDisconnect.add(call);
}
+
+ @VisibleForTesting
+ public void addConnectionServiceRepositoryCache(ComponentName componentName,
+ UserHandle userHandle, ConnectionServiceWrapper service) {
+ mConnectionServiceRepository.setService(componentName, userHandle, service);
+ }
}
diff --git a/src/com/android/server/telecom/CarModeTracker.java b/src/com/android/server/telecom/CarModeTracker.java
index e64ef5d..737ce5a 100644
--- a/src/com/android/server/telecom/CarModeTracker.java
+++ b/src/com/android/server/telecom/CarModeTracker.java
@@ -30,6 +30,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.PriorityQueue;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -40,30 +41,40 @@
* Data class holding information about apps which have requested to enter car mode.
*/
private class CarModeApp {
- private @IntRange(from = 0) int mPriority;
+ private final boolean mAutomotiveProjection;
+ private final @IntRange(from = 0) int mPriority;
private @NonNull String mPackageName;
+ public CarModeApp(@NonNull String packageName) {
+ this(true, 0, packageName);
+ }
+
public CarModeApp(int priority, @NonNull String packageName) {
+ this(false, priority, packageName);
+ }
+
+ private CarModeApp(boolean automotiveProjection, int priority, @NonNull String packageName) {
+ mAutomotiveProjection = automotiveProjection;
mPriority = priority;
mPackageName = Objects.requireNonNull(packageName);
}
+ public boolean hasSetAutomotiveProjection() {
+ return mAutomotiveProjection;
+ }
+
/**
* The priority at which the app requested to enter car mode.
* Will be the same as the one specified when {@link UiModeManager#enableCarMode(int, int)}
- * was called, or {@link UiModeManager#DEFAULT_PRIORITY} if no priority was specifeid.
+ * was called, or {@link UiModeManager#DEFAULT_PRIORITY} if no priority was specified.
* @return The priority.
*/
public int getPriority() {
return mPriority;
}
- public void setPriority(int priority) {
- mPriority = priority;
- }
-
/**
- * @return The package name of the app which requested to enter car mode.
+ * @return The package name of the app which requested to enter car mode/set projection.
*/
public String getPackageName() {
return mPackageName;
@@ -72,26 +83,24 @@
public void setPackageName(String packageName) {
mPackageName = packageName;
}
- }
- /**
- * Comparator used to maintain the car mode priority queue ordering.
- */
- private class CarModeAppComparator implements Comparator<CarModeApp> {
- @Override
- public int compare(CarModeApp o1, CarModeApp o2) {
- // highest priority takes precedence.
- return Integer.compare(o2.getPriority(), o1.getPriority());
+ public String toString() {
+ return String.format("[%s, %s]",
+ mAutomotiveProjection ? "PROJECTION SET" : mPriority,
+ mPackageName);
}
}
/**
- * Priority list of apps which have entered or exited car mode, ordered with the highest
- * priority app at the top of the queue. Where items have the same priority, they are ordered
- * by insertion time.
+ * Priority list of apps which have entered or exited car mode, ordered first by whether the app
+ * has set automotive projection, and then by highest priority. Where items have the same
+ * priority, order is arbitrary, but we only allow one item in the queue per priority.
*/
private PriorityQueue<CarModeApp> mCarModeApps = new PriorityQueue<>(2,
- new CarModeAppComparator());
+ // Natural ordering of booleans is False, True. Natural ordering of ints is increasing.
+ Comparator.comparing(CarModeApp::hasSetAutomotiveProjection)
+ .thenComparing(CarModeApp::getPriority)
+ .reversed());
private final LocalLog mCarModeChangeLog = new LocalLog(20);
@@ -144,6 +153,47 @@
mCarModeApps.removeIf(c -> c.getPriority() == priority);
}
+ public void handleSetAutomotiveProjection(@NonNull String packageName) {
+ Optional<CarModeApp> projectingApp = mCarModeApps.stream()
+ .filter(CarModeApp::hasSetAutomotiveProjection)
+ .findAny();
+ // No app with automotive projection? Easy peasy, just add it.
+ if (!projectingApp.isPresent()) {
+ Log.i(this, "handleSetAutomotiveProjection: %s", packageName);
+ mCarModeChangeLog.log("setAutomotiveProjection: packageName=" + packageName);
+ mCarModeApps.add(new CarModeApp(packageName));
+ return;
+ }
+ // Otherwise an app already has automotive projection set. Is it the same app?
+ if (packageName.equals(projectingApp.get().getPackageName())) {
+ Log.w(this, "handleSetAutomotiveProjection: %s already the automotive projection app",
+ packageName);
+ return;
+ }
+ // We have a new app for automotive projection. As a shortcut just reuse the same object by
+ // overwriting the package name.
+ Log.i(this, "handleSetAutomotiveProjection: %s replacing %s as automotive projection app",
+ packageName, projectingApp.get().getPackageName());
+ mCarModeChangeLog.log("setAutomotiveProjection: " + packageName + " replaces "
+ + projectingApp.get().getPackageName());
+ projectingApp.get().setPackageName(packageName);
+ }
+
+ public void handleReleaseAutomotiveProjection() {
+ Optional<String> projectingPackage = mCarModeApps.stream()
+ .filter(CarModeApp::hasSetAutomotiveProjection)
+ .map(CarModeApp::getPackageName)
+ .findAny();
+ if (!projectingPackage.isPresent()) {
+ Log.w(this, "handleReleaseAutomotiveProjection: no current automotive projection app");
+ return;
+ }
+ Log.i(this, "handleReleaseAutomotiveProjection: %s", projectingPackage.get());
+ mCarModeChangeLog.log("releaseAutomotiveProjection: packageName="
+ + projectingPackage.get());
+ mCarModeApps.removeIf(CarModeApp::hasSetAutomotiveProjection);
+ }
+
/**
* Force-removes a package from the car mode tracking list, no matter at which priority.
*
@@ -151,19 +201,21 @@
* from the tracking list so they don't cause a leak.
* @param packageName Package name of the app to force-remove
*/
- public void forceExitCarMode(@NonNull String packageName) {
- Optional<CarModeApp> forcedApp = mCarModeApps.stream()
+ public void forceRemove(@NonNull String packageName) {
+ // We must account for the possibility that the app has set both car mode AND projection.
+ List<CarModeApp> forcedApp = mCarModeApps.stream()
.filter(c -> c.getPackageName().equals(packageName))
- .findAny();
- if (forcedApp.isPresent()) {
- String logString = String.format("forceExitCarMode: packageName=%s, was at priority=%s",
- packageName, forcedApp.get().getPriority());
+ .collect(Collectors.toList());
+ if (forcedApp.isEmpty()) {
+ Log.i(this, "Package %s is not tracked.", packageName);
+ return;
+ }
+ for (CarModeApp app : forcedApp) {
+ String logString = "forceRemove: " + app;
Log.i(this, logString);
mCarModeChangeLog.log(logString);
- mCarModeApps.removeIf(c -> c.getPackageName().equals(packageName));
- } else {
- Log.i(this, "Package %s is not tracked as requesting car mode", packageName);
}
+ mCarModeApps.removeIf(c -> c.getPackageName().equals(packageName));
}
/**
@@ -175,7 +227,7 @@
return mCarModeApps
.stream()
.sorted(mCarModeApps.comparator())
- .map(cma -> cma.getPackageName())
+ .map(CarModeApp::getPackageName)
.collect(Collectors.toList());
}
@@ -183,7 +235,7 @@
return mCarModeApps
.stream()
.sorted(mCarModeApps.comparator())
- .map(cma -> "[" + cma.getPriority() + ", " + cma.getPackageName() + "]")
+ .map(CarModeApp::toString)
.collect(Collectors.joining(", "));
}
@@ -216,7 +268,7 @@
pw.increaseIndent();
for (CarModeApp app : mCarModeApps) {
pw.print("[");
- pw.print(app.getPriority());
+ pw.print(app.hasSetAutomotiveProjection() ? "PROJECTION SET" : app.getPriority());
pw.print("] ");
pw.println(app.getPackageName());
}
diff --git a/src/com/android/server/telecom/ConnectionServiceFocusManager.java b/src/com/android/server/telecom/ConnectionServiceFocusManager.java
index fbb23f4..aa0a64f 100644
--- a/src/com/android/server/telecom/ConnectionServiceFocusManager.java
+++ b/src/com/android/server/telecom/ConnectionServiceFocusManager.java
@@ -391,7 +391,7 @@
}
private void handleRequestFocus(FocusRequest focusRequest) {
- Log.d(this, "handleRequestFocus req = %s", focusRequest);
+ Log.i(this, "handleRequestFocus req = %s", focusRequest);
if (mCurrentFocus == null
|| mCurrentFocus.equals(focusRequest.call.getConnectionServiceWrapper())) {
updateConnectionServiceFocus(focusRequest.call.getConnectionServiceWrapper());
diff --git a/src/com/android/server/telecom/ConnectionServiceRepository.java b/src/com/android/server/telecom/ConnectionServiceRepository.java
index d34ea3c..3991ed5 100644
--- a/src/com/android/server/telecom/ConnectionServiceRepository.java
+++ b/src/com/android/server/telecom/ConnectionServiceRepository.java
@@ -79,6 +79,13 @@
return service;
}
+ @VisibleForTesting
+ public void setService(ComponentName componentName, UserHandle userHandle,
+ ConnectionServiceWrapper service) {
+ Pair<ComponentName, UserHandle> cacheKey = Pair.create(componentName, userHandle);
+ mServiceCache.put(cacheKey, service);
+ }
+
/**
* Dumps the state of the {@link ConnectionServiceRepository}.
*
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index ad78cb0..3a4d143 100755
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import android.Manifest;
import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
@@ -30,6 +31,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.telecom.CallAudioState;
+import android.telecom.CallScreeningService;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
import android.telecom.ConnectionService;
@@ -43,6 +45,8 @@
import android.telecom.StatusHints;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
+import android.telephony.CellIdentity;
+import android.telephony.TelephonyManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.IConnectionService;
@@ -350,7 +354,7 @@
logIncoming("removeCall %s", callId);
Call call = mCallIdMapper.getCall(callId);
if (call != null) {
- if (call.isAlive()) {
+ if (call.isAlive() && !call.isDisconnectHandledViaFuture()) {
mCallsManager.markCallAsDisconnected(
call, new DisconnectCause(DisconnectCause.REMOTE));
} else {
@@ -918,6 +922,45 @@
} else {
connectIdToCheck = callId;
}
+
+ // Handle the case where an existing connection was added by Telephony via
+ // a connection manager. The remote connection service API does not include
+ // the ability to specify a parent connection when adding an existing
+ // connection, so we stash the desired parent in the connection extras.
+ if (connectionExtras != null
+ && connectionExtras.containsKey(
+ Connection.EXTRA_ADD_TO_CONFERENCE_ID)
+ && connection.getParentCallId() == null) {
+ String parentId = connectionExtras.getString(
+ Connection.EXTRA_ADD_TO_CONFERENCE_ID);
+ Log.i(ConnectionServiceWrapper.this, "addExistingConnection: remote "
+ + "connection will auto-add to parent %s", parentId);
+ // Replace parcelable connection instance, swapping the new desired
+ // parent in.
+ connection = new ParcelableConnection(
+ connection.getPhoneAccount(),
+ connection.getState(),
+ connection.getConnectionCapabilities(),
+ connection.getConnectionProperties(),
+ connection.getSupportedAudioRoutes(),
+ connection.getHandle(),
+ connection.getHandlePresentation(),
+ connection.getCallerDisplayName(),
+ connection.getCallerDisplayNamePresentation(),
+ connection.getVideoProvider(),
+ connection.getVideoState(),
+ connection.isRingbackRequested(),
+ connection.getIsVoipAudioMode(),
+ connection.getConnectTimeMillis(),
+ connection.getConnectElapsedTimeMillis(),
+ connection.getStatusHints(),
+ connection.getDisconnectCause(),
+ connection.getConferenceableConnectionIds(),
+ connection.getExtras(),
+ parentId,
+ connection.getCallDirection(),
+ connection.getCallerNumberVerificationStatus());
+ }
// Check to see if this Connection has already been added.
Call alreadyAddedConnection = mCallsManager
.getAlreadyAddedConnection(connectIdToCheck);
@@ -1195,6 +1238,24 @@
}
}
+ private CellIdentity getLastKnownCellIdentity() {
+ TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ if (telephonyManager != null) {
+ CellIdentity lastKnownCellIdentity = telephonyManager.getLastKnownCellIdentity();
+ try {
+ mAppOpsManager.noteOp(AppOpsManager.OP_FINE_LOCATION,
+ mContext.getPackageManager().getPackageUid(
+ getComponentName().getPackageName(), 0),
+ getComponentName().getPackageName());
+ } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+ Log.e(this, nameNotFoundException, "could not find the package -- %s",
+ getComponentName().getPackageName());
+ }
+ return lastKnownCellIdentity;
+ }
+ return null;
+ }
+
/**
* Creates a conference for a new outgoing call or attach to an existing incoming call.
*/
@@ -1269,6 +1330,14 @@
@Override
public void onSuccess() {
String callId = mCallIdMapper.getCallId(call);
+ if (callId == null) {
+ Log.w(ConnectionServiceWrapper.this, "Call not present"
+ + " in call id mapper, maybe it was aborted before the bind"
+ + " completed successfully?");
+ response.handleCreateConnectionFailure(
+ new DisconnectCause(DisconnectCause.CANCELED));
+ return;
+ }
mPendingResponses.put(callId, response);
GatewayInfo gatewayInfo = call.getGatewayInfo();
@@ -1306,6 +1375,11 @@
Log.piiHandle(call.getHandle()) + " via:" +
getComponentName().getPackageName());
+ if (call.isEmergencyCall()) {
+ extras.putParcelable(Connection.EXTRA_LAST_KNOWN_CELL_IDENTITY,
+ getLastKnownCellIdentity());
+ }
+
ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
.setAccountHandle(call.getTargetPhoneAccount())
.setAddress(call.getHandle())
@@ -1352,7 +1426,8 @@
* create a connection has been denied or failed.
* @param call The call.
*/
- void createConnectionFailed(final Call call) {
+ @VisibleForTesting
+ public void createConnectionFailed(final Call call) {
Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
@Override
@@ -1863,6 +1938,28 @@
}
}
+ void onCallFilteringCompleted(Call call,
+ Connection.CallFilteringCompletionInfo completionInfo) {
+ final String callId = mCallIdMapper.getCallId(call);
+ if (callId != null && isServiceValid("onCallFilteringCompleted")) {
+ try {
+ logOutgoing("onCallFilteringCompleted %s", completionInfo);
+ int contactsPermission = mContext.getPackageManager()
+ .checkPermission(Manifest.permission.READ_CONTACTS,
+ getComponentName().getPackageName());
+ if (contactsPermission == PackageManager.PERMISSION_GRANTED) {
+ mServiceInterface.onCallFilteringCompleted(callId, completionInfo,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
+ } else {
+ logOutgoing("Skipping call filtering complete message for %s due"
+ + " to lack of READ_CONTACTS", getComponentName().getPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(this, e, "Remote exception calling onCallFilteringCompleted");
+ }
+ }
+ }
+
void onExtrasChanged(Call call, Bundle extras) {
final String callId = mCallIdMapper.getCallId(call);
if (callId != null && isServiceValid("onExtrasChanged")) {
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index 2e67b08..3561211 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -39,6 +39,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
/**
* This class creates connections to place new outgoing calls or to attach to an existing incoming
@@ -386,8 +387,13 @@
mAttemptRecords.clear();
// Phone accounts in profile do not handle emergency call, use phone accounts in
// current user.
+ // ONLY include phone accounts which are NOT self-managed; we will never consider a self
+ // managed phone account for placing an emergency call.
List<PhoneAccount> allAccounts = mPhoneAccountRegistrar
- .getAllPhoneAccountsOfCurrentUser();
+ .getAllPhoneAccountsOfCurrentUser()
+ .stream()
+ .filter(act -> !act.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED))
+ .collect(Collectors.toList());
if (allAccounts.isEmpty() && mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEPHONY)) {
@@ -661,7 +667,7 @@
}
// then by hashcode
- return account1.hashCode() - account2.hashCode();
+ return Integer.compare(account1.hashCode(), account2.hashCode());
});
}
diff --git a/src/com/android/server/telecom/DtmfLocalTonePlayer.java b/src/com/android/server/telecom/DtmfLocalTonePlayer.java
index 304a698..5869008 100644
--- a/src/com/android/server/telecom/DtmfLocalTonePlayer.java
+++ b/src/com/android/server/telecom/DtmfLocalTonePlayer.java
@@ -193,8 +193,9 @@
final Context context = call.getContext();
final boolean areLocalTonesEnabled;
if (context.getResources().getBoolean(R.bool.allow_local_dtmf_tones)) {
- areLocalTonesEnabled = Settings.System.getInt(
- context.getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
+ areLocalTonesEnabled = Settings.System.getIntForUser(
+ context.getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, 1,
+ context.getUserId()) == 1;
} else {
areLocalTonesEnabled = false;
}
diff --git a/src/com/android/server/telecom/FrameworksUtils.java b/src/com/android/server/telecom/FrameworksUtils.java
new file mode 100644
index 0000000..08a19f5
--- /dev/null
+++ b/src/com/android/server/telecom/FrameworksUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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.app.AlertDialog;
+import android.content.Context;
+import android.content.res.Configuration;
+
+/**
+ * This class provides utility functions over framework APIs
+ */
+public class FrameworksUtils {
+ /**
+ * Create a new instance of {@link AlertDialog.Builder}.
+ * @param context reference to a Context
+ * @return an instance of AlertDialog.Builder
+ */
+ public static AlertDialog.Builder makeAlertDialogBuilder(Context context) {
+ boolean isDarkTheme = (context.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+ return new AlertDialog.Builder(context, isDarkTheme
+ ? android.R.style.Theme_DeviceDefault_Dialog_Alert : 0);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index e46d377..d315127 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.os.Process.myUid;
import android.Manifest;
@@ -23,6 +24,7 @@
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
+import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -33,13 +35,17 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.hardware.SensorPrivacyManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.PackageTagsList;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.telecom.CallAudioState;
import android.telecom.ConnectionService;
import android.telecom.InCallService;
@@ -54,6 +60,7 @@
import com.android.internal.annotations.VisibleForTesting;
// TODO: Needed for move to system service: import com.android.internal.R;
import com.android.internal.telecom.IInCallService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.SystemStateHelper.SystemStateListener;
import com.android.server.telecom.ui.NotificationChannelManager;
@@ -75,9 +82,10 @@
* can send updates to the in-call app. This class is created and owned by CallsManager and retains
* a binding to the {@link IInCallService} (implemented by the in-call app).
*/
-public class InCallController extends CallsManagerListenerBase {
- public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;
+public class InCallController extends CallsManagerListenerBase implements
+ AppOpsManager.OnOpActiveChangedListener {
public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName();
+ public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;
public class InCallServiceConnection {
/**
@@ -274,7 +282,16 @@
@Override
public int connect(Call call) {
if (mIsConnected) {
- Log.addEvent(call, LogUtils.Events.INFO, "Already connected, ignoring request.");
+ Log.addEvent(call, LogUtils.Events.INFO, "Already connected, ignoring request: "
+ + mInCallServiceInfo);
+ if (call != null) {
+ // Track the call if we don't already know about it.
+ addCall(call);
+
+ // Notify this new added call
+ sendCallToService(call, mInCallServiceInfo,
+ mInCallServices.get(mInCallServiceInfo));
+ }
return CONNECTION_SUCCEEDED;
}
@@ -289,7 +306,7 @@
Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
intent.setComponent(mInCallServiceInfo.getComponentName());
- if (call != null && !call.isIncoming() && !call.isExternalCall()){
+ if (call != null && !call.isIncoming() && !call.isExternalCall()) {
intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS,
call.getIntentExtras());
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
@@ -300,9 +317,9 @@
mIsConnected = true;
mInCallServiceInfo.setBindingStartTime(mClockProxy.elapsedRealtime());
if (!mContext.bindServiceAsUser(intent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
- UserHandle.CURRENT)) {
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
+ UserHandle.CURRENT)) {
Log.w(this, "Failed to connect.");
mIsConnected = false;
}
@@ -442,15 +459,15 @@
}
mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(call,
- mCallsManager.getCurrentUserHandle());
+ mCallsManager.getCurrentUserHandle());
if (call != null && call.isIncoming()
- && mEmergencyCallHelper.getLastEmergencyCallTimeMillis() > 0) {
- // Add the last emergency call time to the call
- Bundle extras = new Bundle();
- extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
- mEmergencyCallHelper.getLastEmergencyCallTimeMillis());
- call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras);
+ && mEmergencyCallHelper.getLastEmergencyCallTimeMillis() > 0) {
+ // Add the last emergency call time to the call
+ Bundle extras = new Bundle();
+ extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
+ mEmergencyCallHelper.getLastEmergencyCallTimeMillis());
+ call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras);
}
// If we are here, we didn't or could not connect to child. So lets connect ourselves.
@@ -484,6 +501,7 @@
return super.getInfo();
}
}
+
@Override
protected void onDisconnected() {
// Save this here because super.onDisconnected() could force us to explicitly
@@ -547,6 +565,7 @@
/**
* Called when we move to a state where calls are present on the device. Chooses the
* {@link InCallService} to which we should connect.
+ *
* @param isCarMode {@code true} if device is in car mode, {@code false} otherwise.
*/
public synchronized void chooseInitialInCallService(boolean isCarMode) {
@@ -585,6 +604,7 @@
/**
* Changes the active {@link InCallService} to a car mode app. Called whenever the device
* changes to car mode or the currently active car mode app changes.
+ *
* @param packageName The package name of the car mode app.
*/
public synchronized void changeCarModeApp(String packageName) {
@@ -593,7 +613,8 @@
InCallServiceInfo currentConnectionInfo = mCurrentConnection == null ? null
: mCurrentConnection.getInfo();
InCallServiceInfo carModeConnectionInfo =
- getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_CAR_MODE_UI);
+ getInCallServiceComponent(packageName,
+ IN_CALL_SERVICE_TYPE_CAR_MODE_UI, true /* ignoreDisabed */);
if (!Objects.equals(currentConnectionInfo, carModeConnectionInfo)) {
Log.i(this, "changeCarModeApp: " + currentConnectionInfo + " => "
@@ -608,7 +629,7 @@
new InCallServiceBindingConnection(carModeConnectionInfo);
mIsCarMode = true;
} else {
- // Invalid car mode app; don't expect this but should handle it gracefully.
+ // The app is not enabled. Using the default dialer connection instead
mCarModeConnection = null;
mIsCarMode = false;
mCurrentConnection = mDialerConnection;
@@ -622,6 +643,10 @@
}
}
+ public boolean isCarMode() {
+ return mIsCarMode;
+ }
+
@Override
public int connect(Call call) {
if (mIsConnected) {
@@ -878,6 +903,12 @@
public void onRemoteRttRequest(Call call, int requestId) {
notifyRemoteRttRequest(call, requestId);
}
+
+ @Override
+ public void onCallerNumberVerificationStatusChanged(Call call,
+ int callerNumberVerificationStatus) {
+ updateCall(call);
+ }
};
private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
@@ -904,6 +935,10 @@
if (mNonUIInCallServiceConnections != null) {
mNonUIInCallServiceConnections.addConnections(componentsToBind);
}
+
+ // If the current car mode app become enabled from disabled, update
+ // the connection to binding
+ updateCarModeForConnections();
}
}
} finally {
@@ -919,8 +954,18 @@
}
@Override
+ public void onAutomotiveProjectionStateSet(String automotiveProjectionPackage) {
+ InCallController.this.handleSetAutomotiveProjection(automotiveProjectionPackage);
+ }
+
+ @Override
+ public void onAutomotiveProjectionStateReleased() {
+ InCallController.this.handleReleaseAutomotiveProjection();
+ }
+
+ @Override
public void onPackageUninstalled(String packageName) {
- mCarModeTracker.forceExitCarMode(packageName);
+ mCarModeTracker.forceRemove(packageName);
updateCarModeForConnections();
}
};
@@ -932,6 +977,9 @@
private static final int IN_CALL_SERVICE_TYPE_NON_UI = 4;
private static final int IN_CALL_SERVICE_TYPE_COMPANION = 5;
+ private static final int[] LIVE_CALL_STATES = { CallState.ACTIVE, CallState.PULLING,
+ CallState.DISCONNECTING };
+
/** The in-call app implementations, see {@link IInCallService}. */
private final Map<InCallServiceInfo, IInCallService> mInCallServices = new ArrayMap<>();
@@ -939,6 +987,7 @@
private final Context mContext;
private final AppOpsManager mAppOpsManager;
+ private final SensorPrivacyManager mSensorPrivacyManager;
private final TelecomSystem.SyncRoot mLock;
private final CallsManager mCallsManager;
private final SystemStateHelper mSystemStateHelper;
@@ -949,6 +998,7 @@
private CarSwappingInCallServiceConnection mInCallServiceConnection;
private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
private final ClockProxy mClockProxy;
+ private final IBinder mToken = new Binder();
// A set of known non-UI in call services on the device, including those that are disabled.
// We track this so that we can efficiently bind to them when we're notified that a new
@@ -968,16 +1018,33 @@
/**
* {@code true} if InCallController is tracking a managed, not external call which is using the
- * microphone, {@code false} otherwise.
+ * microphone, and is not muted {@code false} otherwise.
*/
private boolean mIsCallUsingMicrophone = false;
+ /**
+ * {@code true} if InCallController is tracking a managed, not external call which is using the
+ * microphone, {@code false} otherwise.
+ */
+ private boolean mIsTrackingManagedAliveCall = false;
+
+ private boolean mIsStartCallDelayScheduled = false;
+
+ /**
+ * A list of call IDs which are currently using the camera.
+ */
+ private ArrayList<String> mCallsUsingCamera = new ArrayList<>();
+
+ private ArraySet<String> mAllCarrierPrivilegedApps = new ArraySet<>();
+ private ArraySet<String> mActiveCarrierPrivilegedApps = new ArraySet<>();
+
public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache,
Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper,
CarModeTracker carModeTracker, ClockProxy clockProxy) {
mContext = context;
mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
mLock = lock;
mCallsManager = callsManager;
mSystemStateHelper = systemStateHelper;
@@ -987,6 +1054,76 @@
mCarModeTracker = carModeTracker;
mSystemStateHelper.addListener(mSystemStateListener);
mClockProxy = clockProxy;
+ restrictPhoneCallOps();
+ }
+
+ private void restrictPhoneCallOps() {
+ PackageTagsList packageRestriction = new PackageTagsList.Builder()
+ .add(mContext.getPackageName())
+ .build();
+ mAppOpsManager.setUserRestrictionForUser(AppOpsManager.OP_PHONE_CALL_MICROPHONE, true,
+ mToken, packageRestriction, UserHandle.USER_ALL);
+ mAppOpsManager.setUserRestrictionForUser(AppOpsManager.OP_PHONE_CALL_CAMERA, true,
+ mToken, packageRestriction, UserHandle.USER_ALL);
+ }
+
+ @Override
+ public void onOpActiveChanged(@androidx.annotation.NonNull String op, int uid,
+ @androidx.annotation.NonNull String packageName, boolean active) {
+ synchronized (mLock) {
+ if (!mAllCarrierPrivilegedApps.contains(packageName)) {
+ return;
+ }
+
+ if (active) {
+ mActiveCarrierPrivilegedApps.add(packageName);
+ } else {
+ mActiveCarrierPrivilegedApps.remove(packageName);
+ }
+ maybeTrackMicrophoneUse(isMuted());
+ }
+ }
+
+ private void updateAllCarrierPrivilegedUsingMic() {
+ mActiveCarrierPrivilegedApps.clear();
+ UserManager userManager = mContext.getSystemService(UserManager.class);
+ PackageManager pkgManager = mContext.getPackageManager();
+ for (String pkg : mAllCarrierPrivilegedApps) {
+ boolean isActive = mActiveCarrierPrivilegedApps.contains(pkg);
+ List<UserHandle> users = userManager.getUserHandles(true);
+ for (UserHandle user : users) {
+ if (isActive) {
+ break;
+ }
+
+ int uid;
+ try {
+ uid = pkgManager.getPackageUidAsUser(pkg, user.getIdentifier());
+ } catch (PackageManager.NameNotFoundException e) {
+ continue;
+ }
+ List<AppOpsManager.PackageOps> pkgOps = mAppOpsManager.getOpsForPackage(
+ uid, pkg, OPSTR_RECORD_AUDIO);
+ for (int j = 0; j < pkgOps.size(); j++) {
+ List<AppOpsManager.OpEntry> opEntries = pkgOps.get(j).getOps();
+ for (int k = 0; k < opEntries.size(); k++) {
+ AppOpsManager.OpEntry entry = opEntries.get(k);
+ if (entry.isRunning()) {
+ mActiveCarrierPrivilegedApps.add(pkg);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void updateAllCarrierPrivileged() {
+ mAllCarrierPrivilegedApps.clear();
+ for (Call call : mCallIdMapper.getCalls()) {
+ mAllCarrierPrivilegedApps.add(call.getConnectionManagerPhoneAccount()
+ .getComponentName().getPackageName());
+ }
}
@Override
@@ -1036,7 +1173,7 @@
true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported(), includeRttCall,
info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
- info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
try {
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
updateCallTracking(call, info, true /* isAdd */);
@@ -1065,11 +1202,16 @@
}
}
}.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
- mContext.getContentResolver()));
+ mContext.getContentResolver()));
}
call.removeListener(mCallListener);
mCallIdMapper.removeCall(call);
+ if (mCallIdMapper.getCalls().isEmpty()) {
+ mActiveCarrierPrivilegedApps.clear();
+ mAppOpsManager.stopWatchingActive(this);
+ }
maybeTrackMicrophoneUse(isMuted());
+ onSetCamera(call, null);
}
@Override
@@ -1103,8 +1245,8 @@
ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported(), includeRttCall,
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
- info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
+ || info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
try {
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
updateCallTracking(call, info, true /* isAdd */);
@@ -1135,9 +1277,9 @@
false /* supportsExternalCalls */,
android.telecom.Call.STATE_DISCONNECTED /* overrideState */,
false /* includeRttCall */,
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
- info.getType() == IN_CALL_SERVICE_TYPE_NON_UI
- );
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
+ || info.getType() == IN_CALL_SERVICE_TYPE_NON_UI
+ );
try {
inCallService.updateCall(
@@ -1221,6 +1363,7 @@
public void onIsVoipAudioModeChanged(Call call) {
Log.d(this, "onIsVoipAudioModeChanged %s", call);
updateCall(call);
+ maybeTrackMicrophoneUse(isMuted());
}
@Override
@@ -1237,18 +1380,35 @@
/**
* Track changes to camera usage for a call.
- * @param call The call.
+ *
+ * @param call The call.
* @param cameraId The id of the camera to use, or {@code null} if camera is off.
*/
@Override
public void onSetCamera(Call call, String cameraId) {
+ if (call == null) {
+ return;
+ }
+
Log.i(this, "onSetCamera callId=%s, cameraId=%s", call.getId(), cameraId);
if (cameraId != null) {
- mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_CAMERA, myUid(),
- mContext.getOpPackageName(), false, null, null);
+ boolean shouldStart = mCallsUsingCamera.isEmpty();
+ if (!mCallsUsingCamera.contains(call.getId())) {
+ mCallsUsingCamera.add(call.getId());
+ }
+
+ if (shouldStart) {
+ mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_CAMERA, myUid(),
+ mContext.getOpPackageName(), false, null, null);
+ mSensorPrivacyManager.showSensorUseDialog(SensorPrivacyManager.Sensors.CAMERA);
+ }
} else {
- mAppOpsManager.finishOp(AppOpsManager.OP_PHONE_CALL_CAMERA, myUid(),
- mContext.getOpPackageName(), null);
+ boolean hadCall = !mCallsUsingCamera.isEmpty();
+ mCallsUsingCamera.remove(call.getId());
+ if (hadCall && mCallsUsingCamera.isEmpty()) {
+ mAppOpsManager.finishOp(AppOpsManager.OP_PHONE_CALL_CAMERA, myUid(),
+ mContext.getOpPackageName(), null);
+ }
}
}
@@ -1281,8 +1441,8 @@
for (IInCallService inCallService : mInCallServices.values()) {
try {
Log.i(this, "notifyConnectionEvent {Call: %s, Event: %s, Extras:[%s]}",
- (call != null ? call.toString() :"null"),
- (event != null ? event : "null") ,
+ (call != null ? call.toString() : "null"),
+ (event != null ? event : "null"),
(extras != null ? extras.toString() : "null"));
inCallService.onConnectionEvent(mCallIdMapper.getCallId(call), event, extras);
} catch (RemoteException ignored) {
@@ -1293,7 +1453,7 @@
private void notifyRttInitiationFailure(Call call, int reason) {
if (!mInCallServices.isEmpty()) {
- mInCallServices.entrySet().stream()
+ mInCallServices.entrySet().stream()
.filter((entry) -> entry.getKey().equals(mInCallServiceConnection.getInfo()))
.forEach((entry) -> {
try {
@@ -1348,7 +1508,7 @@
/**
* Unbinds an existing bound connection to the in-call app.
*/
- private void unbindFromServices() {
+ public void unbindFromServices() {
try {
mContext.unregisterReceiver(mPackageChangedReceiver);
} catch (IllegalArgumentException e) {
@@ -1420,6 +1580,10 @@
} else {
Log.i(this, "bindToServices: current UI doesn't support call; not binding.");
}
+
+ IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
+ packageChangedFilter.addDataScheme("package");
+ mContext.registerReceiver(mPackageChangedReceiver, packageChangedFilter);
}
private void updateNonUiInCallServices() {
@@ -1434,7 +1598,7 @@
if (callCompanionApps != null && !callCompanionApps.isEmpty()) {
for (String pkg : callCompanionApps) {
InCallServiceInfo info = getInCallServiceComponent(pkg,
- IN_CALL_SERVICE_TYPE_COMPANION);
+ IN_CALL_SERVICE_TYPE_COMPANION, true /* ignoreDisabled */);
if (info != null) {
nonUIInCalls.add(new InCallServiceBindingConnection(info));
}
@@ -1449,10 +1613,6 @@
updateNonUiInCallServices();
}
mNonUIInCallServiceConnections.connect(call);
-
- IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
- packageChangedFilter.addDataScheme("package");
- mContext.registerReceiver(mPackageChangedReceiver, packageChangedFilter);
}
private InCallServiceInfo getDefaultDialerComponent() {
@@ -1463,8 +1623,10 @@
InCallServiceInfo defaultDialerComponent =
(systemPackageName != null && systemPackageName.equals(packageName))
- ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI)
- : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI);
+ ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI,
+ true /* ignoreDisabled */)
+ : getInCallServiceComponent(packageName,
+ IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI, true /* ignoreDisabled */);
/* TODO: in Android 12 re-enable this an InCallService is required by the dialer role.
if (packageName != null && defaultDialerComponent == null) {
// The in call service of default phone app is disabled, send notification.
@@ -1476,7 +1638,7 @@
private InCallServiceInfo getCurrentCarModeComponent() {
return getInCallServiceComponent(mCarModeTracker.getCurrentCarModePackage(),
- IN_CALL_SERVICE_TYPE_CAR_MODE_UI);
+ IN_CALL_SERVICE_TYPE_CAR_MODE_UI, true /* ignoreDisabled */);
}
private InCallServiceInfo getInCallServiceComponent(ComponentName componentName, int type) {
@@ -1486,13 +1648,15 @@
} else {
// Last Resort: Try to bind to the ComponentName given directly.
Log.e(this, new Exception(), "Package Manager could not find ComponentName: "
- + componentName +". Trying to bind anyway.");
+ + componentName + ". Trying to bind anyway.");
return new InCallServiceInfo(componentName, false, false, type);
}
}
- private InCallServiceInfo getInCallServiceComponent(String packageName, int type) {
- List<InCallServiceInfo> list = getInCallServiceComponents(packageName, type);
+ private InCallServiceInfo getInCallServiceComponent(String packageName, int type,
+ boolean ignoreDisabled) {
+ List<InCallServiceInfo> list = getInCallServiceComponents(packageName, type,
+ ignoreDisabled);
if (list != null && !list.isEmpty()) {
return list.get(0);
}
@@ -1503,8 +1667,9 @@
return getInCallServiceComponents(null, null, type);
}
- private List<InCallServiceInfo> getInCallServiceComponents(String packageName, int type) {
- return getInCallServiceComponents(packageName, null, type);
+ private List<InCallServiceInfo> getInCallServiceComponents(String packageName, int type,
+ boolean ignoreDisabled) {
+ return getInCallServiceComponents(packageName, null, type, ignoreDisabled);
}
private List<InCallServiceInfo> getInCallServiceComponents(ComponentName componentName,
@@ -1514,6 +1679,12 @@
private List<InCallServiceInfo> getInCallServiceComponents(String packageName,
ComponentName componentName, int requestedType) {
+ return getInCallServiceComponents(packageName, componentName, requestedType,
+ true /* ignoreDisabled */);
+ }
+
+ private List<InCallServiceInfo> getInCallServiceComponents(String packageName,
+ ComponentName componentName, int requestedType, boolean ignoreDisabled) {
List<InCallServiceInfo> retval = new LinkedList<>();
Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
@@ -1525,11 +1696,16 @@
}
PackageManager packageManager = mContext.getPackageManager();
+ Context userContext = mContext.createContextAsUser(mCallsManager.getCurrentUserHandle(),
+ 0 /* flags */);
+ PackageManager userPackageManager = userContext != null ?
+ userContext.getPackageManager() : packageManager;
for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
serviceIntent,
PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
mCallsManager.getCurrentUserHandle().getIdentifier())) {
ServiceInfo serviceInfo = entry.serviceInfo;
+
if (serviceInfo != null) {
boolean isExternalCallsSupported = serviceInfo.metaData != null &&
serviceInfo.metaData.getBoolean(
@@ -1546,13 +1722,16 @@
mKnownNonUiInCallServices.add(foundComponentName);
}
+ boolean isEnabled = isServiceEnabled(foundComponentName,
+ serviceInfo, userPackageManager);
boolean isRequestedType;
if (requestedType == IN_CALL_SERVICE_TYPE_INVALID) {
isRequestedType = true;
} else {
isRequestedType = requestedType == currentType;
}
- if (serviceInfo.enabled && isRequestedType) {
+
+ if ((!ignoreDisabled || isEnabled) && isRequestedType) {
retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported,
isSelfManageCallsSupported, requestedType));
}
@@ -1561,6 +1740,25 @@
return retval;
}
+ private boolean isServiceEnabled(ComponentName componentName,
+ ServiceInfo serviceInfo, PackageManager packageManager) {
+ if (packageManager == null) {
+ return serviceInfo.isEnabled();
+ }
+
+ int componentEnabledState = packageManager.getComponentEnabledSetting(componentName);
+
+ if (componentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ return true;
+ }
+
+ if (componentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+ return serviceInfo.isEnabled();
+ }
+
+ return false;
+ }
+
private boolean shouldUseCarModeUI() {
return mCarModeTracker.isInCarMode();
}
@@ -1687,34 +1885,7 @@
"calls", calls.size(), info.getComponentName());
int numCallsSent = 0;
for (Call call : calls) {
- try {
- if ((call.isSelfManaged() && (!info.isSelfManagedCallsSupported()
- || !call.visibleToInCallService())) ||
- (call.isExternalCall() && !info.isExternalCallsSupported())) {
- continue;
- }
-
- // Only send the RTT call if it's a UI in-call service
- boolean includeRttCall = false;
- if (mInCallServiceConnection != null) {
- includeRttCall = info.equals(mInCallServiceConnection.getInfo());
- }
-
- // Track the call if we don't already know about it.
- addCall(call);
- numCallsSent += 1;
- ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
- call,
- true /* includeVideoProvider */,
- mCallsManager.getPhoneAccountRegistrar(),
- info.isExternalCallsSupported(),
- includeRttCall,
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
- info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
- inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
- updateCallTracking(call, info, true /* isAdd */);
- } catch (RemoteException ignored) {
- }
+ numCallsSent += sendCallToService(call, info, inCallService);
}
try {
inCallService.onCallAudioStateChanged(mCallsManager.getAudioState());
@@ -1722,7 +1893,7 @@
} catch (RemoteException ignored) {
}
// Don't complete the binding future for non-ui incalls
- if (info.getType() != IN_CALL_SERVICE_TYPE_NON_UI) {
+ if (info.getType() != IN_CALL_SERVICE_TYPE_NON_UI && !mBindingFuture.isDone()) {
mBindingFuture.complete(true);
}
@@ -1730,6 +1901,39 @@
return true;
}
+ private int sendCallToService(Call call, InCallServiceInfo info,
+ IInCallService inCallService) {
+ try {
+ if ((call.isSelfManaged() && (!info.isSelfManagedCallsSupported()
+ || !call.visibleToInCallService())) ||
+ (call.isExternalCall() && !info.isExternalCallsSupported())) {
+ return 0;
+ }
+
+ // Only send the RTT call if it's a UI in-call service
+ boolean includeRttCall = false;
+ if (mInCallServiceConnection != null) {
+ includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+ }
+
+ // Track the call if we don't already know about it.
+ addCall(call);
+ ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
+ call,
+ true /* includeVideoProvider */,
+ mCallsManager.getPhoneAccountRegistrar(),
+ info.isExternalCallsSupported(),
+ includeRttCall,
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
+ inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+ updateCallTracking(call, info, true /* isAdd */);
+ return 1;
+ } catch (RemoteException ignored) {
+ }
+ return 0;
+ }
+
/**
* Cleans up an instance of in-call app after the service has been unbound.
*
@@ -1805,10 +2009,18 @@
* @param call The call to add.
*/
private void addCall(Call call) {
+ if (mCallIdMapper.getCalls().size() == 0) {
+ mAppOpsManager.startWatchingActive(new String[] { OPSTR_RECORD_AUDIO },
+ java.lang.Runnable::run, this);
+ updateAllCarrierPrivileged();
+ updateAllCarrierPrivilegedUsingMic();
+ }
+
if (mCallIdMapper.getCallId(call) == null) {
mCallIdMapper.addCall(call);
call.addListener(mCallListener);
}
+
maybeTrackMicrophoneUse(isMuted());
}
@@ -1952,8 +2164,11 @@
* {@code false} otherwise.
*/
private boolean isCarModeInCallService(@NonNull String packageName) {
+ // Disabled InCallService should also be considered as a valid InCallService here so that
+ // it can be added to the CarModeTracker, in case it will be enabled in future.
InCallServiceInfo info =
- getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_CAR_MODE_UI);
+ getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_CAR_MODE_UI,
+ false /* ignoreDisabled */);
return info != null && info.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI;
}
@@ -1976,15 +2191,39 @@
updateCarModeForConnections();
}
+ public void handleSetAutomotiveProjection(@NonNull String packageName) {
+ Log.i(this, "handleSetAutomotiveProjection: packageName=%s", packageName);
+ if (!isCarModeInCallService(packageName)) {
+ Log.i(this, "handleSetAutomotiveProjection: not a valid InCallService: packageName=%s",
+ packageName);
+ return;
+ }
+ mCarModeTracker.handleSetAutomotiveProjection(packageName);
+
+ updateCarModeForConnections();
+ }
+
+ public void handleReleaseAutomotiveProjection() {
+ Log.i(this, "handleReleaseAutomotiveProjection");
+ mCarModeTracker.handleReleaseAutomotiveProjection();
+
+ updateCarModeForConnections();
+ }
+
public void updateCarModeForConnections() {
Log.i(this, "updateCarModeForConnections: car mode apps: %s",
mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
if (mInCallServiceConnection != null) {
if (shouldUseCarModeUI()) {
+ Log.i(this, "updateCarModeForConnections: potentially update car mode app.");
mInCallServiceConnection.changeCarModeApp(
mCarModeTracker.getCurrentCarModePackage());
} else {
- mInCallServiceConnection.disableCarMode();
+ if (mInCallServiceConnection.isCarMode()) {
+ Log.i(this, "updateCarModeForConnections: car mode no longer "
+ + "applicable; disabling");
+ mInCallServiceConnection.disableCarMode();
+ }
}
}
}
@@ -2013,18 +2252,42 @@
Log.i(this, "trackCallingUserInterfaceStopped: %s is no longer calling UX", packageName);
}
+ private void maybeTrackMicrophoneUse(boolean isMuted) {
+ maybeTrackMicrophoneUse(isMuted, false);
+ }
+
/**
* As calls are added, removed and change between external and non-external status, track
* whether the current active calling UX is using the microphone. We assume if there is a
* managed call present and the mic is not muted that the microphone is in use.
*/
- private void maybeTrackMicrophoneUse(boolean isMuted) {
- boolean wasTrackingManagedCall = mIsCallUsingMicrophone;
- mIsCallUsingMicrophone = isTrackingManagedAliveCall() && !isMuted;
- if (wasTrackingManagedCall != mIsCallUsingMicrophone) {
+ private void maybeTrackMicrophoneUse(boolean isMuted, boolean isScheduledDelay) {
+ if (mIsStartCallDelayScheduled && !isScheduledDelay) {
+ return;
+ }
+
+ mIsStartCallDelayScheduled = false;
+ boolean wasUsingMicrophone = mIsCallUsingMicrophone;
+ boolean wasTrackingCall = mIsTrackingManagedAliveCall;
+ mIsTrackingManagedAliveCall = isTrackingManagedAliveCall();
+ if (!wasTrackingCall && mIsTrackingManagedAliveCall) {
+ mIsStartCallDelayScheduled = true;
+ mHandler.postDelayed(new Runnable("ICC.mTMU", mLock) {
+ @Override
+ public void loggedRun() {
+ maybeTrackMicrophoneUse(isMuted(), true);
+ }
+ }.prepare(), mTimeoutsAdapter.getCallStartAppOpDebounceIntervalMillis());
+ return;
+ }
+
+ mIsCallUsingMicrophone = mIsTrackingManagedAliveCall && !isMuted
+ && !isCarrierPrivilegedUsingMicDuringVoipCall();
+ if (wasUsingMicrophone != mIsCallUsingMicrophone) {
if (mIsCallUsingMicrophone) {
mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(),
mContext.getOpPackageName(), false, null, null);
+ mSensorPrivacyManager.showSensorUseDialog(SensorPrivacyManager.Sensors.MICROPHONE);
} else {
mAppOpsManager.finishOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(),
mContext.getOpPackageName(), null);
@@ -2038,8 +2301,13 @@
*/
private boolean isTrackingManagedAliveCall() {
return mCallIdMapper.getCalls().stream().anyMatch(c -> !c.isExternalCall()
- && !c.isSelfManaged() && c.isAlive() && c.getState() != CallState.ON_HOLD
- && c.getState() != CallState.AUDIO_PROCESSING);
+ && !c.isSelfManaged() && c.isAlive() && ArrayUtils.contains(LIVE_CALL_STATES,
+ c.getState()));
+ }
+
+ private boolean isCarrierPrivilegedUsingMicDuringVoipCall() {
+ return !mActiveCarrierPrivilegedApps.isEmpty() &&
+ mCallIdMapper.getCalls().stream().anyMatch(Call::getIsVoipAudioMode);
}
/**
@@ -2053,9 +2321,13 @@
}
private boolean isAppOpsPermittedManageOngoingCalls(int uid, String callingPackage) {
- return PermissionChecker.checkPermissionForPreflight(mContext,
- Manifest.permission.MANAGE_ONGOING_CALLS, PermissionChecker.PID_UNKNOWN, uid,
- callingPackage) == PermissionChecker.PERMISSION_GRANTED;
+ return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(mContext,
+ Manifest.permission.MANAGE_ONGOING_CALLS, PermissionChecker.PID_UNKNOWN,
+ new AttributionSource(mContext.getAttributionSource(),
+ new AttributionSource(uid, callingPackage,
+ /*attributionTag*/ null)), "Checking whether the app has"
+ + " MANAGE_ONGOING_CALLS permission")
+ == PermissionChecker.PERMISSION_GRANTED;
}
private void sendCrashedInCallServiceNotification(String packageName) {
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index 4f0cf8d..524d119 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -162,6 +162,8 @@
public static final int TONE_UNOBTAINABLE_NUMBER = 12;
public static final int TONE_VOICE_PRIVACY = 13;
public static final int TONE_VIDEO_UPGRADE = 14;
+ public static final int TONE_RTT_REQUEST = 15;
+ public static final int TONE_IN_CALL_QUALITY_NOTIFICATION = 16;
private static final int TONE_RESOURCE_ID_UNDEFINED = -1;
@@ -329,12 +331,22 @@
// TODO: fill in.
throw new IllegalStateException("Voice privacy tone NYI.");
case TONE_VIDEO_UPGRADE:
+ case TONE_RTT_REQUEST:
// Similar to the call waiting tone, but does not repeat.
toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
toneVolume = RELATIVE_VOLUME_HIPRI;
toneLengthMillis = 4000;
mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
break;
+ case TONE_IN_CALL_QUALITY_NOTIFICATION:
+ // Don't use tone generator
+ toneType = ToneGenerator.TONE_UNKNOWN;
+ toneVolume = RELATIVE_VOLUME_UNDEFINED;
+ toneLengthMillis = 0;
+
+ // Use a tone resource file for a more rich, full-bodied tone experience.
+ mediaResourceId = R.raw.InCallQualityNotification;
+ break;
default:
throw new IllegalStateException("Bad toneId: " + mToneId);
}
@@ -427,7 +439,7 @@
@Override
public void onCompletion(MediaPlayer mp) {
Log.i(this, "playMediaTone: toneResourceId=%d completed.", toneResourceId);
- synchronized (this) {
+ synchronized (InCallTonePlayer.this) {
mState = STATE_OFF;
}
mToneMediaPlayer.release();
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index e4a414b..f53f239 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -138,6 +138,7 @@
public static final String REMOVE_CHILD = "REMOVE_CHILD";
public static final String SET_PARENT = "SET_PARENT";
public static final String CONF_STATE_CHANGED = "CONF_STATE_CHANGED";
+ public static final String CONF_CALLS_CHANGED = "CONF_CALLS_CHANGED";
public static final String CALL_DIRECTION_CHANGED = "CALL_DIRECTION_CHANGED";
public static final String MUTE = "MUTE";
public static final String UNMUTE = "UNMUTE";
@@ -196,6 +197,12 @@
public static final String REDIRECTION_USER_CONFIRMATION = "REDIRECTION_USER_CONFIRMATION";
public static final String REDIRECTION_USER_CONFIRMED = "REDIRECTION_USER_CONFIRMED";
public static final String REDIRECTION_USER_CANCELLED = "REDIRECTION_USER_CANCELLED";
+ public static final String BT_QUALITY_REPORT = "BT_QUALITY_REPORT";
+ public static final String SET_DISCONNECTED_ORIG = "SET_DISCONNECTED_ORIG";
+ public static final String OVERRIDE_DISCONNECT_MESSAGE = "OVERRIDE_DISCONNECT_MSG";
+ public static final String CALL_DIAGNOSTIC_SERVICE_TIMEOUT =
+ "CALL_DIAGNOSTIC_SERVICE_TIMEOUT";
+ public static final String VERSTAT_CHANGED = "VERSTAT_CHANGED";
public static class Timings {
public static final String ACCEPT_TIMING = "accept";
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index a5291e7..0becaef 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -27,6 +27,7 @@
import android.telecom.ParcelableCall;
import android.telecom.ParcelableRttCall;
import android.telecom.TelecomManager;
+import android.telephony.ims.ImsCallProfile;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -61,6 +62,7 @@
static {
RESTRICTED_CALL_SCREENING_EXTRA_KEYS = new ArrayList<>();
RESTRICTED_CALL_SCREENING_EXTRA_KEYS.add(android.telecom.Connection.EXTRA_SIP_INVITE);
+ RESTRICTED_CALL_SCREENING_EXTRA_KEYS.add(ImsCallProfile.EXTRA_IS_BUSINESS_CALL);
}
public static class Converter {
@@ -507,7 +509,11 @@
android.telecom.Call.Details.CAPABILITY_TRANSFER,
Connection.CAPABILITY_TRANSFER_CONSULTATIVE,
- android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE
+ android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE,
+
+ Connection.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT,
+ android.telecom.Call.Details.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT
+
};
private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
@@ -554,7 +560,10 @@
android.telecom.Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
Connection.PROPERTY_IS_ADHOC_CONFERENCE,
- android.telecom.Call.Details.PROPERTY_IS_ADHOC_CONFERENCE
+ android.telecom.Call.Details.PROPERTY_IS_ADHOC_CONFERENCE,
+
+ Connection.PROPERTY_CROSS_SIM,
+ android.telecom.Call.Details.PROPERTY_CROSS_SIM
};
private static int convertConnectionToCallProperties(int connectionProperties) {
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 9a4f7df..bce6e43 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -1226,6 +1226,14 @@
= mState.defaultOutgoingAccountHandles.get(Process.myUserHandle());
pw.println("defaultOutgoing: " + (defaultPhoneAccountHandle == null ? "none" :
defaultPhoneAccountHandle.phoneAccountHandle));
+ PhoneAccountHandle defaultOutgoing =
+ getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL, mCurrentUserHandle);
+ pw.print("outgoingPhoneAccountForTelScheme: ");
+ if (defaultOutgoing == null) {
+ pw.println("none");
+ } else {
+ pw.println(defaultOutgoing);
+ }
pw.println("simCallManager: " + getSimCallManager(mCurrentUserHandle));
pw.println("phoneAccounts:");
pw.increaseIndent();
@@ -1993,8 +2001,8 @@
* @return {@code True} if SIP should be used for all calls.
*/
private boolean useSipForPstnCalls(Context context) {
- String option = Settings.System.getString(context.getContentResolver(),
- Settings.System.SIP_CALL_OPTIONS);
+ String option = Settings.System.getStringForUser(context.getContentResolver(),
+ Settings.System.SIP_CALL_OPTIONS, context.getUserId());
option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY;
return option.equals(Settings.System.SIP_ALWAYS);
}
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index f02f7e8..490db85 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -130,10 +130,17 @@
TelephonyManager tm = mCallsManager.getContext().getSystemService(TelephonyManager.class);
String strippedNumber =
PhoneNumberUtils.stripSeparators(call.getHandle().getSchemeSpecificPart());
- Optional<EmergencyNumber> emergencyNumber = tm.getEmergencyNumberList().values().stream()
- .flatMap(List::stream)
- .filter(numberObj -> Objects.equals(numberObj.getNumber(), strippedNumber))
- .findFirst();
+ Optional<EmergencyNumber> emergencyNumber;
+ try {
+ emergencyNumber = tm.getEmergencyNumberList().values().stream()
+ .flatMap(List::stream)
+ .filter(numberObj -> Objects.equals(numberObj.getNumber(), strippedNumber))
+ .findFirst();
+ } catch (IllegalStateException ie) {
+ emergencyNumber = Optional.empty();
+ } catch (RuntimeException r) {
+ emergencyNumber = Optional.empty();
+ }
int subscriptionId = tm.getSubscriptionId(call.getTargetPhoneAccount());
SubscriptionManager subscriptionManager =
diff --git a/src/com/android/server/telecom/RespondViaSmsManager.java b/src/com/android/server/telecom/RespondViaSmsManager.java
index 00d94f0..23ccc1c 100644
--- a/src/com/android/server/telecom/RespondViaSmsManager.java
+++ b/src/com/android/server/telecom/RespondViaSmsManager.java
@@ -204,7 +204,7 @@
for (int i = 0; i < messageParts.size(); i++) {
Intent intent = new Intent(ACTION_MESSAGE_SENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, i, intent,
- PendingIntent.FLAG_ONE_SHOT);
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
sentIntents.add(pendingIntent);
}
MessageSentReceiver receiver = new MessageSentReceiver(
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index a769a94..91276de 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -20,26 +20,27 @@
import android.app.NotificationManager;
import android.app.Person;
import android.content.Context;
-import android.os.VibrationEffect;
-import android.telecom.Log;
-import android.telecom.TelecomManager;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.VolumeShaper;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.telecom.Log;
+import android.telecom.TelecomManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.telecom.LogUtils.EventTimer;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
-import java.util.stream.Collectors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Controls the ringtone player.
@@ -114,6 +115,8 @@
private static final int REPEAT_SIMPLE_VIBRATION_AT = 1;
+ private static final long RINGER_ATTRIBUTES_TIMEOUT = 5000; // 5 seconds
+
private static final float EPSILON = 1e-6f;
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
@@ -147,6 +150,7 @@
private InCallTonePlayer mCallWaitingPlayer;
private RingtoneFactory mRingtoneFactory;
+ private AudioManager mAudioManager;
/**
* Call objects that are ringing, vibrating or call-waiting. These are used only for logging
@@ -161,6 +165,8 @@
*/
private boolean mIsVibrating = false;
+ private Handler mHandler = null;
+
/** Initializes the Ringer. */
@VisibleForTesting
public Ringer(
@@ -183,6 +189,7 @@
mRingtoneFactory = ringtoneFactory;
mInCallController = inCallController;
mVibrationEffectProxy = vibrationEffectProxy;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) {
mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN,
@@ -216,58 +223,39 @@
return false;
}
- AudioManager audioManager =
- (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- LogUtils.EventTimer timer = new EventTimer();
- boolean isVolumeOverZero = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0;
- timer.record("isVolumeOverZero");
- boolean shouldRingForContact = shouldRingForContact(foregroundCall.getContactUri());
- timer.record("shouldRingForContact");
- boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(foregroundCall) == null);
- timer.record("getRingtone");
- boolean isSelfManaged = foregroundCall.isSelfManaged();
- timer.record("isSelfManaged");
- boolean isSilentRingingRequested = foregroundCall.isSilentRingingRequested();
- timer.record("isSilentRingRequested");
+ // Use completable future to establish a timeout, not intent to make these work outside the
+ // main thread asynchronously
+ // TODO: moving these RingerAttributes calculation out of Telecom lock to avoid blocking.
+ CompletableFuture<RingerAttributes> ringerAttributesFuture = CompletableFuture
+ .supplyAsync(() -> getRingerAttributes(foregroundCall, isHfpDeviceAttached),
+ new LoggedHandlerExecutor(getHandler(), "R.sR", null));
- boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent;
- timer.record("isRingerAudible");
- boolean hasExternalRinger = hasExternalRinger(foregroundCall);
- timer.record("hasExternalRinger");
- // Don't do call waiting operations or vibration unless these are false.
- boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext);
- timer.record("isTheaterModeOn");
- boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging();
- timer.record("letDialerHandleRinging");
+ RingerAttributes attributes = null;
+ try {
+ attributes = ringerAttributesFuture.get(
+ RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException | InterruptedException | TimeoutException e) {
+ // Keep attributs as null
+ Log.i(this, "getAttributes error: " + e);
+ }
- Log.i(this, "startRinging timings: " + timer);
- boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged ||
- hasExternalRinger || isSilentRingingRequested;
+ if (attributes == null) {
+ Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "RingerAttributes error");
+ return false;
+ }
- // Acquire audio focus under any of the following conditions:
- // 1. Should ring for contact and there's an HFP device attached
- // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone
- // present.
- // 3. The call is self-managed.
- boolean shouldAcquireAudioFocus =
- isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged;
-
- if (endEarly) {
- if (letDialerHandleRinging) {
+ if (attributes.isEndEarly()) {
+ if (attributes.letDialerHandleRinging()) {
Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Dialer handles");
}
- if (isSilentRingingRequested) {
+ if (attributes.isSilentRingingRequested()) {
Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Silent ringing "
+ "requested");
}
- Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " +
- "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s",
- isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger,
- isSilentRingingRequested);
if (mBlockOnRingingFuture != null) {
mBlockOnRingingFuture.complete(null);
}
- return shouldAcquireAudioFocus;
+ return attributes.shouldAcquireAudioFocus();
}
stopCallWaiting();
@@ -276,7 +264,7 @@
CompletableFuture<Boolean> hapticsFuture = null;
// Determine if the settings and DND mode indicate that the vibrator can be used right now.
boolean isVibratorEnabled = isVibratorEnabled(mContext, foregroundCall);
- if (isRingerAudible) {
+ if (attributes.isRingerAudible()) {
mRingingCall = foregroundCall;
Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER);
// Because we wait until a contact info query to complete before processing a
@@ -309,15 +297,14 @@
effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
}
} else {
- String reason = String.format(
- "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s",
- isVolumeOverZero, shouldRingForContact, isRingtonePresent);
- Log.i(this, "startRinging: skipping because ringer would not be audible. " + reason);
- Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + reason);
+ Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: "
+ + attributes.getInaudibleReason());
effect = mDefaultVibrationEffect;
}
if (hapticsFuture != null) {
+ final boolean shouldRingForContact = attributes.shouldRingForContact();
+ final boolean isRingerAudible = attributes.isRingerAudible();
mVibrateFuture = hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> {
if (!isUsingAudioCoupledHaptics || !mIsHapticPlaybackSupportedByDevice) {
Log.i(this, "startRinging: fileHasHaptics=%b, hapticsSupported=%b",
@@ -342,11 +329,11 @@
mBlockOnRingingFuture.complete(null);
}
Log.w(this, "startRinging: No haptics future; fallback to default behavior");
- maybeStartVibration(foregroundCall, shouldRingForContact, effect, isVibratorEnabled,
- isRingerAudible);
+ maybeStartVibration(foregroundCall, attributes.shouldRingForContact(), effect,
+ isVibratorEnabled, attributes.isRingerAudible());
}
- return shouldAcquireAudioFocus;
+ return attributes.shouldAcquireAudioFocus();
}
private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact,
@@ -517,4 +504,75 @@
return mSystemSettingsUtil.canVibrateWhenRinging(context)
|| mSystemSettingsUtil.applyRampingRinger(context);
}
+
+ private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) {
+ RingerAttributes.Builder builder = new RingerAttributes.Builder();
+
+ LogUtils.EventTimer timer = new EventTimer();
+
+ boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0;
+ timer.record("isVolumeOverZero");
+ boolean shouldRingForContact = shouldRingForContact(call.getHandle());
+ timer.record("shouldRingForContact");
+ boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(call) == null);
+ timer.record("getRingtone");
+ boolean isSelfManaged = call.isSelfManaged();
+ timer.record("isSelfManaged");
+ boolean isSilentRingingRequested = call.isSilentRingingRequested();
+ timer.record("isSilentRingRequested");
+
+ boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent;
+ timer.record("isRingerAudible");
+ String inaudibleReason = "";
+ if (!isRingerAudible) {
+ inaudibleReason = String.format(
+ "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s",
+ isVolumeOverZero, shouldRingForContact, isRingtonePresent);
+ }
+
+ boolean hasExternalRinger = hasExternalRinger(call);
+ timer.record("hasExternalRinger");
+ // Don't do call waiting operations or vibration unless these are false.
+ boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext);
+ timer.record("isTheaterModeOn");
+ boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging();
+ timer.record("letDialerHandleRinging");
+
+ Log.i(this, "startRinging timings: " + timer);
+ boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged ||
+ hasExternalRinger || isSilentRingingRequested;
+
+ if (endEarly) {
+ Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " +
+ "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s",
+ isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger,
+ isSilentRingingRequested);
+ }
+
+ // Acquire audio focus under any of the following conditions:
+ // 1. Should ring for contact and there's an HFP device attached
+ // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone
+ // present.
+ // 3. The call is self-managed.
+ boolean shouldAcquireAudioFocus =
+ isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged;
+
+ return builder.setEndEarly(endEarly)
+ .setLetDialerHandleRinging(letDialerHandleRinging)
+ .setAcquireAudioFocus(shouldAcquireAudioFocus)
+ .setRingerAudible(isRingerAudible)
+ .setInaudibleReason(inaudibleReason)
+ .setShouldRingForContact(shouldRingForContact)
+ .setSilentRingingRequested(isSilentRingingRequested)
+ .build();
+ }
+
+ private Handler getHandler() {
+ if (mHandler == null) {
+ HandlerThread handlerThread = new HandlerThread("Ringer");
+ handlerThread.start();
+ mHandler = handlerThread.getThreadHandler();
+ }
+ return mHandler;
+ }
}
diff --git a/src/com/android/server/telecom/RingerAttributes.java b/src/com/android/server/telecom/RingerAttributes.java
new file mode 100644
index 0000000..840d815
--- /dev/null
+++ b/src/com/android/server/telecom/RingerAttributes.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 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;
+
+public class RingerAttributes {
+ public static class Builder {
+ private boolean mEndEarly;
+ private boolean mLetDialerHandleRinging;
+ private boolean mAcquireAudioFocus;
+ private boolean mRingerAudible;
+ private String mInaudibleReason;
+ private boolean mShouldRingForContact;
+ private boolean mSilentRingingRequested;
+
+ public RingerAttributes.Builder setEndEarly(boolean endEarly) {
+ mEndEarly = endEarly;
+ return this;
+ }
+
+ public RingerAttributes.Builder setLetDialerHandleRinging(boolean letDialerHandleRinging) {
+ mLetDialerHandleRinging = letDialerHandleRinging;
+ return this;
+ }
+
+ public RingerAttributes.Builder setAcquireAudioFocus(boolean acquireAudioFocus) {
+ mAcquireAudioFocus = acquireAudioFocus;
+ return this;
+ }
+
+ public RingerAttributes.Builder setRingerAudible(boolean ringerAudible) {
+ mRingerAudible = ringerAudible;
+ return this;
+ }
+
+ public RingerAttributes.Builder setInaudibleReason(String inaudibleReason) {
+ mInaudibleReason = inaudibleReason;
+ return this;
+ }
+
+ public RingerAttributes.Builder setShouldRingForContact(boolean shouldRingForContact) {
+ mShouldRingForContact = shouldRingForContact;
+ return this;
+ }
+
+ public RingerAttributes.Builder setSilentRingingRequested(boolean silentRingingRequested) {
+ mSilentRingingRequested = silentRingingRequested;
+ return this;
+ }
+
+ public RingerAttributes build() {
+ return new RingerAttributes(mEndEarly, mLetDialerHandleRinging, mAcquireAudioFocus,
+ mRingerAudible, mInaudibleReason, mShouldRingForContact,
+ mSilentRingingRequested);
+ }
+ }
+
+ private boolean mEndEarly;
+ private boolean mLetDialerHandleRinging;
+ private boolean mAcquireAudioFocus;
+ private boolean mRingerAudible;
+ private String mInaudibleReason;
+ private boolean mShouldRingForContact;
+ private boolean mSilentRingingRequested;
+
+ private RingerAttributes(boolean endEarly, boolean letDialerHandleRinging,
+ boolean acquireAudioFocus, boolean ringerAudible, String inaudibleReason,
+ boolean shouldRingForContact, boolean silentRingingRequested) {
+ mEndEarly = endEarly;
+ mLetDialerHandleRinging = letDialerHandleRinging;
+ mAcquireAudioFocus = acquireAudioFocus;
+ mRingerAudible = ringerAudible;
+ mInaudibleReason = inaudibleReason;
+ mShouldRingForContact = shouldRingForContact;
+ mSilentRingingRequested = silentRingingRequested;
+ }
+
+ public boolean isEndEarly() {
+ return mEndEarly;
+ }
+
+ public boolean letDialerHandleRinging() {
+ return mLetDialerHandleRinging;
+ }
+
+ public boolean shouldAcquireAudioFocus() {
+ return mAcquireAudioFocus;
+ }
+
+ public boolean isRingerAudible() {
+ return mRingerAudible;
+ }
+
+ public String getInaudibleReason() {
+ return mInaudibleReason;
+ }
+
+ public boolean shouldRingForContact() {
+ return mShouldRingForContact;
+ }
+
+ public boolean isSilentRingingRequested() {
+ return mSilentRingingRequested;
+ }
+}
diff --git a/src/com/android/server/telecom/RingtoneFactory.java b/src/com/android/server/telecom/RingtoneFactory.java
index d3d2d0e..6a121f7 100644
--- a/src/com/android/server/telecom/RingtoneFactory.java
+++ b/src/com/android/server/telecom/RingtoneFactory.java
@@ -75,7 +75,12 @@
if(ringtoneUri != null && userContext != null) {
// Ringtone URI is explicitly specified. First, try to create a Ringtone with that.
- ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri, volumeShaperConfig);
+ try {
+ ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri,
+ volumeShaperConfig);
+ } catch (NullPointerException npe) {
+ Log.e(this, npe, "getRingtone: NPE while getting ringtone.");
+ }
}
if(ringtone == null) {
// Contact didn't specify ringtone or custom Ringtone creation failed. Get default
@@ -85,14 +90,24 @@
if (UserManager.get(contextToUse).isUserUnlocked(contextToUse.getUserId())) {
defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(contextToUse,
RingtoneManager.TYPE_RINGTONE);
+ if (defaultRingtoneUri == null) {
+ Log.i(this, "getRingtone: defaultRingtoneUri for user is null.");
+ }
} else {
defaultRingtoneUri = Settings.System.DEFAULT_RINGTONE_URI;
+ if (defaultRingtoneUri == null) {
+ Log.i(this, "getRingtone: Settings.System.DEFAULT_RINGTONE_URI is null.");
+ }
}
if (defaultRingtoneUri == null) {
return null;
}
- ringtone = RingtoneManager.getRingtone(
- contextToUse, defaultRingtoneUri, volumeShaperConfig);
+ try {
+ ringtone = RingtoneManager.getRingtone(
+ contextToUse, defaultRingtoneUri, volumeShaperConfig);
+ } catch (NullPointerException npe) {
+ Log.e(this, npe, "getRingtone: NPE while getting ringtone.");
+ }
}
if (ringtone != null) {
ringtone.setAudioAttributes(new AudioAttributes.Builder()
diff --git a/src/com/android/server/telecom/SystemSettingsUtil.java b/src/com/android/server/telecom/SystemSettingsUtil.java
index f104f27..7baae05 100644
--- a/src/com/android/server/telecom/SystemSettingsUtil.java
+++ b/src/com/android/server/telecom/SystemSettingsUtil.java
@@ -40,18 +40,19 @@
}
public boolean canVibrateWhenRinging(Context context) {
- return Settings.System.getInt(context.getContentResolver(),
- Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.VIBRATE_WHEN_RINGING, 0, context.getUserId()) != 0;
}
public boolean isEnhancedCallBlockingEnabled(Context context) {
- return Settings.System.getInt(context.getContentResolver(),
- Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, 0) != 0;
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, 0, context.getUserId()) != 0;
}
public boolean setEnhancedCallBlockingEnabled(Context context, boolean enabled) {
- return Settings.System.putInt(context.getContentResolver(),
- Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, enabled ? 1 : 0);
+ return Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, enabled ? 1 : 0,
+ context.getUserId());
}
public boolean applyRampingRinger(Context context) {
diff --git a/src/com/android/server/telecom/SystemStateHelper.java b/src/com/android/server/telecom/SystemStateHelper.java
index 3be3d5e..dd978c2 100644
--- a/src/com/android/server/telecom/SystemStateHelper.java
+++ b/src/com/android/server/telecom/SystemStateHelper.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import android.annotation.NonNull;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -38,7 +39,7 @@
/**
* Provides various system states to the rest of the telecom codebase.
*/
-public class SystemStateHelper {
+public class SystemStateHelper implements UiModeManager.OnProjectionStateChangedListener {
public interface SystemStateListener {
/**
* Listener method to inform interested parties when a package name requests to enter or
@@ -51,6 +52,19 @@
void onCarModeChanged(int priority, String packageName, boolean isCarMode);
/**
+ * Listener method to inform interested parties when a package has set automotive projection
+ * state.
+ * @param automotiveProjectionPackage the package that set automotive projection.
+ */
+ void onAutomotiveProjectionStateSet(String automotiveProjectionPackage);
+
+ /**
+ * Listener method to inform interested parties when automotive projection state has been
+ * cleared.
+ */
+ void onAutomotiveProjectionStateReleased();
+
+ /**
* Notifies when a package has been uninstalled.
* @param packageName the package name of the uninstalled package
*/
@@ -61,37 +75,41 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- Log.startSession("SSP.oR");
+ Log.startSession("SSH.oR");
try {
- String action = intent.getAction();
- if (UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED.equals(action)) {
- int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
- UiModeManager.DEFAULT_PRIORITY);
- String callingPackage = intent.getStringExtra(
- UiModeManager.EXTRA_CALLING_PACKAGE);
- Log.i(SystemStateHelper.this, "ENTER_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
- priority, callingPackage);
- onEnterCarMode(priority, callingPackage);
- } else if (UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED.equals(action)) {
- int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
- UiModeManager.DEFAULT_PRIORITY);
- String callingPackage = intent.getStringExtra(
- UiModeManager.EXTRA_CALLING_PACKAGE);
- Log.i(SystemStateHelper.this, "EXIT_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
- priority, callingPackage);
- onExitCarMode(priority, callingPackage);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- Uri data = intent.getData();
- if (data == null) {
+ synchronized (mLock) {
+ String action = intent.getAction();
+ if (UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED.equals(action)) {
+ int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
+ UiModeManager.DEFAULT_PRIORITY);
+ String callingPackage = intent.getStringExtra(
+ UiModeManager.EXTRA_CALLING_PACKAGE);
+ Log.i(SystemStateHelper.this,
+ "ENTER_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
+ priority, callingPackage);
+ onEnterCarMode(priority, callingPackage);
+ } else if (UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED.equals(action)) {
+ int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
+ UiModeManager.DEFAULT_PRIORITY);
+ String callingPackage = intent.getStringExtra(
+ UiModeManager.EXTRA_CALLING_PACKAGE);
+ Log.i(SystemStateHelper.this,
+ "EXIT_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
+ priority, callingPackage);
+ onExitCarMode(priority, callingPackage);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ Uri data = intent.getData();
+ if (data == null) {
+ Log.w(SystemStateHelper.this,
+ "Got null data for package removed, ignoring");
+ return;
+ }
+ mListeners.forEach(
+ l -> l.onPackageUninstalled(data.getEncodedSchemeSpecificPart()));
+ } else {
Log.w(SystemStateHelper.this,
- "Got null data for package removed, ignoring");
- return;
+ "Unexpected intent received: %s", intent.getAction());
}
- mListeners.forEach(
- l -> l.onPackageUninstalled(data.getEncodedSchemeSpecificPart()));
- } else {
- Log.w(SystemStateHelper.this,
- "Unexpected intent received: %s", intent.getAction());
}
} finally {
Log.endSession();
@@ -99,11 +117,31 @@
}
};
- private Set<SystemStateListener> mListeners = new CopyOnWriteArraySet<>();
- private boolean mIsCarMode;
+ @Override
+ public void onProjectionStateChanged(int activeProjectionTypes,
+ @NonNull Set<String> projectingPackages) {
+ Log.startSession("SSH.oPSC");
+ try {
+ synchronized (mLock) {
+ if (projectingPackages.isEmpty()) {
+ onReleaseAutomotiveProjection();
+ } else {
+ onSetAutomotiveProjection(projectingPackages.iterator().next());
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
- public SystemStateHelper(Context context) {
+ }
+
+ private Set<SystemStateListener> mListeners = new CopyOnWriteArraySet<>();
+ private boolean mIsCarModeOrProjectionActive;
+ private final TelecomSystem.SyncRoot mLock;
+
+ public SystemStateHelper(Context context, TelecomSystem.SyncRoot lock) {
mContext = context;
+ mLock = lock;
IntentFilter intentFilter1 = new IntentFilter(
UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
@@ -116,7 +154,9 @@
Log.i(this, "Registering broadcast receiver: %s", intentFilter1);
Log.i(this, "Registering broadcast receiver: %s", intentFilter2);
- mIsCarMode = getSystemCarMode();
+ mContext.getSystemService(UiModeManager.class).addOnProjectionStateChangedListener(
+ UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, mContext.getMainExecutor(), this);
+ mIsCarModeOrProjectionActive = getSystemCarModeOrProjectionState();
}
public void addListener(SystemStateListener listener) {
@@ -129,8 +169,8 @@
return mListeners.remove(listener);
}
- public boolean isCarMode() {
- return mIsCarMode;
+ public boolean isCarModeOrProjectionActive() {
+ return mIsCarModeOrProjectionActive;
}
public boolean isDeviceAtEar() {
@@ -215,7 +255,7 @@
private void onEnterCarMode(int priority, String packageName) {
Log.i(this, "Entering carmode");
- mIsCarMode = getSystemCarMode();
+ mIsCarModeOrProjectionActive = getSystemCarModeOrProjectionState();
for (SystemStateListener listener : mListeners) {
listener.onCarModeChanged(priority, packageName, true /* isCarMode */);
}
@@ -223,25 +263,44 @@
private void onExitCarMode(int priority, String packageName) {
Log.i(this, "Exiting carmode");
- mIsCarMode = getSystemCarMode();
+ mIsCarModeOrProjectionActive = getSystemCarModeOrProjectionState();
for (SystemStateListener listener : mListeners) {
listener.onCarModeChanged(priority, packageName, false /* isCarMode */);
}
}
- /**
- * Checks the system for the current car mode.
- *
- * @return True if in car mode, false otherwise.
- */
- private boolean getSystemCarMode() {
- UiModeManager uiModeManager =
- (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
-
- if (uiModeManager != null) {
- return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR;
+ private void onSetAutomotiveProjection(String packageName) {
+ Log.i(this, "Automotive projection set.");
+ mIsCarModeOrProjectionActive = getSystemCarModeOrProjectionState();
+ for (SystemStateListener listener : mListeners) {
+ listener.onAutomotiveProjectionStateSet(packageName);
}
+ }
+
+ private void onReleaseAutomotiveProjection() {
+ Log.i(this, "Automotive projection released.");
+ mIsCarModeOrProjectionActive = getSystemCarModeOrProjectionState();
+ for (SystemStateListener listener : mListeners) {
+ listener.onAutomotiveProjectionStateReleased();
+ }
+ }
+
+ /**
+ * Checks the system for the current car projection state.
+ *
+ * @return True if projection is active, false otherwise.
+ */
+ private boolean getSystemCarModeOrProjectionState() {
+ UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
+
+ if (uiModeManager != null) {
+ return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR
+ || (uiModeManager.getActiveProjectionTypes()
+ & UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) != 0;
+ }
+
+ Log.w(this, "Got null UiModeManager, returning false.");
return false;
}
}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 3481558..8d6e324 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -30,6 +30,9 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.app.UiModeManager;
+import android.app.compat.CompatChanges;
+import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -58,7 +61,6 @@
import android.util.EventLog;
import com.android.internal.telecom.ITelecomService;
-import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.settings.BlockedNumbersActivity;
@@ -115,7 +117,7 @@
public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme,
String callingPackage, String callingFeatureId) {
try {
- Log.startSession("TSI.gDOPA");
+ Log.startSession("TSI.gDOPA", Log.getPackageAbbreviation(callingPackage));
synchronized (mLock) {
PhoneAccountHandle phoneAccountHandle = null;
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
@@ -147,7 +149,7 @@
public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(String callingPackage) {
synchronized (mLock) {
try {
- Log.startSession("TSI.gUSOPA");
+ Log.startSession("TSI.gUSOPA", Log.getPackageAbbreviation(callingPackage));
if (!isDialerOrPrivileged(callingPackage, "getDefaultOutgoingPhoneAccount")) {
throw new SecurityException("Only the default dialer, or caller with "
+ "READ_PRIVILEGED_PHONE_STATE can call this method.");
@@ -191,7 +193,7 @@
public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
boolean includeDisabledAccounts, String callingPackage, String callingFeatureId) {
try {
- Log.startSession("TSI.gCCPA");
+ Log.startSession("TSI.gCCPA", Log.getPackageAbbreviation(callingPackage));
if (includeDisabledAccounts &&
!canReadPrivilegedPhoneState(
callingPackage, "getCallCapablePhoneAccounts")) {
@@ -223,7 +225,7 @@
public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage,
String callingFeatureId) {
try {
- Log.startSession("TSI.gSMPA");
+ Log.startSession("TSI.gSMPA", Log.getPackageAbbreviation(callingPackage));
if (!canReadPhoneState(callingPackage, callingFeatureId,
"Requires READ_PHONE_STATE permission.")) {
throw new SecurityException("Requires READ_PHONE_STATE permission.");
@@ -250,7 +252,7 @@
public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme,
String callingPackage) {
try {
- Log.startSession("TSI.gPASS");
+ Log.startSession("TSI.gPASS", Log.getPackageAbbreviation(callingPackage));
try {
enforceModifyPermission(
"getPhoneAccountsSupportingScheme requires MODIFY_PHONE_STATE");
@@ -315,9 +317,21 @@
}
@Override
- public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
+ public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle,
+ String callingPackage) {
synchronized (mLock) {
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
+ if (CompatChanges.isChangeEnabled(
+ TelecomManager.ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION,
+ callingPackage, Binder.getCallingUserHandle())) {
+ if (Binder.getCallingUid() != Process.SHELL_UID &&
+ !canGetPhoneAccount(callingPackage, accountHandle)) {
+ SecurityException e = new SecurityException("getPhoneAccount API requires" +
+ "READ_PHONE_NUMBERS");
+ Log.e(this, e, "getPhoneAccount %s", accountHandle);
+ throw e;
+ }
+ }
long token = Binder.clearCallingIdentity();
try {
Log.startSession("TSI.gPA");
@@ -327,7 +341,7 @@
// profile's phone account handle.
return mPhoneAccountRegistrar
.getPhoneAccount(accountHandle, callingUserHandle,
- /* acrossProfiles */ true);
+ /* acrossProfiles */ true);
} catch (Exception e) {
Log.e(this, e, "getPhoneAccount %s", accountHandle);
throw e;
@@ -457,11 +471,11 @@
try {
Log.startSession("TSI.gSCMFU");
final int callingUid = Binder.getCallingUid();
+ if (user != ActivityManager.getCurrentUser()) {
+ enforceCrossUserPermission(callingUid);
+ }
long token = Binder.clearCallingIdentity();
try {
- if (user != ActivityManager.getCurrentUser()) {
- enforceCrossUserPermission(callingUid);
- }
return mPhoneAccountRegistrar.getSimCallManager(UserHandle.of(user));
} finally {
Binder.restoreCallingIdentity(token);
@@ -832,16 +846,21 @@
}
/**
- * @see android.telecom.TelecomManager#hasCompanionInCallServiceAccess
+ * @see android.telecom.TelecomManager#hasManageOngoingCallsPermission
*/
@Override
- public boolean hasCompanionInCallServiceAccess(String callingPackage) {
+ public boolean hasManageOngoingCallsPermission(String callingPackage) {
try {
- Log.startSession("TSI.hCICSA");
- return PermissionChecker.checkPermissionForPreflight(mContext,
- Manifest.permission.MANAGE_ONGOING_CALLS,
- PermissionChecker.PID_UNKNOWN, Binder.getCallingUid(),
- callingPackage) == PermissionChecker.PERMISSION_GRANTED;
+ Log.startSession("TSI.hMOCP");
+ enforceCallingPackage(callingPackage);
+ return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
+ mContext, Manifest.permission.MANAGE_ONGOING_CALLS,
+ Binder.getCallingPid(),
+ new AttributionSource(mContext.getAttributionSource(),
+ new AttributionSource(Binder.getCallingUid(),
+ callingPackage, /*attributionTag*/ null)),
+ "Checking whether the caller has MANAGE_ONGOING_CALLS permission")
+ == PermissionChecker.PERMISSION_GRANTED;
} finally {
Log.endSession();
}
@@ -898,12 +917,48 @@
}
/**
- * @see TelecomManager#getCallState
+ * @see TelecomManager#getCallState()
+ * @deprecated this is only being kept due to an @UnsupportedAppUsage tag. Apps targeting
+ * API 31+ must use {@link #getCallStateUsingPackage(String, String)} below.
*/
+ @Deprecated
@Override
public int getCallState() {
try {
- Log.startSession("TSI.getCallState");
+ Log.startSession("TSI.getCallState(DEPRECATED)");
+ if (CompatChanges.isChangeEnabled(
+ TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION,
+ Binder.getCallingUid())) {
+ // Do not allow this API to be called on API version 31+, it should only be
+ // called on old apps using this Binder call directly.
+ throw new SecurityException("This method can only be used for applications "
+ + "targeting API version 30 or less.");
+ }
+ synchronized (mLock) {
+ return mCallsManager.getCallState();
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ /**
+ * @see TelecomManager#getCallState()
+ */
+ @Override
+ public int getCallStateUsingPackage(String callingPackage, String callingFeatureId) {
+ try {
+ Log.startSession("TSI.getCallStateUsingPackage");
+ if (CompatChanges.isChangeEnabled(
+ TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION, callingPackage,
+ Binder.getCallingUserHandle())) {
+ // Bypass canReadPhoneState check if this is being called from SHELL UID
+ if (Binder.getCallingUid() != Process.SHELL_UID && !canReadPhoneState(
+ callingPackage, callingFeatureId, "getCallState")) {
+ throw new SecurityException("getCallState API requires READ_PHONE_STATE"
+ + " for API version 31+");
+ }
+ }
synchronized (mLock) {
return mCallsManager.getCallState();
}
@@ -918,7 +973,7 @@
@Override
public boolean endCall(String callingPackage) {
try {
- Log.startSession("TSI.eC");
+ Log.startSession("TSI.eC", Log.getPackageAbbreviation(callingPackage));
synchronized (mLock) {
if (!enforceAnswerCallPermission(callingPackage, Binder.getCallingUid())) {
throw new SecurityException("requires ANSWER_PHONE_CALLS permission");
@@ -942,13 +997,13 @@
@Override
public void acceptRingingCall(String packageName) {
try {
- Log.startSession("TSI.aRC");
+ Log.startSession("TSI.aRC", Log.getPackageAbbreviation(packageName));
synchronized (mLock) {
if (!enforceAnswerCallPermission(packageName, Binder.getCallingUid())) return;
long token = Binder.clearCallingIdentity();
try {
- acceptRingingCallInternal(DEFAULT_VIDEO_STATE);
+ acceptRingingCallInternal(DEFAULT_VIDEO_STATE, packageName);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -965,13 +1020,13 @@
@Override
public void acceptRingingCallWithVideoState(String packageName, int videoState) {
try {
- Log.startSession("TSI.aRCWVS");
+ Log.startSession("TSI.aRCWVS", Log.getPackageAbbreviation(packageName));
synchronized (mLock) {
if (!enforceAnswerCallPermission(packageName, Binder.getCallingUid())) return;
long token = Binder.clearCallingIdentity();
try {
- acceptRingingCallInternal(videoState);
+ acceptRingingCallInternal(videoState, packageName);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -988,7 +1043,7 @@
public void showInCallScreen(boolean showDialpad, String callingPackage,
String callingFeatureId) {
try {
- Log.startSession("TSI.sICS");
+ Log.startSession("TSI.sICS", Log.getPackageAbbreviation(callingPackage));
if (!canReadPhoneState(callingPackage, callingFeatureId, "showInCallScreen")) {
return;
}
@@ -1013,7 +1068,7 @@
@Override
public void cancelMissedCallsNotification(String callingPackage) {
try {
- Log.startSession("TSI.cMCN");
+ Log.startSession("TSI.cMCN", Log.getPackageAbbreviation(callingPackage));
synchronized (mLock) {
enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
UserHandle userHandle = Binder.getCallingUserHandle();
@@ -1034,7 +1089,7 @@
@Override
public boolean handlePinMmi(String dialString, String callingPackage) {
try {
- Log.startSession("TSI.hPM");
+ Log.startSession("TSI.hPM", Log.getPackageAbbreviation(callingPackage));
enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
// Switch identity so that TelephonyManager checks Telecom's permissions
@@ -1062,7 +1117,7 @@
public boolean handlePinMmiForPhoneAccount(PhoneAccountHandle accountHandle,
String dialString, String callingPackage) {
try {
- Log.startSession("TSI.hPMFPA");
+ Log.startSession("TSI.hPMFPA", Log.getPackageAbbreviation(callingPackage));
enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
UserHandle callingUserHandle = Binder.getCallingUserHandle();
@@ -1103,7 +1158,7 @@
public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle,
String callingPackage) {
try {
- Log.startSession("TSI.aAUFPA");
+ Log.startSession("TSI.aAUFPA", Log.getPackageAbbreviation(callingPackage));
enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
synchronized (mLock) {
if (!isPhoneAccountHandleVisibleToCallingUser(accountHandle,
@@ -1137,7 +1192,7 @@
@Override
public boolean isTtySupported(String callingPackage, String callingFeatureId) {
try {
- Log.startSession("TSI.iTS");
+ Log.startSession("TSI.iTS", Log.getPackageAbbreviation(callingPackage));
if (!canReadPhoneState(callingPackage, callingFeatureId, "isTtySupported")) {
throw new SecurityException("Only default dialer or an app with" +
"READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE can call this api");
@@ -1157,7 +1212,7 @@
@Override
public int getCurrentTtyMode(String callingPackage, String callingFeatureId) {
try {
- Log.startSession("TSI.gCTM");
+ Log.startSession("TSI.gCTM", Log.getPackageAbbreviation(callingPackage));
if (!canReadPhoneState(callingPackage, callingFeatureId, "getCurrentTtyMode")) {
return TelecomManager.TTY_MODE_OFF;
}
@@ -1389,7 +1444,7 @@
public void startConference(List<Uri> participants, Bundle extras,
String callingPackage) {
try {
- Log.startSession("TSI.sC");
+ Log.startSession("TSI.sC", Log.getPackageAbbreviation(callingPackage));
if (!canCallPhone(callingPackage, "startConference")) {
throw new SecurityException("Package " + callingPackage + " is not allowed"
+ " to start conference call");
@@ -1408,10 +1463,11 @@
public void placeCall(Uri handle, Bundle extras, String callingPackage,
String callingFeatureId) {
try {
- Log.startSession("TSI.pC");
+ Log.startSession("TSI.pC", Log.getPackageAbbreviation(callingPackage));
enforceCallingPackage(callingPackage);
PhoneAccountHandle phoneAccountHandle = null;
+ boolean clearPhoneAccountHandleExtra = false;
if (extras != null) {
phoneAccountHandle = extras.getParcelable(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
@@ -1423,17 +1479,24 @@
boolean isSelfManaged = phoneAccountHandle != null &&
isSelfManagedConnectionService(phoneAccountHandle);
if (isSelfManaged) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_OWN_CALLS,
- "Self-managed ConnectionServices require MANAGE_OWN_CALLS permission.");
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MANAGE_OWN_CALLS,
+ "Self-managed ConnectionServices require "
+ + "MANAGE_OWN_CALLS permission.");
+ } catch (SecurityException e) {
+ // Fallback to use mobile network to avoid disclosing phone account handle
+ // package information
+ clearPhoneAccountHandleExtra = true;
+ }
- if (!callingPackage.equals(
+ if (!clearPhoneAccountHandleExtra && !callingPackage.equals(
phoneAccountHandle.getComponentName().getPackageName())
&& !canCallPhone(callingPackage, callingFeatureId,
"CALL_PHONE permission required to place calls.")) {
- // The caller is not allowed to place calls, so we want to ensure that it
- // can only place calls through itself.
- throw new SecurityException("Self-managed ConnectionServices can only "
- + "place calls through their own ConnectionService.");
+ // The caller is not allowed to place calls, so fallback to use mobile
+ // network.
+ clearPhoneAccountHandleExtra = true;
}
} else if (!canCallPhone(callingPackage, callingFeatureId, "placeCall")) {
throw new SecurityException("Package " + callingPackage
@@ -1468,6 +1531,9 @@
final Intent intent = new Intent(hasCallPrivilegedPermission ?
Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, handle);
if (extras != null) {
+ if (clearPhoneAccountHandleExtra) {
+ extras.remove(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+ }
extras.setDefusable(true);
intent.putExtras(extras);
}
@@ -1776,6 +1842,8 @@
* {@link CallState#DISCONNECTED} or {@link CallState#DISCONNECTING} states. Stuck calls
* during CTS cause cascading failures, so if the CTS test detects such a state, it should
* call this method via a shell command to clean up before moving on to the next test.
+ * Also cleans up any pending futures related to
+ * {@link android.telecom.CallDiagnosticService}s.
*/
@Override
public void cleanupStuckCalls() {
@@ -1785,11 +1853,35 @@
enforceShellOnly(Binder.getCallingUid(), "cleanupStuckCalls");
Binder.withCleanCallingIdentity(() -> {
for (Call call : mCallsManager.getCalls()) {
+ call.cleanup();
if (call.getState() == CallState.DISCONNECTED
|| call.getState() == CallState.DISCONNECTING) {
mCallsManager.markCallAsRemoved(call);
}
}
+ mCallsManager.getInCallController().unbindFromServices();
+ });
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ /**
+ * A method intended for use in testing to reset car mode at all priorities.
+ *
+ * Runs during setup to avoid cascading failures from failing car mode CTS.
+ */
+ @Override
+ public void resetCarMode() {
+ Log.startSession("TCI.rCM");
+ try {
+ synchronized (mLock) {
+ enforceShellOnly(Binder.getCallingUid(), "resetCarMode");
+ Binder.withCleanCallingIdentity(() -> {
+ UiModeManager uiModeManager =
+ mContext.getSystemService(UiModeManager.class);
+ uiModeManager.disableCarMode(UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES);
});
}
} finally {
@@ -1899,6 +1991,30 @@
Log.endSession();
}
}
+
+ @Override
+ public void setTestCallDiagnosticService(String packageName) {
+ try {
+ Log.startSession("TSI.sTCDS");
+ enforceModifyPermission();
+ enforceShellOnly(Binder.getCallingUid(), "setTestCallDiagnosticService is for "
+ + "shell use only.");
+ synchronized (mLock) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ CallDiagnosticServiceController controller =
+ mCallsManager.getCallDiagnosticServiceController();
+ if (controller != null) {
+ controller.setTestCallDiagnosticService(packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
};
/**
@@ -2028,9 +2144,16 @@
return false;
}
- private void acceptRingingCallInternal(int videoState) {
- Call call = mCallsManager.getFirstCallWithState(CallState.RINGING, CallState.SIMULATED_RINGING);
+ private void acceptRingingCallInternal(int videoState, String packageName) {
+ Call call = mCallsManager.getFirstCallWithState(CallState.RINGING,
+ CallState.SIMULATED_RINGING);
if (call != null) {
+ if (call.isSelfManaged()) {
+ Log.addEvent(call, LogUtils.Events.REQUEST_ACCEPT,
+ "self-mgd accept ignored from " + packageName);
+ return;
+ }
+
if (videoState == DEFAULT_VIDEO_STATE || !isValidAcceptVideoState(videoState)) {
videoState = call.getVideoState();
}
@@ -2058,6 +2181,12 @@
return false;
}
+ if (call.isSelfManaged()) {
+ Log.addEvent(call, LogUtils.Events.REQUEST_DISCONNECT,
+ "self-mgd disconnect ignored from " + callingPackage);
+ return false;
+ }
+
if (call.getState() == CallState.RINGING
|| call.getState() == CallState.SIMULATED_RINGING) {
mCallsManager.rejectCall(call, false /* rejectWithMessage */, null);
@@ -2317,6 +2446,28 @@
== AppOpsManager.MODE_ALLOWED;
}
+ private boolean canGetPhoneAccount(String callingPackage, PhoneAccountHandle accountHandle) {
+ // Allow default dialer, system dialer and sim call manager to be able to do this without
+ // extra permission
+ try {
+ if (isPrivilegedDialerCalling(callingPackage) || isCallerSimCallManager(
+ accountHandle)) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ // ignore
+ }
+
+ try {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);
+ return true;
+ } catch (SecurityException e) {
+ // Accessing phone state is gated by a special permission.
+ mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, null);
+ return true;
+ }
+ }
+
private boolean isCallerSimCallManager(PhoneAccountHandle targetPhoneAccount) {
long token = Binder.clearCallingIdentity();
PhoneAccountHandle accountHandle = null;
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 8928e76..a7442a9 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -31,13 +31,16 @@
import com.android.server.telecom.ui.ToastFactory;
import android.app.ActivityManager;
+import android.bluetooth.BluetoothManager;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
@@ -45,8 +48,11 @@
import android.telecom.PhoneAccountHandle;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+
import java.io.FileNotFoundException;
import java.io.InputStream;
+import java.util.List;
/**
* Top-level Application class for Telecom.
@@ -212,165 +218,208 @@
defaultDialerAdapter, roleManagerAdapter, mLock);
Log.startSession("TS.init");
- mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext, defaultDialerCache,
- packageName -> AppLabelProxy.Util.getAppLabel(
- mContext.getPackageManager(), packageName));
+ // Wrap this in a try block to ensure session cleanup occurs in the case of error.
+ try {
+ mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext, defaultDialerCache,
+ packageName -> AppLabelProxy.Util.getAppLabel(
+ mContext.getPackageManager(), packageName));
- mContactsAsyncHelper = contactsAsyncHelperFactory.create(
- new ContactsAsyncHelper.ContentResolverAdapter() {
- @Override
- public InputStream openInputStream(Context context, Uri uri)
- throws FileNotFoundException {
- return context.getContentResolver().openInputStream(uri);
- }
- });
- BluetoothDeviceManager bluetoothDeviceManager = new BluetoothDeviceManager(mContext,
- new BluetoothAdapterProxy());
- BluetoothRouteManager bluetoothRouteManager = new BluetoothRouteManager(mContext, mLock,
- bluetoothDeviceManager, new Timeouts.Adapter());
- BluetoothStateReceiver bluetoothStateReceiver = new BluetoothStateReceiver(
- bluetoothDeviceManager, bluetoothRouteManager);
- mContext.registerReceiver(bluetoothStateReceiver, BluetoothStateReceiver.INTENT_FILTER);
+ mContactsAsyncHelper = contactsAsyncHelperFactory.create(
+ new ContactsAsyncHelper.ContentResolverAdapter() {
+ @Override
+ public InputStream openInputStream(Context context, Uri uri)
+ throws FileNotFoundException {
+ return context.getContentResolver().openInputStream(uri);
+ }
+ });
+ BluetoothDeviceManager bluetoothDeviceManager = new BluetoothDeviceManager(mContext,
+ new BluetoothManager(mContext).getAdapter());
+ BluetoothRouteManager bluetoothRouteManager = new BluetoothRouteManager(mContext, mLock,
+ bluetoothDeviceManager, new Timeouts.Adapter());
+ BluetoothStateReceiver bluetoothStateReceiver = new BluetoothStateReceiver(
+ bluetoothDeviceManager, bluetoothRouteManager);
+ mContext.registerReceiver(bluetoothStateReceiver, BluetoothStateReceiver.INTENT_FILTER);
- WiredHeadsetManager wiredHeadsetManager = new WiredHeadsetManager(mContext);
- SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
+ WiredHeadsetManager wiredHeadsetManager = new WiredHeadsetManager(mContext);
+ SystemStateHelper systemStateHelper = new SystemStateHelper(mContext, mLock);
- mMissedCallNotifier = missedCallNotifierImplFactory
- .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache,
- deviceIdleControllerAdapter);
- DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory =
- new DisconnectedCallNotifier.Default();
+ mMissedCallNotifier = missedCallNotifierImplFactory
+ .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar,
+ defaultDialerCache,
+ deviceIdleControllerAdapter);
+ DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory =
+ new DisconnectedCallNotifier.Default();
- CallerInfoLookupHelper callerInfoLookupHelper =
- new CallerInfoLookupHelper(context, callerInfoAsyncQueryFactory,
- mContactsAsyncHelper, mLock);
+ CallerInfoLookupHelper callerInfoLookupHelper =
+ new CallerInfoLookupHelper(context, callerInfoAsyncQueryFactory,
+ mContactsAsyncHelper, mLock);
- EmergencyCallHelper emergencyCallHelper = new EmergencyCallHelper(mContext,
- defaultDialerCache, timeoutsAdapter);
+ EmergencyCallHelper emergencyCallHelper = new EmergencyCallHelper(mContext,
+ defaultDialerCache, timeoutsAdapter);
- InCallControllerFactory inCallControllerFactory = new InCallControllerFactory() {
- @Override
- public InCallController create(Context context, SyncRoot lock,
- CallsManager callsManager, SystemStateHelper systemStateProvider,
- DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter,
- EmergencyCallHelper emergencyCallHelper) {
- return new InCallController(context, lock, callsManager, systemStateProvider,
- defaultDialerCache, timeoutsAdapter, emergencyCallHelper,
- new CarModeTracker(), clockProxy);
- }
- };
+ InCallControllerFactory inCallControllerFactory = new InCallControllerFactory() {
+ @Override
+ public InCallController create(Context context, SyncRoot lock,
+ CallsManager callsManager, SystemStateHelper systemStateProvider,
+ DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter,
+ EmergencyCallHelper emergencyCallHelper) {
+ return new InCallController(context, lock, callsManager, systemStateProvider,
+ defaultDialerCache, timeoutsAdapter, emergencyCallHelper,
+ new CarModeTracker(), clockProxy);
+ }
+ };
- AudioProcessingNotification audioProcessingNotification =
- new AudioProcessingNotification(mContext);
+ CallDiagnosticServiceController callDiagnosticServiceController =
+ new CallDiagnosticServiceController(
+ new CallDiagnosticServiceController.ContextProxy() {
+ @Override
+ public List<ResolveInfo> queryIntentServicesAsUser(
+ @NonNull Intent intent, int flags, int userId) {
+ return mContext.getPackageManager().queryIntentServicesAsUser(
+ intent, flags, userId);
+ }
- ToastFactory toastFactory = new ToastFactory() {
- @Override
- public Toast makeText(Context context, int resId, int duration) {
- return Toast.makeText(context, context.getMainLooper(), context.getString(resId),
- duration);
+ @Override
+ public boolean bindServiceAsUser(@NonNull Intent service,
+ @NonNull ServiceConnection conn, int flags,
+ @NonNull UserHandle user) {
+ return mContext.bindServiceAsUser(service, conn, flags, user);
+ }
+
+ @Override
+ public void unbindService(@NonNull ServiceConnection conn) {
+ mContext.unbindService(conn);
+ }
+
+ @Override
+ public UserHandle getCurrentUserHandle() {
+ return mCallsManager.getCurrentUserHandle();
+ }
+ },
+ mContext.getResources().getString(
+ com.android.server.telecom.R.string
+ .call_diagnostic_service_package_name),
+ mLock
+ );
+
+ AudioProcessingNotification audioProcessingNotification =
+ new AudioProcessingNotification(mContext);
+
+ ToastFactory toastFactory = new ToastFactory() {
+ @Override
+ public Toast makeText(Context context, int resId, int duration) {
+ return Toast.makeText(context, context.getMainLooper(),
+ context.getString(resId),
+ duration);
+ }
+
+ @Override
+ public Toast makeText(Context context, CharSequence text, int duration) {
+ return Toast.makeText(context, context.getMainLooper(), text, duration);
+ }
+ };
+
+ mCallsManager = new CallsManager(
+ mContext,
+ mLock,
+ callerInfoLookupHelper,
+ mMissedCallNotifier,
+ disconnectedCallNotifierFactory,
+ mPhoneAccountRegistrar,
+ headsetMediaButtonFactory,
+ proximitySensorManagerFactory,
+ inCallWakeLockControllerFactory,
+ connectionServiceFocusManagerFactory,
+ audioServiceFactory,
+ bluetoothRouteManager,
+ wiredHeadsetManager,
+ systemStateHelper,
+ defaultDialerCache,
+ timeoutsAdapter,
+ asyncRingtonePlayer,
+ phoneNumberUtilsAdapter,
+ emergencyCallHelper,
+ toneGeneratorFactory,
+ clockProxy,
+ audioProcessingNotification,
+ bluetoothStateReceiver,
+ callAudioRouteStateMachineFactory,
+ callAudioModeStateMachineFactory,
+ inCallControllerFactory,
+ callDiagnosticServiceController,
+ roleManagerAdapter,
+ toastFactory);
+
+ mIncomingCallNotifier = incomingCallNotifier;
+ incomingCallNotifier.setCallsManagerProxy(new IncomingCallNotifier.CallsManagerProxy() {
+ @Override
+ public boolean hasUnholdableCallsForOtherConnectionService(
+ PhoneAccountHandle phoneAccountHandle) {
+ return mCallsManager.hasUnholdableCallsForOtherConnectionService(
+ phoneAccountHandle);
+ }
+
+ @Override
+ public int getNumUnholdableCallsForOtherConnectionService(
+ PhoneAccountHandle phoneAccountHandle) {
+ return mCallsManager.getNumUnholdableCallsForOtherConnectionService(
+ phoneAccountHandle);
+ }
+
+ @Override
+ public Call getActiveCall() {
+ return mCallsManager.getActiveCall();
+ }
+ });
+ mCallsManager.setIncomingCallNotifier(mIncomingCallNotifier);
+
+ mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
+ mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
+
+ mContext.registerReceiverAsUser(mUserSwitchedReceiver, UserHandle.ALL,
+ USER_SWITCHED_FILTER, null, null);
+ mContext.registerReceiverAsUser(mUserStartingReceiver, UserHandle.ALL,
+ USER_STARTING_FILTER, null, null);
+ mContext.registerReceiverAsUser(mBootCompletedReceiver, UserHandle.ALL,
+ BOOT_COMPLETE_FILTER, null, null);
+
+ // Set current user explicitly since USER_SWITCHED_FILTER intent can be missed at
+ // startup
+ synchronized (mLock) {
+ UserHandle currentUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
+ mPhoneAccountRegistrar.setCurrentUserHandle(currentUserHandle);
+ mCallsManager.onUserSwitch(currentUserHandle);
}
- @Override
- public Toast makeText(Context context, CharSequence text, int duration) {
- return Toast.makeText(context, context.getMainLooper(), text, duration);
- }
- };
+ mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager,
+ defaultDialerCache);
+ mTelecomBroadcastIntentProcessor = new TelecomBroadcastIntentProcessor(
+ mContext, mCallsManager);
- mCallsManager = new CallsManager(
- mContext,
- mLock,
- callerInfoLookupHelper,
- mMissedCallNotifier,
- disconnectedCallNotifierFactory,
- mPhoneAccountRegistrar,
- headsetMediaButtonFactory,
- proximitySensorManagerFactory,
- inCallWakeLockControllerFactory,
- connectionServiceFocusManagerFactory,
- audioServiceFactory,
- bluetoothRouteManager,
- wiredHeadsetManager,
- systemStateHelper,
- defaultDialerCache,
- timeoutsAdapter,
- asyncRingtonePlayer,
- phoneNumberUtilsAdapter,
- emergencyCallHelper,
- toneGeneratorFactory,
- clockProxy,
- audioProcessingNotification,
- bluetoothStateReceiver,
- callAudioRouteStateMachineFactory,
- callAudioModeStateMachineFactory,
- inCallControllerFactory,
- roleManagerAdapter,
- toastFactory);
+ // Register the receiver for the dialer secret codes, used to enable extended logging.
+ mDialerCodeReceiver = new DialerCodeReceiver(mCallsManager);
+ mContext.registerReceiver(mDialerCodeReceiver, DIALER_SECRET_CODE_FILTER,
+ Manifest.permission.CONTROL_INCALL_EXPERIENCE, null);
- mIncomingCallNotifier = incomingCallNotifier;
- incomingCallNotifier.setCallsManagerProxy(new IncomingCallNotifier.CallsManagerProxy() {
- @Override
- public boolean hasUnholdableCallsForOtherConnectionService(
- PhoneAccountHandle phoneAccountHandle) {
- return mCallsManager.hasUnholdableCallsForOtherConnectionService(
- phoneAccountHandle);
- }
-
- @Override
- public int getNumUnholdableCallsForOtherConnectionService(
- PhoneAccountHandle phoneAccountHandle) {
- return mCallsManager.getNumUnholdableCallsForOtherConnectionService(
- phoneAccountHandle);
- }
-
- @Override
- public Call getActiveCall() {
- return mCallsManager.getActiveCall();
- }
- });
- mCallsManager.setIncomingCallNotifier(mIncomingCallNotifier);
-
- mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
- mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
-
- mContext.registerReceiverAsUser(mUserSwitchedReceiver, UserHandle.ALL,
- USER_SWITCHED_FILTER, null, null);
- mContext.registerReceiverAsUser(mUserStartingReceiver, UserHandle.ALL,
- USER_STARTING_FILTER, null, null);
- mContext.registerReceiverAsUser(mBootCompletedReceiver, UserHandle.ALL,
- BOOT_COMPLETE_FILTER, null, null);
-
- // Set current user explicitly since USER_SWITCHED_FILTER intent can be missed at startup
- synchronized(mLock) {
- UserHandle currentUserHandle = UserHandle.of(ActivityManager.getCurrentUser());
- mPhoneAccountRegistrar.setCurrentUserHandle(currentUserHandle);
- mCallsManager.onUserSwitch(currentUserHandle);
+ // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly.
+ final UserManager userManager = UserManager.get(mContext);
+ mTelecomServiceImpl = new TelecomServiceImpl(
+ mContext, mCallsManager, mPhoneAccountRegistrar,
+ new CallIntentProcessor.AdapterImpl(defaultDialerCache),
+ new UserCallIntentProcessorFactory() {
+ @Override
+ public UserCallIntentProcessor create(Context context,
+ UserHandle userHandle) {
+ return new UserCallIntentProcessor(context, userHandle);
+ }
+ },
+ defaultDialerCache,
+ new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
+ new TelecomServiceImpl.SettingsSecureAdapterImpl(),
+ mLock);
+ } finally {
+ Log.endSession();
}
-
- mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager, defaultDialerCache);
- mTelecomBroadcastIntentProcessor = new TelecomBroadcastIntentProcessor(
- mContext, mCallsManager);
-
- // Register the receiver for the dialer secret codes, used to enable extended logging.
- mDialerCodeReceiver = new DialerCodeReceiver(mCallsManager);
- mContext.registerReceiver(mDialerCodeReceiver, DIALER_SECRET_CODE_FILTER,
- Manifest.permission.CONTROL_INCALL_EXPERIENCE, null);
-
- // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly.
- final UserManager userManager = UserManager.get(mContext);
- mTelecomServiceImpl = new TelecomServiceImpl(
- mContext, mCallsManager, mPhoneAccountRegistrar,
- new CallIntentProcessor.AdapterImpl(defaultDialerCache),
- new UserCallIntentProcessorFactory() {
- @Override
- public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
- return new UserCallIntentProcessor(context, userHandle);
- }
- },
- defaultDialerCache,
- new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
- new TelecomServiceImpl.SettingsSecureAdapterImpl(),
- mLock);
- Log.endSession();
}
@VisibleForTesting
diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java
index 2309596..36caa25 100644
--- a/src/com/android/server/telecom/Timeouts.java
+++ b/src/com/android/server/telecom/Timeouts.java
@@ -17,8 +17,13 @@
package com.android.server.telecom;
import android.content.ContentResolver;
+import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.telecom.CallDiagnosticService;
import android.telecom.CallRedirectionService;
+import android.telecom.CallDiagnostics;
+import android.telephony.ims.ImsReasonInfo;
+
import java.util.concurrent.TimeUnit;
/**
@@ -67,6 +72,14 @@
public long getCallRecordingToneRepeatIntervalMillis(ContentResolver cr) {
return Timeouts.getCallRecordingToneRepeatIntervalMillis(cr);
}
+
+ public long getCallDiagnosticServiceTimeoutMillis(ContentResolver cr) {
+ return Timeouts.getCallDiagnosticServiceTimeoutMillis(cr);
+ }
+
+ public long getCallStartAppOpDebounceIntervalMillis() {
+ return Timeouts.getCallStartAppOpDebounceIntervalMillis();
+ }
}
/** A prefix to use for all keys so to not clobber the global namespace. */
@@ -85,7 +98,8 @@
* @return The timeout value from Settings or the default value if it hasn't been changed.
*/
private static long get(ContentResolver contentResolver, String key, long defaultValue) {
- return Settings.Secure.getLong(contentResolver, PREFIX + key, defaultValue);
+ return Settings.Secure.getLongForUser(contentResolver, PREFIX + key, defaultValue,
+ contentResolver.getUserId());
}
/**
@@ -189,7 +203,7 @@
/**
* Returns the amount of time for an user-defined {@link CallRedirectionService}.
*
- * @param contentResolver The content resolved.
+ * @param contentResolver The content resolver.
*/
public static long getUserDefinedCallRedirectionTimeoutMillis(ContentResolver contentResolver) {
return get(contentResolver, "user_defined_call_redirection_timeout",
@@ -199,7 +213,7 @@
/**
* Returns the amount of time for a carrier {@link CallRedirectionService}.
*
- * @param contentResolver The content resolved.
+ * @param contentResolver The content resolver.
*/
public static long getCarrierCallRedirectionTimeoutMillis(ContentResolver contentResolver) {
return get(contentResolver, "carrier_call_redirection_timeout", 5000L /* 5 seconds */);
@@ -213,6 +227,21 @@
}
/**
+ * Returns the maximum amount of time a {@link CallDiagnosticService} is permitted to take to
+ * return back from {@link CallDiagnostics#onCallDisconnected(ImsReasonInfo)} and
+ * {@link CallDiagnostics#onCallDisconnected(int, int)}.
+ * @param contentResolver The resolver for the config option.
+ * @return The timeout in millis.
+ */
+ public static long getCallDiagnosticServiceTimeoutMillis(ContentResolver contentResolver) {
+ return get(contentResolver, "call_diagnostic_service_timeout", 2000L /* 2 sec */);
+ }
+
+ public static long getCallStartAppOpDebounceIntervalMillis() {
+ return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, "app_op_debounce_time", 250L);
+ }
+
+ /**
* Returns the number of milliseconds for which the system should exempt the default dialer from
* power save restrictions due to the dialer needing to handle a missed call notification
* (update call log, check VVM, etc...).
diff --git a/src/com/android/server/telecom/TtyManager.java b/src/com/android/server/telecom/TtyManager.java
index dfddb8f..f1b74a4 100644
--- a/src/com/android/server/telecom/TtyManager.java
+++ b/src/com/android/server/telecom/TtyManager.java
@@ -42,16 +42,17 @@
mWiredHeadsetManager = wiredHeadsetManager;
mWiredHeadsetManager.addListener(this);
- mPreferredTtyMode = Settings.Secure.getInt(
+ mPreferredTtyMode = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.PREFERRED_TTY_MODE,
- TelecomManager.TTY_MODE_OFF);
+ TelecomManager.TTY_MODE_OFF,
+ mContext.getUserId());
IntentFilter intentFilter = new IntentFilter(
TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
mContext.registerReceiver(mReceiver, intentFilter,
android.Manifest.permission.MODIFY_PHONE_STATE,
- null);
+ null, Context.RECEIVER_EXPORTED);
updateCurrentTtyMode();
}
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 7fd600c..c7671e3 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -26,8 +26,6 @@
import android.util.LocalLog;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.telecom.BluetoothAdapterProxy;
-import com.android.server.telecom.BluetoothHeadsetProxy;
import java.util.ArrayList;
import java.util.Collection;
@@ -48,13 +46,12 @@
synchronized (mLock) {
String logString;
if (profile == BluetoothProfile.HEADSET) {
- mBluetoothHeadsetService =
- new BluetoothHeadsetProxy((BluetoothHeadset) proxy);
- logString = "Got BluetoothHeadset: " + mBluetoothHeadsetService;
+ mBluetoothHeadset = (BluetoothHeadset) proxy;
+ logString = "Got BluetoothHeadset: " + mBluetoothHeadset;
} else if (profile == BluetoothProfile.HEARING_AID) {
- mBluetoothHearingAidService = (BluetoothHearingAid) proxy;
+ mBluetoothHearingAid = (BluetoothHearingAid) proxy;
logString = "Got BluetoothHearingAid: "
- + mBluetoothHearingAidService;
+ + mBluetoothHearingAid;
} else {
logString = "Connected to non-requested bluetooth service." +
" Not changing bluetooth headset.";
@@ -75,13 +72,13 @@
LinkedHashMap<String, BluetoothDevice> lostServiceDevices;
String logString;
if (profile == BluetoothProfile.HEADSET) {
- mBluetoothHeadsetService = null;
+ mBluetoothHeadset = null;
lostServiceDevices = mHfpDevicesByAddress;
mBluetoothRouteManager.onActiveDeviceChanged(null, false);
logString = "Lost BluetoothHeadset service. " +
"Removing all tracked devices";
} else if (profile == BluetoothProfile.HEARING_AID) {
- mBluetoothHearingAidService = null;
+ mBluetoothHearingAid = null;
logString = "Lost BluetoothHearingAid service. " +
"Removing all tracked devices.";
lostServiceDevices = mHearingAidDevicesByAddress;
@@ -117,14 +114,14 @@
private final Object mLock = new Object();
private BluetoothRouteManager mBluetoothRouteManager;
- private BluetoothHeadsetProxy mBluetoothHeadsetService;
- private BluetoothHearingAid mBluetoothHearingAidService;
+ private BluetoothHeadset mBluetoothHeadset;
+ private BluetoothHearingAid mBluetoothHearingAid;
private BluetoothDevice mBluetoothHearingAidActiveDeviceCache;
- private BluetoothAdapterProxy mBluetoothAdapterProxy;
+ private BluetoothAdapter mBluetoothAdapter;
- public BluetoothDeviceManager(Context context, BluetoothAdapterProxy bluetoothAdapter) {
+ public BluetoothDeviceManager(Context context, BluetoothAdapter bluetoothAdapter) {
if (bluetoothAdapter != null) {
- mBluetoothAdapterProxy = bluetoothAdapter;
+ mBluetoothAdapter = bluetoothAdapter;
bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
BluetoothProfile.HEADSET);
bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
@@ -160,8 +157,9 @@
Set<Long> seenHiSyncIds = new LinkedHashSet<>();
// Add the left-most active device to the seen list so that we match up with the list
// generated in BluetoothRouteManager.
- if (mBluetoothHearingAidService != null) {
- for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
+ if (mBluetoothAdapter != null) {
+ for (BluetoothDevice device : mBluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID)) {
if (device != null) {
result.add(device);
seenHiSyncIds.add(mHearingAidDeviceSyncIds.getOrDefault(device, -1L));
@@ -182,20 +180,24 @@
return Collections.unmodifiableCollection(result);
}
- public BluetoothHeadsetProxy getHeadsetService() {
- return mBluetoothHeadsetService;
+ public BluetoothHeadset getBluetoothHeadset() {
+ return mBluetoothHeadset;
}
- public BluetoothHearingAid getHearingAidService() {
- return mBluetoothHearingAidService;
+ public BluetoothAdapter getBluetoothAdapter() {
+ return mBluetoothAdapter;
}
- public void setHeadsetServiceForTesting(BluetoothHeadsetProxy bluetoothHeadset) {
- mBluetoothHeadsetService = bluetoothHeadset;
+ public BluetoothHearingAid getBluetoothHearingAid() {
+ return mBluetoothHearingAid;
+ }
+
+ public void setHeadsetServiceForTesting(BluetoothHeadset bluetoothHeadset) {
+ mBluetoothHeadset = bluetoothHeadset;
}
public void setHearingAidServiceForTesting(BluetoothHearingAid bluetoothHearingAid) {
- mBluetoothHearingAidService = bluetoothHearingAid;
+ mBluetoothHearingAid = bluetoothHearingAid;
}
void onDeviceConnected(BluetoothDevice device, boolean isHearingAid) {
@@ -204,15 +206,15 @@
synchronized (mLock) {
LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
if (isHearingAid) {
- if (mBluetoothHearingAidService == null) {
+ if (mBluetoothHearingAid == null) {
Log.w(this, "Hearing aid service null when receiving device added broadcast");
return;
}
- long hiSyncId = mBluetoothHearingAidService.getHiSyncId(device);
+ long hiSyncId = mBluetoothHearingAid.getHiSyncId(device);
mHearingAidDeviceSyncIds.put(device, hiSyncId);
targetDeviceMap = mHearingAidDevicesByAddress;
} else {
- if (mBluetoothHeadsetService == null) {
+ if (mBluetoothHeadset == null) {
Log.w(this, "Headset service null when receiving device added broadcast");
return;
}
@@ -244,13 +246,11 @@
}
public void disconnectAudio() {
- if (mBluetoothHearingAidService == null) {
- Log.w(this, "Trying to disconnect audio but no hearing aid service exists");
- } else {
- for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
+ if (mBluetoothAdapter != null) {
+ for (BluetoothDevice device: mBluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID)) {
if (device != null) {
- mBluetoothAdapterProxy.setActiveDevice(null,
- BluetoothAdapter.ACTIVE_DEVICE_ALL);
+ mBluetoothAdapter.removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
}
}
}
@@ -258,10 +258,10 @@
}
public void disconnectSco() {
- if (mBluetoothHeadsetService == null) {
+ if (mBluetoothHeadset == null) {
Log.w(this, "Trying to disconnect audio but no headset service exists.");
} else {
- mBluetoothHeadsetService.disconnectAudio();
+ mBluetoothHeadset.disconnectAudio();
}
}
@@ -269,27 +269,27 @@
// or a HFP device, and using the proper BT API.
public boolean connectAudio(String address) {
if (mHearingAidDevicesByAddress.containsKey(address)) {
- if (mBluetoothHearingAidService == null) {
+ if (mBluetoothHearingAid == null) {
Log.w(this, "Attempting to turn on audio when the hearing aid service is null");
return false;
}
- return mBluetoothAdapterProxy.setActiveDevice(
+ return mBluetoothAdapter.setActiveDevice(
mHearingAidDevicesByAddress.get(address),
BluetoothAdapter.ACTIVE_DEVICE_ALL);
} else if (mHfpDevicesByAddress.containsKey(address)) {
BluetoothDevice device = mHfpDevicesByAddress.get(address);
- if (mBluetoothHeadsetService == null) {
+ if (mBluetoothHeadset == null) {
Log.w(this, "Attempting to turn on audio when the headset service is null");
return false;
}
- boolean success = mBluetoothAdapterProxy.setActiveDevice(device,
+ boolean success = mBluetoothAdapter.setActiveDevice(device,
BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
if (!success) {
Log.w(this, "Couldn't set active device to %s", address);
return false;
}
- if (!mBluetoothHeadsetService.isAudioOn()) {
- return mBluetoothHeadsetService.connectAudio();
+ if (!mBluetoothHeadset.isAudioOn()) {
+ return mBluetoothHeadset.connectAudio();
}
return true;
} else {
@@ -299,20 +299,20 @@
}
public void cacheHearingAidDevice() {
- if (mBluetoothHearingAidService != null) {
- for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
- if (device != null) {
- mBluetoothHearingAidActiveDeviceCache = device;
- }
- }
+ if (mBluetoothAdapter != null) {
+ for (BluetoothDevice device : mBluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID)) {
+ if (device != null) {
+ mBluetoothHearingAidActiveDeviceCache = device;
+ }
+ }
}
}
public void restoreHearingAidDevice() {
- if (mBluetoothHearingAidActiveDeviceCache != null && mBluetoothHearingAidService != null) {
- mBluetoothAdapterProxy.setActiveDevice(
- mBluetoothHearingAidActiveDeviceCache,
- BluetoothAdapter.ACTIVE_DEVICE_ALL);
+ if (mBluetoothHearingAidActiveDeviceCache != null) {
+ mBluetoothAdapter.setActiveDevice(mBluetoothHearingAidActiveDeviceCache,
+ BluetoothAdapter.ACTIVE_DEVICE_ALL);
mBluetoothHearingAidActiveDeviceCache = null;
}
}
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 7211990..81f4ab6 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -16,9 +16,11 @@
package com.android.server.telecom.bluetooth;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Message;
import android.telecom.Log;
@@ -30,7 +32,6 @@
import com.android.internal.util.IState;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import com.android.server.telecom.BluetoothHeadsetProxy;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
@@ -701,19 +702,28 @@
*/
@VisibleForTesting
public BluetoothDevice getBluetoothAudioConnectedDevice() {
- BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService();
- BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getHearingAidService();
+ BluetoothAdapter bluetoothAdapter = mDeviceManager.getBluetoothAdapter();
+ BluetoothHeadset bluetoothHeadset = mDeviceManager.getBluetoothHeadset();
+ BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getBluetoothHearingAid();
BluetoothDevice hfpAudioOnDevice = null;
BluetoothDevice hearingAidActiveDevice = null;
+ if (bluetoothAdapter == null) {
+ Log.i(this, "getBluetoothAudioConnectedDevice: no adapter available.");
+ return null;
+ }
if (bluetoothHeadset == null && bluetoothHearingAid == null) {
Log.i(this, "getBluetoothAudioConnectedDevice: no service available.");
return null;
}
if (bluetoothHeadset != null) {
- hfpAudioOnDevice = bluetoothHeadset.getActiveDevice();
+ for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEADSET)) {
+ hfpAudioOnDevice = device;
+ break;
+ }
if (bluetoothHeadset.getAudioState(hfpAudioOnDevice)
== BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
@@ -722,7 +732,8 @@
}
if (bluetoothHearingAid != null) {
- for (BluetoothDevice device : bluetoothHearingAid.getActiveDevices()) {
+ for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID)) {
if (device != null) {
hearingAidActiveDevice = device;
break;
@@ -751,7 +762,7 @@
*/
@VisibleForTesting
public boolean isInbandRingingEnabled() {
- BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService();
+ BluetoothHeadset bluetoothHeadset = mDeviceManager.getBluetoothHeadset();
if (bluetoothHeadset == null) {
Log.i(this, "isInbandRingingEnabled: no headset service available.");
return false;
diff --git a/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java b/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java
index daf6be0..36f2077 100644
--- a/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java
+++ b/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java
@@ -155,6 +155,7 @@
return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER;
case BlockedNumberContract.STATUS_BLOCKED_UNKNOWN_NUMBER:
+ case BlockedNumberContract.STATUS_BLOCKED_UNAVAILABLE:
return CallLog.Calls.BLOCK_REASON_UNKNOWN_NUMBER;
case BlockedNumberContract.STATUS_BLOCKED_RESTRICTED:
diff --git a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
index d95d578..84ce4d4 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
@@ -18,6 +18,7 @@
import android.provider.CallLog;
import android.provider.CallLog.Calls;
+import android.telecom.CallScreeningService;
import android.text.TextUtils;
import java.util.Objects;
@@ -34,6 +35,8 @@
private int mCallBlockReason = Calls.BLOCK_REASON_NOT_BLOCKED;
private CharSequence mCallScreeningAppName = null;
private String mCallScreeningComponentName = null;
+ private CallScreeningService.ParcelableCallResponse mCallScreeningResponse = null;
+ private boolean mIsResponseFromSystemDialer = false;
public Builder setShouldAllowCall(boolean shouldAllowCall) {
mShouldAllowCall = shouldAllowCall;
@@ -80,6 +83,13 @@
return this;
}
+ public Builder setCallScreeningResponse(
+ CallScreeningService.ParcelableCallResponse response, boolean isFromSystemDialer) {
+ mCallScreeningResponse = response;
+ mIsResponseFromSystemDialer = isFromSystemDialer;
+ return this;
+ }
+
public Builder setContactExists(boolean contactExists) {
mContactExists = contactExists;
return this;
@@ -96,14 +106,16 @@
.setShouldScreenViaAudio(result.shouldScreenViaAudio)
.setCallScreeningAppName(result.mCallScreeningAppName)
.setCallScreeningComponentName(result.mCallScreeningComponentName)
+ .setCallScreeningResponse(result.mCallScreeningResponse,
+ result.mIsResponseFromSystemDialer)
.setContactExists(result.contactExists);
}
public CallFilteringResult build() {
return new CallFilteringResult(mShouldAllowCall, mShouldReject, mShouldSilence,
mShouldAddToCallLog, mShouldShowNotification, mCallBlockReason,
- mCallScreeningAppName, mCallScreeningComponentName, mShouldScreenViaAudio,
- mContactExists);
+ mCallScreeningAppName, mCallScreeningComponentName, mCallScreeningResponse,
+ mIsResponseFromSystemDialer, mShouldScreenViaAudio, mContactExists);
}
}
@@ -116,11 +128,15 @@
public int mCallBlockReason;
public CharSequence mCallScreeningAppName;
public String mCallScreeningComponentName;
+ public CallScreeningService.ParcelableCallResponse mCallScreeningResponse;
+ public boolean mIsResponseFromSystemDialer;
public boolean contactExists;
private CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification, int
callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName,
+ CallScreeningService.ParcelableCallResponse callScreeningResponse,
+ boolean isResponseFromSystemDialer,
boolean shouldScreenViaAudio, boolean contactExists) {
this.shouldAllowCall = shouldAllowCall;
this.shouldReject = shouldReject;
@@ -131,6 +147,8 @@
this.mCallBlockReason = callBlockReason;
this.mCallScreeningAppName = callScreeningAppName;
this.mCallScreeningComponentName = callScreeningComponentName;
+ this.mCallScreeningResponse = callScreeningResponse;
+ this.mIsResponseFromSystemDialer = isResponseFromSystemDialer;
this.contactExists = contactExists;
}
@@ -148,25 +166,25 @@
if (isBlockedByProvider(mCallBlockReason)) {
return getCombinedCallFilteringResult(other, mCallBlockReason,
- null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
+ null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
} else if (isBlockedByProvider(other.mCallBlockReason)) {
return getCombinedCallFilteringResult(other, other.mCallBlockReason,
- null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
+ null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
}
if (mCallBlockReason == Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL
- || other.mCallBlockReason == Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL) {
+ || other.mCallBlockReason == Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL) {
return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL,
- null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
+ null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
}
if (shouldReject && mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE) {
return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
- mCallScreeningAppName, mCallScreeningComponentName);
+ mCallScreeningAppName, mCallScreeningComponentName);
} else if (other.shouldReject && other.mCallBlockReason == CallLog.Calls
- .BLOCK_REASON_CALL_SCREENING_SERVICE) {
+ .BLOCK_REASON_CALL_SCREENING_SERVICE) {
return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
- other.mCallScreeningAppName, other.mCallScreeningComponentName);
+ other.mCallScreeningAppName, other.mCallScreeningComponentName);
}
if (shouldScreenViaAudio) {
@@ -177,15 +195,16 @@
other.mCallScreeningAppName, other.mCallScreeningComponentName);
}
- return new Builder()
+ Builder b = new Builder()
.setShouldAllowCall(shouldAllowCall && other.shouldAllowCall)
.setShouldReject(shouldReject || other.shouldReject)
.setShouldSilence(shouldSilence || other.shouldSilence)
.setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
.setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
.setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
- .setContactExists(contactExists || other.contactExists)
- .build();
+ .setContactExists(contactExists || other.contactExists);
+ combineScreeningResponses(b, this, other);
+ return b.build();
}
private boolean isBlockedByProvider(int blockReason) {
@@ -201,8 +220,9 @@
}
private CallFilteringResult getCombinedCallFilteringResult(CallFilteringResult other,
- int callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName) {
- return new Builder()
+ int callBlockReason, CharSequence callScreeningAppName,
+ String callScreeningComponentName) {
+ Builder b = new Builder()
.setShouldAllowCall(shouldAllowCall && other.shouldAllowCall)
.setShouldReject(shouldReject || other.shouldReject)
.setShouldSilence(shouldSilence || other.shouldSilence)
@@ -212,10 +232,33 @@
.setCallBlockReason(callBlockReason)
.setCallScreeningAppName(callScreeningAppName)
.setCallScreeningComponentName(callScreeningComponentName)
- .setContactExists(contactExists || other.contactExists)
- .build();
+ .setContactExists(contactExists || other.contactExists);
+ combineScreeningResponses(b, this, other);
+ return b.build();
}
+ private static void combineScreeningResponses(Builder builder, CallFilteringResult r1,
+ CallFilteringResult r2) {
+ if (r1.mIsResponseFromSystemDialer) {
+ builder.setCallScreeningResponse(r1.mCallScreeningResponse, true);
+ builder.setCallScreeningComponentName(r1.mCallScreeningComponentName);
+ builder.setCallScreeningAppName(r1.mCallScreeningAppName);
+ } else if (r2.mIsResponseFromSystemDialer) {
+ builder.setCallScreeningResponse(r2.mCallScreeningResponse, true);
+ builder.setCallScreeningComponentName(r2.mCallScreeningComponentName);
+ builder.setCallScreeningAppName(r2.mCallScreeningAppName);
+ } else {
+ if (r1.mCallScreeningResponse != null) {
+ builder.setCallScreeningResponse(r1.mCallScreeningResponse, false);
+ builder.setCallScreeningComponentName(r1.mCallScreeningComponentName);
+ builder.setCallScreeningAppName(r1.mCallScreeningAppName);
+ } else {
+ builder.setCallScreeningResponse(r2.mCallScreeningResponse, false);
+ builder.setCallScreeningComponentName(r2.mCallScreeningComponentName);
+ builder.setCallScreeningAppName(r2.mCallScreeningAppName);
+ }
+ }
+ }
@Override
public boolean equals(Object o) {
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 486cd8d..4a308e0 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -25,6 +25,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.CallLog;
+import android.telecom.CallScreeningService;
import android.telecom.Log;
import android.telecom.TelecomManager;
@@ -64,15 +65,44 @@
}
@Override
- public void allowCall(String callId) {
- Long token = Binder.clearCallingIdentity();
+ public void onScreeningResponse(String callId, ComponentName componentName,
+ CallScreeningService.ParcelableCallResponse callResponse) {
+ if (callResponse == null) {
+ Log.w(this, "Null responses are only supposed to happen for outgoing calls");
+ return;
+ }
+ if (callResponse.shouldDisallowCall()) {
+ disallowCall(callId, componentName, callResponse);
+ } else if (callResponse.shouldSilenceCall()) {
+ silenceCall(callId, componentName, callResponse);
+ } else if (callResponse.shouldScreenCallViaAudioProcessing()) {
+ screenCallFurther(callId, componentName, callResponse);
+ } else {
+ allowCall(callId, componentName, callResponse);
+ }
+ }
+
+ public void allowCall(String callId, ComponentName componentName,
+ CallScreeningService.ParcelableCallResponse response) {
+ long token = Binder.clearCallingIdentity();
Log.startSession("NCSSF.aC");
try {
if (mCall == null || (!mCall.getId().equals(callId))) {
Log.w(this, "allowCall, unknown call id: %s", callId);
}
- Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, mPriorStageResult);
- mResultFuture.complete(mPriorStageResult);
+ CallFilteringResult result = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(false)
+ .setShouldAddToCallLog(mPriorStageResult.shouldAddToCallLog)
+ .setShouldShowNotification(mPriorStageResult.shouldShowNotification)
+ .setCallScreeningAppName(mAppName)
+ .setCallScreeningComponentName(componentName.flattenToString())
+ .setCallScreeningResponse(response, isSystemDialer())
+ .setContactExists(mPriorStageResult.contactExists)
+ .build();
+ Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
+ mResultFuture.complete(result);
} finally {
unbindCallScreeningService();
Binder.restoreCallingIdentity(token);
@@ -80,24 +110,23 @@
}
}
- @Override
- public void disallowCall(String callId, boolean shouldReject,
- boolean shouldAddToCallLog, boolean shouldShowNotification,
- ComponentName componentName) {
+ public void disallowCall(String callId, ComponentName componentName,
+ CallScreeningService.ParcelableCallResponse response) {
long token = Binder.clearCallingIdentity();
Log.startSession("NCSSF.dC");
try {
if (mCall != null && mCall.getId().equals(callId)) {
CallFilteringResult result = new CallFilteringResult.Builder()
.setShouldAllowCall(false)
- .setShouldReject(shouldReject)
+ .setShouldReject(response.shouldRejectCall())
.setShouldSilence(false)
- .setShouldAddToCallLog(shouldAddToCallLog
+ .setShouldAddToCallLog(!response.shouldSkipCallLog()
|| packageTypeShouldAdd(mPackagetype))
- .setShouldShowNotification(shouldShowNotification)
+ .setShouldShowNotification(!response.shouldSkipNotification())
.setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
.setCallScreeningAppName(mAppName)
.setCallScreeningComponentName(componentName.flattenToString())
+ .setCallScreeningResponse(response, isSystemDialer())
.setContactExists(mPriorStageResult.contactExists)
.build();
Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
@@ -113,8 +142,8 @@
}
}
- @Override
- public void silenceCall(String callId) {
+ public void silenceCall(String callId, ComponentName componentName,
+ CallScreeningService.ParcelableCallResponse response) {
long token = Binder.clearCallingIdentity();
Log.startSession("NCSSF.sC");
try {
@@ -125,6 +154,9 @@
.setShouldSilence(true)
.setShouldAddToCallLog(true)
.setShouldShowNotification(true)
+ .setCallScreeningResponse(response, isSystemDialer())
+ .setCallScreeningAppName(mAppName)
+ .setCallScreeningComponentName(componentName.flattenToString())
.setContactExists(mPriorStageResult.contactExists)
.build();
Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
@@ -140,8 +172,8 @@
}
}
- @Override
- public void screenCallFurther(String callId) {
+ public void screenCallFurther(String callId, ComponentName componentName,
+ CallScreeningService.ParcelableCallResponse response) {
if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
throw new SecurityException("Only the default/system dialer may request screen via"
+ "background call audio");
@@ -158,6 +190,8 @@
.setShouldSilence(false)
.setShouldScreenViaAudio(true)
.setCallScreeningAppName(mAppName)
+ .setCallScreeningComponentName(componentName.flattenToString())
+ .setCallScreeningResponse(response, isSystemDialer())
.setContactExists(mPriorStageResult.contactExists)
.build();
Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
index e3c68c9..9fa864e 100644
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
+++ b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
@@ -49,7 +49,7 @@
private final HandlerThread mHandlerThread;
private final TelecomSystem.SyncRoot mLock;
private List<CallFilter> mFiltersList;
- private CallFilter mDummyComplete;
+ private CallFilter mCompletionSentinel;
private boolean mFinished;
private CallFilteringResult mCurrentResult;
private Context mContext;
@@ -70,7 +70,7 @@
scheduleFilter(filter);
}
}
- if (mFilter.equals(mDummyComplete)) {
+ if (mFilter.equals(mCompletionSentinel)) {
synchronized (mLock) {
mFinished = true;
mListener.onCallFilteringComplete(mCall, result, false);
@@ -105,15 +105,15 @@
public void performFiltering() {
Log.addEvent(mCall, LogUtils.Events.FILTERING_INITIATED);
CallFilter dummyStart = new CallFilter();
- mDummyComplete = new CallFilter();
+ mCompletionSentinel = new CallFilter();
for (CallFilter filter : mFiltersList) {
addEdge(dummyStart, filter);
}
for (CallFilter filter : mFiltersList) {
- addEdge(filter, mDummyComplete);
+ addEdge(filter, mCompletionSentinel);
}
- addEdge(dummyStart, mDummyComplete);
+ addEdge(dummyStart, mCompletionSentinel);
scheduleFilter(dummyStart);
mHandler.postDelayed(new Runnable("ICFG.pF", mLock) {
@@ -159,7 +159,11 @@
startFuture.thenComposeAsync(filter::startFilterLookup,
new LoggedHandlerExecutor(mHandler, "ICFG.sF", null))
.thenApplyAsync(postFilterTask::whenDone,
- new LoggedHandlerExecutor(mHandler, "ICFG.sF", null));
+ new LoggedHandlerExecutor(mHandler, "ICFG.sF", null))
+ .exceptionally((t) -> {
+ Log.e(filter, t, "Encountered exception running filter");
+ return null;
+ });
Log.i(TAG, "Filter %s scheduled.", filter);
}
diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
index e93ef22..adeb311 100644
--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
+++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
@@ -124,6 +124,17 @@
}
}
+ public void notifyTimeout() {
+ if (mService != null) {
+ try {
+ mService.notifyTimeout();
+ } catch (RemoteException e) {
+ Log.e(this, e, "Failed to notify call redirection timed out to "
+ + mServiceType + " call redirection service");
+ }
+ }
+ }
+
private class CallRedirectionServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
@@ -294,7 +305,7 @@
* The current rule to decide whether the implemented {@link CallRedirectionService} should
* allow interactive responses with users is only based on whether it is in car mode.
*/
- mAllowInteractiveResponse = !callsManager.getSystemStateHelper().isCarMode();
+ mAllowInteractiveResponse = !callsManager.getSystemStateHelper().isCarModeOrProjectionActive();
mCallRedirectionProcessorHelper = new CallRedirectionProcessorHelper(
context, callsManager, phoneAccountRegistrar);
mProcessedDestinationUri = mCallRedirectionProcessorHelper.formatNumberForRedirection(
@@ -394,6 +405,7 @@
Log.addEvent(mCall, serviceType.equals(SERVICE_TYPE_USER_DEFINED)
? LogUtils.Events.REDIRECTION_TIMED_OUT_USER
: LogUtils.Events.REDIRECTION_TIMED_OUT_CARRIER);
+ mAttempt.notifyTimeout();
if (serviceType.equals(SERVICE_TYPE_USER_DEFINED)) {
mUiAction = UI_TYPE_USER_DEFINED_TIMEOUT;
mShouldCancelCall = true;
diff --git a/src/com/android/server/telecom/components/ErrorDialogActivity.java b/src/com/android/server/telecom/components/ErrorDialogActivity.java
index 1bdcdf2..3618b77 100644
--- a/src/com/android/server/telecom/components/ErrorDialogActivity.java
+++ b/src/com/android/server/telecom/components/ErrorDialogActivity.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.components;
+import com.android.server.telecom.FrameworksUtils;
import com.android.server.telecom.R;
import android.app.Activity;
@@ -84,7 +85,7 @@
}
};
- final AlertDialog errorDialog = new AlertDialog.Builder(this)
+ final AlertDialog errorDialog = FrameworksUtils.makeAlertDialogBuilder(this)
.setMessage(msg).setPositiveButton(android.R.string.ok, clickListener)
.setOnCancelListener(cancelListener).create();
@@ -97,7 +98,7 @@
}
private void showMissingVoicemailErrorDialog() {
- new AlertDialog.Builder(this)
+ FrameworksUtils.makeAlertDialogBuilder(this)
.setTitle(R.string.no_vm_number)
.setMessage(R.string.no_vm_number_msg)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
index 1fe7c5f..036fb91 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.ActionBar;
import android.app.AlertDialog;
-import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -35,14 +34,13 @@
import android.database.Cursor;
import android.os.Bundle;
import android.provider.BlockedNumberContract;
-import android.provider.ContactsContract;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.Editable;
-import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -56,6 +54,7 @@
import android.widget.TextView;
import android.widget.Toast;
+import com.android.server.telecom.FrameworksUtils;
import com.android.server.telecom.R;
@@ -247,7 +246,7 @@
final EditText editText = (EditText) dialogView.findViewById(R.id.add_blocked_number);
editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
editText.addTextChangedListener(this);
- AlertDialog dialog = new AlertDialog.Builder(this)
+ AlertDialog dialog = FrameworksUtils.makeAlertDialogBuilder(this)
.setView(dialogView)
.setPositiveButton(R.string.block_button, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
index df68f6e..333e451 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
@@ -29,6 +29,7 @@
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
+import com.android.server.telecom.FrameworksUtils;
import com.android.server.telecom.R;
public class BlockedNumbersAdapter extends SimpleCursorAdapter {
@@ -72,7 +73,7 @@
Spannable messageSpannable = new SpannableString(message);
PhoneNumberUtils.addTtsSpan(messageSpannable, startingPosition,
startingPosition + formattedNumber.length());
- AlertDialog dialog = new AlertDialog.Builder(context)
+ AlertDialog dialog = FrameworksUtils.makeAlertDialogBuilder(context)
.setMessage(messageSpannable)
.setPositiveButton(R.string.unblock_button,
new DialogInterface.OnClickListener() {
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
index 67634e4..4be75f8 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
@@ -95,7 +95,8 @@
if (showNotification) {
Intent intent = new Intent(context, CallBlockDisabledActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
- context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT
+ | PendingIntent.FLAG_IMMUTABLE);
String title = context.getString(
R.string.phone_strings_call_blocking_turned_off_notification_title_txt);
diff --git a/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java b/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java
index 5f42b37..232546b 100644
--- a/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java
+++ b/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.provider.BlockedNumberContract;
+import com.android.server.telecom.FrameworksUtils;
import com.android.server.telecom.R;
/**
@@ -50,7 +51,7 @@
return;
}
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ AlertDialog.Builder builder = FrameworksUtils.makeAlertDialogBuilder(this);
mDialog = builder
.setTitle(R.string.phone_strings_emergency_call_made_dialog_title_txt)
.setMessage(R.string
diff --git a/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java b/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java
index ecc019f..c0bb56a 100644
--- a/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java
+++ b/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java
@@ -42,6 +42,8 @@
"block_private_number_calls_setting";
private static final String BLOCK_UNKNOWN_NUMBERS_KEY =
"block_unknown_calls_setting";
+ private static final String BLOCK_UNAVAILABLE_NUMBERS_KEY =
+ "block_unavailable_calls_setting";
private boolean mIsCombiningRestrictedAndUnknownOption = false;
@Override
@@ -55,6 +57,7 @@
setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE);
setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE);
setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN);
+ setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE);
if (!showPayPhoneBlocking()) {
Preference payPhoneOption = getPreferenceScreen().findPreference(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE);
getPreferenceScreen().removePreference(payPhoneOption);
@@ -90,8 +93,10 @@
mIsCombiningRestrictedAndUnknownOption = getResources().getBoolean(
R.bool.combine_options_to_block_restricted_and_unknown_callers);
if (mIsCombiningRestrictedAndUnknownOption) {
- Preference pref = findPreference(BLOCK_RESTRICTED_NUMBERS_KEY);
- screen.removePreference(pref);
+ Preference restricted_pref = findPreference(BLOCK_RESTRICTED_NUMBERS_KEY);
+ Preference unavailable_pref = findPreference(BLOCK_UNAVAILABLE_NUMBERS_KEY);
+ screen.removePreference(restricted_pref);
+ screen.removePreference(unavailable_pref);
Log.i(this, "onCreate: removed block restricted preference.");
}
}
@@ -116,6 +121,7 @@
updateEnhancedBlockPref(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE);
}
updateEnhancedBlockPref(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN);
+ updateEnhancedBlockPref(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE);
}
/**
@@ -136,6 +142,8 @@
preference.getKey(), BLOCK_RESTRICTED_NUMBERS_KEY, (boolean) objValue);
BlockedNumbersUtil.setEnhancedBlockSetting(getActivity(), BLOCK_RESTRICTED_NUMBERS_KEY,
(boolean) objValue);
+ BlockedNumbersUtil.setEnhancedBlockSetting(getActivity(),
+ BLOCK_UNAVAILABLE_NUMBERS_KEY, (boolean) objValue);
}
BlockedNumbersUtil.setEnhancedBlockSetting(getActivity(), preference.getKey(),
(boolean) objValue);
diff --git a/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java b/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java
index 5aa80c6..b5c850e 100644
--- a/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java
+++ b/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.ui;
+import com.android.server.telecom.FrameworksUtils;
import com.android.server.telecom.R;
import android.app.Activity;
@@ -45,7 +46,7 @@
Log.i(this, "showDialog: timeout redirection with %s", redirectionAppName);
CharSequence message = getString(
R.string.alert_redirect_outgoing_call_timeout, redirectionAppName);
- final AlertDialog errorDialog = new AlertDialog.Builder(this)
+ final AlertDialog errorDialog = FrameworksUtils.makeAlertDialogBuilder(this)
.setMessage(message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
diff --git a/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java b/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
index 4735e3c..e9f99b6 100644
--- a/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
+++ b/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.ui;
+import com.android.server.telecom.FrameworksUtils;
import com.android.server.telecom.R;
import com.android.server.telecom.TelecomBroadcastIntentProcessor;
import com.android.server.telecom.components.TelecomBroadcastReceiver;
@@ -48,7 +49,7 @@
private void showDialog(final String callId, CharSequence ongoingAppName) {
Log.i(this, "showDialog: confirming callId=%s, ongoing=%s", callId, ongoingAppName);
CharSequence message = getString(R.string.alert_outgoing_call, ongoingAppName);
- final AlertDialog errorDialog = new AlertDialog.Builder(this)
+ final AlertDialog errorDialog = FrameworksUtils.makeAlertDialogBuilder(this)
.setMessage(message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
diff --git a/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java b/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java
index 3f54689..66f9fe4 100644
--- a/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java
+++ b/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java
@@ -333,7 +333,8 @@
UserHandle userHandle) {
Intent intent = new Intent(action, data, mContext, TelecomBroadcastReceiver.class);
intent.putExtra(TelecomBroadcastIntentProcessor.EXTRA_USERHANDLE, userHandle);
- return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
private boolean canRespondViaSms(@NonNull CallInfo call) {
@@ -354,7 +355,7 @@
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(mContext);
taskStackBuilder.addNextIntent(intent);
- return taskStackBuilder.getPendingIntent(0, 0, null, userHandle);
+ return taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_IMMUTABLE, null, userHandle);
}
/**
diff --git a/src/com/android/server/telecom/ui/IncomingCallNotifier.java b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
index edea89b..0c1c5a3 100644
--- a/src/com/android/server/telecom/ui/IncomingCallNotifier.java
+++ b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
@@ -282,12 +282,12 @@
R.anim.on_going_call,
getActionText(R.string.answer_incoming_call, R.color.notification_action_answer),
PendingIntent.getBroadcast(mContext, 0, answerIntent,
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE));
builder.addAction(
R.drawable.ic_close_dk,
getActionText(R.string.decline_incoming_call, R.color.notification_action_decline),
PendingIntent.getBroadcast(mContext, 0, rejectIntent,
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE));
return builder;
}
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 4e32c9f..12d3820 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -67,18 +67,15 @@
import android.text.TextUtils;
import android.telecom.CallerInfo;
+import android.util.ArrayMap;
import java.lang.Override;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-// TODO: Needed for move to system service: import com.android.internal.R;
/**
* Creates a notification for calls that the user missed (neither answered nor rejected).
@@ -139,8 +136,10 @@
private final DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
private UserHandle mCurrentUserHandle;
+ // Used to guard access to mMissedCallCounts
+ private final Object mMissedCallCountsLock = new Object();
// Used to track the number of missed calls.
- private ConcurrentMap<UserHandle, AtomicInteger> mMissedCallCounts;
+ private final Map<UserHandle, Integer> mMissedCallCounts;
private List<UserHandle> mUsersToLoadAfterBootComplete = new ArrayList<>();
@@ -164,7 +163,7 @@
mDefaultDialerCache = defaultDialerCache;
mNotificationBuilderFactory = notificationBuilderFactory;
- mMissedCallCounts = new ConcurrentHashMap<>();
+ mMissedCallCounts = new ArrayMap<>();
}
/** Clears missed call notification and marks the call log's missed calls as read. */
@@ -263,17 +262,16 @@
}
private void sendNotificationThroughDefaultDialer(String dialerPackage, CallInfo callInfo,
- UserHandle userHandle) {
- int count = mMissedCallCounts.get(userHandle).get();
+ UserHandle userHandle, int missedCallCount) {
Intent intent = getShowMissedCallIntentForDefaultDialer(dialerPackage)
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT,
createClearMissedCallsPendingIntent(userHandle))
- .putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, count)
+ .putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, missedCallCount)
.putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER,
callInfo == null ? null : callInfo.getPhoneNumber());
- if (count == 1 && callInfo != null) {
+ if (missedCallCount == 1 && callInfo != null) {
final Uri handleUri = callInfo.getHandle();
String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart();
@@ -284,8 +282,8 @@
}
}
-
- Log.w(this, "Showing missed calls through default dialer.");
+ Log.i(this, "sendNotificationThroughDefaultDialer; count=%d, dialerPackage=%s",
+ missedCallCount, intent.getPackage());
Bundle options = exemptFromPowerSavingTemporarily(dialerPackage, userHandle);
mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE, options);
}
@@ -293,7 +291,7 @@
/**
* Create a system notification for the missed call.
*
- * @param call The missed call.
+ * @param callInfo The missed call.
*/
@Override
public void showMissedCallNotification(@NonNull CallInfo callInfo) {
@@ -311,13 +309,21 @@
}
private void showMissedCallNotification(@NonNull CallInfo callInfo, UserHandle userHandle) {
- Log.i(this, "showMissedCallNotification: userHandle=%d", userHandle.getIdentifier());
- mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0));
- int missCallCounts = mMissedCallCounts.get(userHandle).incrementAndGet();
+ int missedCallCounts;
+ synchronized (mMissedCallCountsLock) {
+ Integer currentCount = mMissedCallCounts.get(userHandle);
+ missedCallCounts = currentCount == null ? 0 : currentCount;
+ missedCallCounts++;
+ mMissedCallCounts.put(userHandle, missedCallCounts);
+ }
+
+ Log.i(this, "showMissedCallNotification: userHandle=%d, missedCallCount=%d",
+ userHandle.getIdentifier(), missedCallCounts);
String dialerPackage = getDefaultDialerPackage(userHandle);
if (shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
- sendNotificationThroughDefaultDialer(dialerPackage, callInfo, userHandle);
+ sendNotificationThroughDefaultDialer(dialerPackage, callInfo, userHandle,
+ missedCallCounts);
return;
}
@@ -327,7 +333,7 @@
// Display the first line of the notification:
// 1 missed call: <caller name || handle>
// More than 1 missed call: <number of calls> + "missed calls"
- if (missCallCounts == 1) {
+ if (missedCallCounts == 1) {
expandedText = getNameForMissedCallNotification(callInfo);
CallerInfo ci = callInfo.getCallerInfo();
@@ -339,7 +345,7 @@
} else {
titleResId = R.string.notification_missedCallsTitle;
expandedText =
- mContext.getString(R.string.notification_missedCallsMsg, missCallCounts);
+ mContext.getString(R.string.notification_missedCallsMsg, missedCallCounts);
}
// Create a public viewable version of the notification, suitable for display when sensitive
@@ -381,7 +387,7 @@
String handle = callInfo.getHandleSchemeSpecificPart();
// Add additional actions when there is only 1 missed call, like call-back and SMS.
- if (missCallCounts == 1) {
+ if (missedCallCounts == 1) {
Log.d(this, "Add actions with number %s.", Log.piiHandle(handle));
if (!TextUtils.isEmpty(handle)
@@ -410,7 +416,7 @@
}
} else {
Log.d(this, "Suppress actions. handle: %s, missedCalls: %d.", Log.piiHandle(handle),
- missCallCounts);
+ missedCallCounts);
}
Notification notification = builder.build();
@@ -430,12 +436,14 @@
/** Cancels the "missed call" notification. */
private void cancelMissedCallNotification(UserHandle userHandle) {
// Reset the number of missed calls to 0.
- mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0));
- mMissedCallCounts.get(userHandle).set(0);
+ synchronized(mMissedCallCountsLock) {
+ mMissedCallCounts.put(userHandle, 0);
+ }
String dialerPackage = getDefaultDialerPackage(userHandle);
if (shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
- sendNotificationThroughDefaultDialer(dialerPackage, null, userHandle);
+ sendNotificationThroughDefaultDialer(dialerPackage, null, userHandle,
+ 0 /* missedCallCount */);
return;
}
@@ -612,7 +620,9 @@
Log.d(MissedCallNotifierImpl.this, "onQueryComplete()...");
if (cursor != null) {
try {
- mMissedCallCounts.remove(userHandle);
+ synchronized(mMissedCallCountsLock) {
+ mMissedCallCounts.remove(userHandle);
+ }
while (cursor.moveToNext()) {
// Get data about the missed call from the cursor
final String handleString = cursor.getString(CALL_LOG_COLUMN_NUMBER);
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 891a7a7..dd8258a 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -39,6 +39,13 @@
<uses-library android:name="android.test.runner"/>
<!-- Miscellaneous telecom app-related test activities. -->
+ <service android:name="com.android.server.telecom.testapps.TestCallDiagnosticService"
+ android:permission="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telecom.CallDiagnosticService"/>
+ </intent-filter>
+ </service>
<service android:name="com.android.server.telecom.testapps.TestConnectionService"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
diff --git a/testapps/callaudiotest/Android.bp b/testapps/callaudiotest/Android.bp
new file mode 100644
index 0000000..81164e6
--- /dev/null
+++ b/testapps/callaudiotest/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "TelecomCallAudioTestApp",
+ static_libs: [
+ "androidx.legacy_legacy-support-v4",
+ "guava",
+ ],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+}
diff --git a/testapps/callaudiotest/AndroidManifest.xml b/testapps/callaudiotest/AndroidManifest.xml
new file mode 100644
index 0000000..014ab29
--- /dev/null
+++ b/testapps/callaudiotest/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ coreApp="true"
+ package="com.android.server.telecom.callaudiotest">
+
+ <uses-sdk android:minSdkVersion="28"
+ android:targetSdkVersion="29"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.CALL_PHONE"/>
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+
+ <application android:label="Telecom Call Audio Test">
+ <uses-library android:name="android.test.runner"/>
+
+ <service android:name="com.android.server.telecom.callaudiotest.CallAudioTestInCallService"
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:exported="true">
+ <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+ android:value="false"/>
+ <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+ android:value="false"/>
+ <intent-filter>
+ <action android:name="android.telecom.InCallService"/>
+ </intent-filter>
+ </service>
+
+ <activity android:name="com.android.server.telecom.callaudiotest.CallAudioTestActivity"
+ android:label="Call Audio Test"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/testapps/callaudiotest/res/layout/call_audio_test_activity.xml b/testapps/callaudiotest/res/layout/call_audio_test_activity.xml
new file mode 100644
index 0000000..0d847f0
--- /dev/null
+++ b/testapps/callaudiotest/res/layout/call_audio_test_activity.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/appLabel"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="25dp"
+ android:text="Call Audio Testing" />
+ <TextView
+ android:id="@+id/appDescription"
+ android:layout_gravity="left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="12dp"
+ android:text="You can enabled auto answer and calls will be answered and some awesome audio will be looped to the caller." />
+ <CheckBox
+ android:id="@+id/enableAutoAnswer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Answer calls and loop audio" />
+</LinearLayout>
diff --git a/testapps/callaudiotest/res/raw/speech.m4a b/testapps/callaudiotest/res/raw/speech.m4a
new file mode 100644
index 0000000..4161ad6
--- /dev/null
+++ b/testapps/callaudiotest/res/raw/speech.m4a
Binary files differ
diff --git a/testapps/callaudiotest/src/com/android/server/telecom/callaudiotest/CallAudioTestActivity.java b/testapps/callaudiotest/src/com/android/server/telecom/callaudiotest/CallAudioTestActivity.java
new file mode 100644
index 0000000..b75a498
--- /dev/null
+++ b/testapps/callaudiotest/src/com/android/server/telecom/callaudiotest/CallAudioTestActivity.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 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.callaudiotest;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+
+/**
+ * Activity to configure the auto answer behavior.
+ */
+public class CallAudioTestActivity extends Activity {
+ private static final int RESULT_PICK_FILE = 1;
+ public static final String AUDIO_TEST_PREFS = "audio_test_prefs";
+ public static final String AUTO_ANSWER_ENABLED = "auto_answer_enabled";
+ private CheckBox mEnable;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.call_audio_test_activity);
+ mEnable = findViewById(R.id.enableAutoAnswer);
+ mEnable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ SharedPreferences prefs = getSharedPreferences(AUDIO_TEST_PREFS, MODE_PRIVATE);
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putBoolean(AUTO_ANSWER_ENABLED, isChecked);
+ edit.apply();
+ }
+ });
+ loadPreferences();
+ }
+
+ private void loadPreferences() {
+ SharedPreferences prefs = getSharedPreferences(AUDIO_TEST_PREFS, MODE_PRIVATE);
+ mEnable.setChecked(prefs.getBoolean(AUTO_ANSWER_ENABLED, false));
+ }
+}
diff --git a/testapps/callaudiotest/src/com/android/server/telecom/callaudiotest/CallAudioTestInCallService.java b/testapps/callaudiotest/src/com/android/server/telecom/callaudiotest/CallAudioTestInCallService.java
new file mode 100644
index 0000000..bd98a7f
--- /dev/null
+++ b/testapps/callaudiotest/src/com/android/server/telecom/callaudiotest/CallAudioTestInCallService.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 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.callaudiotest;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.IBinder;
+import android.telecom.Call;
+import android.telecom.InCallService;
+import android.telecom.Log;
+import android.telecom.VideoProfile;
+
+import java.io.IOException;
+import java.lang.String;
+
+/**
+ * Simple test InCallService which answers a call automatically and plays back some looping audio.
+ * Intended for testing call audio between devices.
+ */
+public class CallAudioTestInCallService extends InCallService {
+ private Call mIncomingCall;
+ private boolean mIsAutoAnswerEnabled = false;
+ private MediaPlayer mMediaPlayer;
+ private Call.Callback mCallback = new Call.Callback() {
+ @Override
+ public void onStateChanged(Call call, int state) {
+ if (state == Call.STATE_ACTIVE) {
+ startPlaying();
+ }
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ SharedPreferences prefs = getSharedPreferences(CallAudioTestActivity.AUDIO_TEST_PREFS,
+ MODE_PRIVATE);
+ mIsAutoAnswerEnabled = prefs.getBoolean(CallAudioTestActivity.AUTO_ANSWER_ENABLED, false);
+ return super.onBind(intent);
+ }
+
+ @Override
+ public void onCallAdded(Call call) {
+ if (!mIsAutoAnswerEnabled) {
+ Log.i(this, "onCallAdded - autoanswer disabled, skip");
+ return;
+ }
+ if (call.getDetails().getState() == Call.STATE_RINGING) {
+ mIncomingCall = call;
+ mIncomingCall.registerCallback(mCallback);
+ mIncomingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
+
+ Log.i(this, "onCallAdded - ringing call");
+ } else {
+ Log.i(this, "onCallAdded - nonringing call");
+ }
+ }
+
+ @Override
+ public void onCallRemoved(Call call) {
+ if (mIncomingCall == call) {
+ mIncomingCall = null;
+ if (mMediaPlayer != null) {
+ mMediaPlayer.stop();
+ mMediaPlayer.release();
+ }
+ }
+ }
+
+ private void startPlaying() {
+ AudioDeviceInfo telephonyDevice = getTelephonyDevice(getSystemService(AudioManager.class));
+ if (telephonyDevice != null) {
+ Log.i(this, "startPlaying: create player for speech");
+ mMediaPlayer = new MediaPlayer();
+ mMediaPlayer.setOnCompletionListener(mediaPlayer -> Log.w(this, "startPlaying: done"));
+ mMediaPlayer.setOnErrorListener(
+ (mediaPlayer, what, extra) -> {
+ Log.w(this, "startPlaying: playback failed!");
+ return true; // Error handled
+ });
+ mMediaPlayer.setLooping(true);
+ mMediaPlayer.setVolume(1.0f);
+ AudioAttributes audioAttributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();
+ mMediaPlayer.setAudioAttributes(audioAttributes);
+ try {
+ mMediaPlayer.setDataSource(getResources().openRawResourceFd(R.raw.speech));
+ mMediaPlayer.prepare();
+ } catch (IOException e) {
+ mMediaPlayer.release();
+ throw new IllegalStateException(e);
+ }
+ if (!mMediaPlayer.setPreferredDevice(telephonyDevice)) {
+ Log.w(this, "startPlaying: setPreferredDevice failed");
+ }
+ mMediaPlayer.start();
+
+ }
+ }
+
+ private AudioDeviceInfo getTelephonyDevice(AudioManager audioManager) {
+ AudioDeviceInfo[] deviceList = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ for (AudioDeviceInfo device: deviceList) {
+ if (device.getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
+ return device;
+ }
+ }
+ return null;
+ }
+}
diff --git a/testapps/companionapp/Android.bp b/testapps/companionapp/Android.bp
new file mode 100644
index 0000000..8718b37
--- /dev/null
+++ b/testapps/companionapp/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2019 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "TelecomCompanionApp",
+ static_libs: [
+ "androidx.legacy_legacy-support-v4",
+ "guava",
+ ],
+ srcs: ["src/**/*.java"],
+}
diff --git a/testapps/companionapp/AndroidManifest.xml b/testapps/companionapp/AndroidManifest.xml
new file mode 100644
index 0000000..7569d8f
--- /dev/null
+++ b/testapps/companionapp/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ coreApp="true"
+ package="com.android.server.telecom.companionapp">
+
+ <uses-sdk android:minSdkVersion="28"
+ android:targetSdkVersion="29"/>
+
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.MANAGE_ONGOING_CALLS" />
+ <uses-feature android:name="android.software.companion_device_setup"/>
+
+ <application android:label="Telecom Companion">
+ <uses-library android:name="android.test.runner"/>
+
+ <activity android:name="com.android.server.telecom.companionapp.CompanionTestApp"
+ android:label="CompanionTestApp">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service android:name="com.android.server.telecom.companionapp.CompanionInCallServiceImpl"
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telecom.InCallService"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/testapps/companionapp/res/drawable-hdpi/ic_android_black_24dp.png b/testapps/companionapp/res/drawable-hdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..ed3ee45
--- /dev/null
+++ b/testapps/companionapp/res/drawable-hdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/companionapp/res/drawable-mdpi/ic_android_black_24dp.png b/testapps/companionapp/res/drawable-mdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..a4add51
--- /dev/null
+++ b/testapps/companionapp/res/drawable-mdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/companionapp/res/drawable-xhdpi/ic_android_black_24dp.png b/testapps/companionapp/res/drawable-xhdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..41558f2
--- /dev/null
+++ b/testapps/companionapp/res/drawable-xhdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/companionapp/res/drawable-xxhdpi/ic_android_black_24dp.png b/testapps/companionapp/res/drawable-xxhdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..6006b12
--- /dev/null
+++ b/testapps/companionapp/res/drawable-xxhdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/companionapp/res/drawable-xxxhdpi/ic_android_black_24dp.png b/testapps/companionapp/res/drawable-xxxhdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..4f935bf
--- /dev/null
+++ b/testapps/companionapp/res/drawable-xxxhdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/companionapp/res/layout/main.xml b/testapps/companionapp/res/layout/main.xml
new file mode 100644
index 0000000..e553754
--- /dev/null
+++ b/testapps/companionapp/res/layout/main.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="This is a test app for companion in call service."
+ android:padding="10dp"
+ android:textColor="#FFFFFF"/>
+ <Button
+ android:id="@+id/buttonStart"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Start Association"/>
+ <Button
+ android:id="@+id/buttonStop"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Stop Association"/>
+</LinearLayout>
diff --git a/testapps/companionapp/src/com/android/server/telecom/companionapp/CompanionInCallServiceImpl.java b/testapps/companionapp/src/com/android/server/telecom/companionapp/CompanionInCallServiceImpl.java
new file mode 100644
index 0000000..890cd77
--- /dev/null
+++ b/testapps/companionapp/src/com/android/server/telecom/companionapp/CompanionInCallServiceImpl.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 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.companionapp;
+
+import android.content.Intent;
+import android.telecom.Call;
+import android.telecom.InCallService;
+import android.telecom.Phone;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.lang.Override;
+import java.lang.String;
+
+/**
+ * Test Companion In-Call service implementation.
+ */
+public class CompanionInCallServiceImpl extends InCallService {
+ private static final String TAG = "CompanionInCallServiceImpl";
+
+ private Phone mPhone;
+
+ private Phone.Listener mPhoneListener = new Phone.Listener() {
+ @Override
+ public void onCallAdded(Phone phone, Call call) {
+ Log.i(TAG, "onCallAdded: " + call.toString());
+ Toast.makeText(
+ CompanionInCallServiceImpl.this, "onCallAdded", Toast.LENGTH_LONG).show();
+ }
+
+ @Override
+ public void onCallRemoved(Phone phone, Call call) {
+ Log.i(TAG, "onCallRemoved: " + call.toString());
+ Toast.makeText(
+ CompanionInCallServiceImpl.this, "onCallRemoved", Toast.LENGTH_LONG).show();
+ }
+ };
+
+ @Override
+ public void onPhoneCreated(Phone phone) {
+ Log.i(TAG, "onPhoneCreated");
+ mPhone = phone;
+ mPhone.addListener(mPhoneListener);
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i(TAG, "Companion TestApp InCallService unbind");
+ mPhone.removeListener(mPhoneListener);
+ mPhone = null;
+ return super.onUnbind(intent);
+ }
+
+ /**
+ * Used to bind a call
+ * @param intent
+ * @return
+ */
+ @Override
+ public android.os.IBinder onBind(Intent intent) {
+ Log.d(TAG, "Companion TestApp InCallService bind");
+ return super.onBind(intent);
+ }
+}
diff --git a/testapps/companionapp/src/com/android/server/telecom/companionapp/CompanionTestApp.java b/testapps/companionapp/src/com/android/server/telecom/companionapp/CompanionTestApp.java
new file mode 100644
index 0000000..7ed1e1e
--- /dev/null
+++ b/testapps/companionapp/src/com/android/server/telecom/companionapp/CompanionTestApp.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 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.companionapp;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothDevice;
+import android.companion.AssociationRequest;
+import android.companion.BluetoothDeviceFilter;
+import android.companion.CompanionDeviceManager;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.os.ParcelUuid;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+/**
+ * Companion Test App in Telecom
+ */
+public class CompanionTestApp extends Activity {
+
+ private static String logtag = "CompanionTestApp";
+ private CompanionDeviceManager mDeviceManager;
+ private AssociationRequest mPairingRequest;
+ private BluetoothDeviceFilter mDeviceFilter;
+
+ private static final int SELECT_DEVICE_REQUEST_CODE = 42;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ setupDeviceAssociation();
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ Button buttonStart = (Button)findViewById(R.id.buttonStart);
+ buttonStart.setOnClickListener(startListener);
+
+ Button buttonStop = (Button)findViewById(R.id.buttonStop);
+ buttonStop.setOnClickListener(stopListener);
+ }
+
+ private OnClickListener startListener = new OnClickListener() {
+ public void onClick(View v) {
+ Log.d(logtag,"onClick() called - start button");
+ Toast.makeText(CompanionTestApp.this, "Start Association", Toast.LENGTH_LONG).show();
+ assosicate();
+ Log.d(logtag,"onClick() ended - start button");
+ }
+ };
+
+ private OnClickListener stopListener = new OnClickListener() {
+ public void onClick(View v) {
+ Log.d(logtag,"onClick() called - stop button");
+ Toast.makeText(CompanionTestApp.this, "Stop Association", Toast.LENGTH_LONG).show();
+ disassosicate();
+ Log.d(logtag,"onClick() ended - stop button");
+ }
+ };
+
+ // Setup Device Association Preparation, per
+ // https://developer.android.com/guide/topics/connectivity/companion-device-pairing
+ private void setupDeviceAssociation() {
+ mDeviceManager = getSystemService(CompanionDeviceManager.class);
+
+ mDeviceFilter = new BluetoothDeviceFilter.Builder()
+ .build();
+
+ mPairingRequest = new AssociationRequest.Builder()
+ .addDeviceFilter(mDeviceFilter)
+ .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
+ .build();
+
+ }
+
+ // Associate bluetooth device, per
+ // https://developer.android.com/guide/topics/connectivity/companion-device-pairing
+ private void assosicate() {
+ // When the app tries to pair with the Bluetooth device, show the
+ // appropriate pairing request dialog to the user.
+ mDeviceManager.associate(mPairingRequest,
+ new CompanionDeviceManager.Callback() {
+ @Override
+ public void onDeviceFound(IntentSender chooserLauncher) {
+ try {
+ startIntentSenderForResult(chooserLauncher,
+ SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0);
+ } catch (Exception ex) {
+ Log.d(logtag, "Callback onDeviceFound() Exception: " + ex);
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence error) {
+ Log.d(logtag, "Callback onFailure() called - error: " + error);
+ }
+ },
+ null);
+ }
+
+ // Disassociate the associated bluetooth device
+ private void disassosicate() {
+ for (String macAddress : mDeviceManager.getAssociations()) {
+ mDeviceManager.disassociate(macAddress);
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == SELECT_DEVICE_REQUEST_CODE &&
+ resultCode == Activity.RESULT_OK) {
+ // User has chosen to pair with the Bluetooth device.
+ BluetoothDevice deviceToPair =
+ data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE);
+ deviceToPair.createBond();
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ Log.d(logtag,"onStart() called");
+ super.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ Log.d(logtag,"onResume() called");
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ Log.d(logtag,"onPause() called");
+ super.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ Log.d(logtag,"onStop() called");
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.d(logtag,"onDestroy() called");
+ super.onDestroy();
+ }
+}
diff --git a/testapps/res/layout/incall_screen.xml b/testapps/res/layout/incall_screen.xml
index f8f919b..22d3574 100644
--- a/testapps/res/layout/incall_screen.xml
+++ b/testapps/res/layout/incall_screen.xml
@@ -131,6 +131,11 @@
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"/>
</LinearLayout>
+ <TextView
+ android:id="@+id/incoming_composer_attachments"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"/>
<Button
android:id="@+id/disable_incallservice"
android:layout_width="wrap_content"
diff --git a/testapps/res/layout/testdialer_main.xml b/testapps/res/layout/testdialer_main.xml
index 3f397b8..749d236 100644
--- a/testapps/res/layout/testdialer_main.xml
+++ b/testapps/res/layout/testdialer_main.xml
@@ -59,6 +59,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/startCallWithRtt"/>
+ <CheckBox
+ android:id="@+id/add_composer_attachments_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/addComposerAttachments"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index 7331d5a..b1a1f80 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -44,6 +44,8 @@
<string name="startCallWithRtt">Start call with RTT</string>
+ <string name="addComposerAttachments">Add call composer attachments</string>
+
<string name="rttIfaceButton">RTT</string>
<string name="endRttButton">End RTT</string>
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallDiagnosticService.java b/testapps/src/com/android/server/telecom/testapps/TestCallDiagnosticService.java
new file mode 100644
index 0000000..e1511e7
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallDiagnosticService.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 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.testapps;
+
+import android.telecom.BluetoothCallQualityReport;
+import android.telecom.Call;
+import android.telecom.CallAudioState;
+import android.telecom.CallDiagnosticService;
+import android.telecom.CallDiagnostics;
+import android.telecom.Log;
+import android.telephony.CallQuality;
+import android.telephony.ims.ImsReasonInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class TestCallDiagnosticService extends CallDiagnosticService {
+
+ public static final class TestCallDiagnostics extends CallDiagnostics {
+ public Call.Details details;
+
+ TestCallDiagnostics(Call.Details details) {
+ this.details = details;
+ }
+
+ @Override
+ public void onCallDetailsChanged(@NonNull Call.Details details) {
+ Log.i(this, "onCallDetailsChanged; %s", details);
+ }
+
+ @Override
+ public void onReceiveDeviceToDeviceMessage(int message, int value) {
+ Log.i(this, "onReceiveDeviceToDeviceMessage; %d/%d", message, value);
+ }
+
+ @Nullable
+ @Override
+ public CharSequence onCallDisconnected(int disconnectCause, int preciseDisconnectCause) {
+ Log.i(this, "onCallDisconnected");
+ return "GSM/CDMA call dropped because " + disconnectCause;
+ }
+
+ @Nullable
+ @Override
+ public CharSequence onCallDisconnected(@NonNull ImsReasonInfo disconnectReason) {
+ Log.i(this, "onCallDisconnected");
+ return "ImsCall dropped because something happened " + disconnectReason.mExtraMessage;
+ }
+
+ @Override
+ public void onCallQualityReceived(@NonNull CallQuality callQuality) {
+ Log.i(this, "onCallQualityReceived %s", callQuality);
+ }
+ }
+
+ @NonNull
+ @Override
+ public CallDiagnostics onInitializeCallDiagnostics(@NonNull Call.Details call) {
+ Log.i(this, "onInitiatlizeDiagnosticCall %s", call);
+ return new TestCallDiagnostics(call);
+ }
+
+ @Override
+ public void onRemoveCallDiagnostics(@NonNull CallDiagnostics call) {
+ Log.i(this, "onRemoveDiagnosticCall %s", call);
+ }
+
+ @Override
+ public void onCallAudioStateChanged(@NonNull CallAudioState audioState) {
+ Log.i(this, "onCallAudioStateChanged %s", audioState);
+ }
+
+ @Override
+ public void onBluetoothCallQualityReportReceived(
+ @NonNull BluetoothCallQualityReport qualityReport) {
+ Log.i(this, "onBluetoothCallQualityReportReceived %s", qualityReport);
+ }
+}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
index 1e06387..010d6ee 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -9,6 +9,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -32,8 +33,18 @@
private EditText mNumberView;
private CheckBox mRttCheckbox;
+ private CheckBox mComposerCheckbox;
private EditText mPriorityView;
+ private static final String COMPOSER_SUBJECT = "Sample call composer subject";
+ private static final Location COMPOSER_LOCATION;
+ static {
+ // Area 51
+ COMPOSER_LOCATION = new Location("");
+ COMPOSER_LOCATION.setLongitude(-115.806407);
+ COMPOSER_LOCATION.setLatitude(37.236214);
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -68,6 +79,7 @@
mNumberView = (EditText) findViewById(R.id.number);
mRttCheckbox = (CheckBox) findViewById(R.id.call_with_rtt_checkbox);
+ mComposerCheckbox = (CheckBox) findViewById(R.id.add_composer_attachments_checkbox);
findViewById(R.id.enable_car_mode).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -169,6 +181,11 @@
if (mRttCheckbox.isChecked()) {
extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true);
}
+ if (mComposerCheckbox.isChecked()) {
+ extras.putInt(TelecomManager.EXTRA_PRIORITY, TelecomManager.PRIORITY_URGENT);
+ extras.putParcelable(TelecomManager.EXTRA_LOCATION, COMPOSER_LOCATION);
+ extras.putString(TelecomManager.EXTRA_CALL_SUBJECT, COMPOSER_SUBJECT);
+ }
Bundle intentExtras = new Bundle();
intentExtras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
diff --git a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
index 3f3a2c8..bdd4c1a 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.location.Location;
import android.os.Bundle;
import android.telecom.Call;
import android.telecom.CallAudioState;
@@ -28,6 +29,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
+import android.telephony.ims.ImsCallProfile;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
@@ -248,6 +250,47 @@
enableInCallService();
}
});
+
+ // Find the ringing call and populate the composer extras
+ for (int i = 0; i < TestCallList.getInstance().size(); i++) {
+ Call call = TestCallList.getInstance().getCall(i);
+ if (call.getState() == Call.STATE_RINGING) {
+ int priority = call.getDetails()
+ .getIntentExtras().getInt(TelecomManager.EXTRA_PRIORITY, -1);
+ Location location = call.getDetails()
+ .getIntentExtras().getParcelable(TelecomManager.EXTRA_LOCATION);
+ String subject = call.getDetails()
+ .getIntentExtras().getString(TelecomManager.EXTRA_CALL_SUBJECT);
+ boolean isBusiness = call.getDetails()
+ .getExtras().getBoolean(ImsCallProfile.EXTRA_IS_BUSINESS_CALL);
+
+ StringBuilder display = new StringBuilder();
+ display.append("priority=");
+ switch (priority) {
+ case TelecomManager.PRIORITY_NORMAL:
+ display.append("normal");
+ break;
+ case TelecomManager.PRIORITY_URGENT:
+ display.append("urgent");
+ break;
+ default:
+ display.append("unset");
+ }
+ display.append(";");
+ if (location != null) {
+ display.append("lat=" + location.getLatitude());
+ display.append("lon=" + location.getLongitude());
+ } else {
+ display.append("loc=null");
+ }
+
+ display.append(" subject=" + subject);
+ display.append(" isBusiness=" + isBusiness);
+ TextView attachmentsTextView = findViewById(R.id.incoming_composer_attachments);
+ attachmentsTextView.setText(display.toString());
+ break;
+ }
+ }
}
public void updateCallAudioState(CallAudioState cas) {
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 22f5348..e8c69d4 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -26,6 +26,7 @@
<!-- TODO: Needed because we call BluetoothAdapter.getDefaultAdapter() statically, and
BluetoothAdapter is a final class. -->
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<!-- TODO: Needed because we call ActivityManager.getCurrentUser() statically. -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
@@ -36,6 +37,13 @@
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Used to access Projection State APIs -->
+ <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
+
+ <!-- Used to access PlatformCompat APIs -->
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+
<application android:label="@string/app_name"
android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index a64f39d..2a304a4 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -17,6 +17,7 @@
package com.android.server.telecom.tests;
import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+import static android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -29,6 +30,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
import android.telecom.CallAudioState;
@@ -184,6 +186,8 @@
@MediumTest
@Test
public void testAnalyticsTwoCalls() throws Exception {
+ when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class)))
+ .thenReturn((long) TEST_TIMEOUT);
IdPair testCall1 = startAndMakeActiveIncomingCall(
"650-555-1212",
mPhoneAccountA0.getAccountHandle(),
@@ -203,7 +207,9 @@
assertTrue(callAnalytics2.startTime > 0);
assertEquals(0, callAnalytics1.endTime);
assertEquals(0, callAnalytics2.endTime);
- assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics1.missedReason);
+ long missedReason1 = callAnalytics1.missedReason;
+ assertTrue(missedReason1 == MISSED_REASON_NOT_MISSED
+ || missedReason1 == USER_MISSED_CALL_FILTERS_TIMEOUT);
assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics2.missedReason);
assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index a8e1c00..a3b8654 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -63,6 +63,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -473,6 +474,7 @@
@LargeTest
@Test
@FlakyTest
+ @Ignore("b/189904580")
public void testIncomingCallFromBlockedNumberIsRejected() throws Exception {
String phoneNumber = "650-555-1212";
blockNumber(phoneNumber);
@@ -492,6 +494,7 @@
waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(),
TEST_TIMEOUT);
+
assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
for (CallerInfoAsyncQueryFactoryFixture.Request request :
mCallerInfoAsyncQueryFactoryFixture.mRequests) {
@@ -827,8 +830,7 @@
private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception {
when(getBlockedNumberProvider().call(
- anyString(),
- nullable(String.class),
+ any(),
anyString(),
eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
eq(phoneNumber),
diff --git a/tests/src/com/android/server/telecom/tests/BlockedNumbersUtilTests.java b/tests/src/com/android/server/telecom/tests/BlockedNumbersUtilTests.java
new file mode 100644
index 0000000..56cb735
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/BlockedNumbersUtilTests.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 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.tests;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.telecom.settings.BlockedNumbersUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class BlockedNumbersUtilTests extends TelecomTestCase {
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @SmallTest
+ @Test
+ public void testPostNotification() {
+ BlockedNumbersUtil.updateEmergencyCallNotification(mContext, true);
+ NotificationManager mgr = mComponentContextFixture.getNotificationManager();
+ verify(mgr).notifyAsUser(isNull(), anyInt(), any(Notification.class),
+ any(UserHandle.class));
+ }
+
+ @SmallTest
+ @Test
+ public void testDismissNotification() {
+ BlockedNumbersUtil.updateEmergencyCallNotification(mContext, false);
+ NotificationManager mgr = mComponentContextFixture.getNotificationManager();
+ verify(mgr).cancelAsUser(isNull(), anyInt(), any(UserHandle.class));
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index bfa7a75..db26aaf 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -26,8 +26,6 @@
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.server.telecom.BluetoothAdapterProxy;
-import com.android.server.telecom.BluetoothHeadsetProxy;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
@@ -54,8 +52,8 @@
@RunWith(JUnit4.class)
public class BluetoothDeviceManagerTest extends TelecomTestCase {
@Mock BluetoothRouteManager mRouteManager;
- @Mock BluetoothHeadsetProxy mHeadsetProxy;
- @Mock BluetoothAdapterProxy mAdapterProxy;
+ @Mock BluetoothHeadset mBluetoothHeadset;
+ @Mock BluetoothAdapter mAdapter;
@Mock BluetoothHearingAid mBluetoothHearingAid;
BluetoothDeviceManager mBluetoothDeviceManager;
@@ -82,18 +80,18 @@
when(mBluetoothHearingAid.getHiSyncId(device4)).thenReturn(100L);
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
- mBluetoothDeviceManager = new BluetoothDeviceManager(mContext, mAdapterProxy);
+ mBluetoothDeviceManager = new BluetoothDeviceManager(mContext, mAdapter);
mBluetoothDeviceManager.setBluetoothRouteManager(mRouteManager);
ArgumentCaptor<BluetoothProfile.ServiceListener> serviceCaptor =
ArgumentCaptor.forClass(BluetoothProfile.ServiceListener.class);
- verify(mAdapterProxy).getProfileProxy(eq(mContext),
+ verify(mAdapter).getProfileProxy(eq(mContext),
serviceCaptor.capture(), eq(BluetoothProfile.HEADSET));
serviceListenerUnderTest = serviceCaptor.getValue();
receiverUnderTest = new BluetoothStateReceiver(mBluetoothDeviceManager, mRouteManager);
- mBluetoothDeviceManager.setHeadsetServiceForTesting(mHeadsetProxy);
+ mBluetoothDeviceManager.setHeadsetServiceForTesting(mBluetoothHeadset);
mBluetoothDeviceManager.setHearingAidServiceForTesting(mBluetoothHearingAid);
}
@@ -127,7 +125,7 @@
assertEquals(0, mBluetoothDeviceManager.getNumConnectedDevices());
}
-
+
@SmallTest
@Test
public void testMultiDeviceConnectAndDisconnect() {
@@ -173,7 +171,7 @@
verify(mRouteManager).onDeviceLost(device1.getAddress());
verify(mRouteManager).onDeviceLost(device3.getAddress());
verify(mRouteManager, never()).onDeviceLost(device2.getAddress());
- assertNull(mBluetoothDeviceManager.getHeadsetService());
+ assertNull(mBluetoothDeviceManager.getBluetoothHeadset());
assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
}
@@ -192,7 +190,7 @@
verify(mRouteManager).onDeviceLost(device2.getAddress());
verify(mRouteManager, never()).onDeviceLost(device1.getAddress());
verify(mRouteManager, never()).onDeviceLost(device3.getAddress());
- assertNull(mBluetoothDeviceManager.getHearingAidService());
+ assertNull(mBluetoothDeviceManager.getBluetoothHearingAid());
assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
}
@@ -216,12 +214,14 @@
public void testConnectDisconnectAudioHeadset() {
receiverUnderTest.onReceive(mContext,
buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
- when(mAdapterProxy.setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
+ when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
+ eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
mBluetoothDeviceManager.connectAudio(device1.getAddress());
- verify(mAdapterProxy).setActiveDevice(device1, BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
- verify(mAdapterProxy, never()).setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_ALL));
+ verify(mAdapter).setActiveDevice(device1, BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
+ verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
+ eq(BluetoothAdapter.ACTIVE_DEVICE_ALL));
mBluetoothDeviceManager.disconnectAudio();
- verify(mHeadsetProxy).disconnectAudio();
+ verify(mBluetoothHeadset).disconnectAudio();
}
@SmallTest
@@ -230,15 +230,17 @@
receiverUnderTest.onReceive(mContext,
buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
mBluetoothDeviceManager.connectAudio(device2.getAddress());
- verify(mAdapterProxy).setActiveDevice(device2, BluetoothAdapter.ACTIVE_DEVICE_ALL);
- verify(mHeadsetProxy, never()).connectAudio();
- verify(mAdapterProxy, never()).setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
+ verify(mAdapter).setActiveDevice(device2, BluetoothAdapter.ACTIVE_DEVICE_ALL);
+ verify(mBluetoothHeadset, never()).connectAudio();
+ verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
+ eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
- when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(device2, null));
+ when(mAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
+ .thenReturn(Arrays.asList(device2, null));
mBluetoothDeviceManager.disconnectAudio();
- verify(mAdapterProxy).setActiveDevice(null, BluetoothAdapter.ACTIVE_DEVICE_ALL);
- verify(mHeadsetProxy).disconnectAudio();
+ verify(mAdapter).removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
+ verify(mBluetoothHeadset).disconnectAudio();
}
private Intent buildConnectionActionIntent(int state, BluetoothDevice device,
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index b20ecfb..28f6966 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -16,16 +16,17 @@
package com.android.server.telecom.tests;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothProfile;
import android.content.ContentResolver;
import android.os.Parcel;
import android.telecom.Log;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.os.SomeArgs;
-import com.android.server.telecom.BluetoothHeadsetProxy;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
@@ -60,8 +61,9 @@
static final BluetoothDevice DEVICE3 = makeBluetoothDevice("00:00:00:00:00:03");
static final BluetoothDevice HEARING_AID_DEVICE = makeBluetoothDevice("00:00:00:00:00:04");
+ @Mock private BluetoothAdapter mBluetoothAdapter;
@Mock private BluetoothDeviceManager mDeviceManager;
- @Mock private BluetoothHeadsetProxy mHeadsetProxy;
+ @Mock private BluetoothHeadset mBluetoothHeadset;
@Mock private BluetoothHearingAid mBluetoothHearingAid;
@Mock private Timeouts.Adapter mTimeoutsAdapter;
@Mock private BluetoothRouteManager.BluetoothStateListener mListener;
@@ -86,7 +88,7 @@
setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, null);
when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
nullable(ContentResolver.class))).thenReturn(0L);
- when(mHeadsetProxy.connectAudio()).thenReturn(false);
+ when(mBluetoothHeadset.connectAudio()).thenReturn(false);
executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE1.getAddress());
// Wait 3 times: for the first connection attempt, the retry attempt,
// the second retry, and once more to make sure there are only three attempts.
@@ -125,7 +127,7 @@
BluetoothRouteManager sm = setupStateMachine(
BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, DEVICE1, null);
- when(mHeadsetProxy.getAudioState(DEVICE1))
+ when(mBluetoothHeadset.getAudioState(DEVICE1))
.thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress());
@@ -143,7 +145,7 @@
setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null);
when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
nullable(ContentResolver.class))).thenReturn(0L);
- when(mHeadsetProxy.connectAudio()).thenReturn(false);
+ when(mBluetoothHeadset.connectAudio()).thenReturn(false);
executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE2.getAddress());
// Wait 3 times: the first connection attempt is accounted for in executeRoutingAction,
// so wait twice for the retry attempt, again to make sure there are only three attempts,
@@ -185,14 +187,15 @@
.collect(Collectors.toList());
when(mDeviceManager.getConnectedDevices()).thenReturn(allDevices);
- when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices));
- when(mHeadsetProxy.getActiveDevice()).thenReturn(hfpActiveDevice);
- when(mHeadsetProxy.getAudioState(hfpActiveDevice))
+ when(mBluetoothHeadset.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices));
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+ .thenReturn(Arrays.asList(hfpActiveDevice));
+ when(mBluetoothHeadset.getAudioState(hfpActiveDevice))
.thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
when(mBluetoothHearingAid.getConnectedDevices())
.thenReturn(Arrays.asList(hearingAidDevices));
- when(mBluetoothHearingAid.getActiveDevices())
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
.thenReturn(Arrays.asList(hearingAidActiveDevice, null));
}
@@ -215,11 +218,12 @@
}
private void resetMocks() {
- reset(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter);
- when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy);
- when(mDeviceManager.getHearingAidService()).thenReturn(mBluetoothHearingAid);
- when(mHeadsetProxy.connectAudio()).thenReturn(true);
- when(mHeadsetProxy.setActiveDevice(nullable(BluetoothDevice.class))).thenReturn(true);
+ reset(mDeviceManager, mListener, mBluetoothHeadset, mTimeoutsAdapter);
+ when(mDeviceManager.getBluetoothHeadset()).thenReturn(mBluetoothHeadset);
+ when(mDeviceManager.getBluetoothHearingAid()).thenReturn(mBluetoothHearingAid);
+ when(mDeviceManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
+ when(mBluetoothHeadset.connectAudio()).thenReturn(true);
+ when(mBluetoothHeadset.setActiveDevice(nullable(BluetoothDevice.class))).thenReturn(true);
when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
nullable(ContentResolver.class))).thenReturn(100000L);
when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis(
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
index b36d74b..d96b687 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
@@ -16,15 +16,16 @@
package com.android.server.telecom.tests;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothProfile;
import android.content.ContentResolver;
import android.telecom.Log;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.os.SomeArgs;
-import com.android.server.telecom.BluetoothHeadsetProxy;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
@@ -76,7 +77,7 @@
private BluetoothDevice expectedConnectionDevice;
private String expectedFinalStateName;
private BluetoothDevice[] connectedDevices;
- // the active device as returned by BluetoothHeadset#getActiveDevice
+ // the active device as returned by BluetoothAdapter#getActiveDevices
private BluetoothDevice activeDevice = null;
private List<BluetoothDevice> hearingAidBtDevices = Collections.emptyList();
@@ -183,7 +184,7 @@
public BluetoothDevice expectedConnectionDevice; // Expected device to connect to.
public String expectedFinalStateName; // Expected name of the final state.
public BluetoothDevice[] connectedDevices; // array of connected devices
- // the active device as returned by BluetoothHeadset#getActiveDevice
+ // the active device as returned by BluetoothAdapter#getActiveDevices
private BluetoothDevice activeDevice = null;
private List<BluetoothDevice> hearingAidBtDevices;
@@ -236,7 +237,8 @@
private final BluetoothRouteTestParameters mParams;
@Mock private BluetoothDeviceManager mDeviceManager;
- @Mock private BluetoothHeadsetProxy mHeadsetProxy;
+ @Mock private BluetoothAdapter mBluetoothAdapter;
+ @Mock private BluetoothHeadset mBluetoothHeadset;
@Mock private BluetoothHearingAid mBluetoothHearingAid;
@Mock private Timeouts.Adapter mTimeoutsAdapter;
@Mock private BluetoothRouteManager.BluetoothStateListener mListener;
@@ -245,6 +247,7 @@
@Before
public void setUp() throws Exception {
super.setUp();
+ when(mDeviceManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
}
@Override
@@ -272,7 +275,8 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = Log.createSubsession();
args.arg2 = mParams.initialDevice.getAddress();
- when(mHeadsetProxy.getActiveDevice()).thenReturn(null);
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+ .thenReturn(Arrays.asList((BluetoothDevice) null));
sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args);
return true;
}).when(mDeviceManager).disconnectAudio();
@@ -287,9 +291,11 @@
sm.onActiveDeviceChanged(null,
mParams.hearingAidBtDevices.contains(mParams.messageDevice));
if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
- when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null));
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
+ .thenReturn(Arrays.asList(null, null));
} else {
- when(mHeadsetProxy.getActiveDevice()).thenReturn(null);
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+ .thenReturn(Arrays.asList((BluetoothDevice) null));
}
sm.onDeviceLost(mParams.messageDevice.getAddress());
} else {
@@ -344,13 +350,15 @@
BluetoothDevice audioOnDevice, BluetoothDevice activeDevice) {
when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length);
when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices));
- when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices));
- when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice);
- when(mHeadsetProxy.getAudioState(nullable(BluetoothDevice.class)))
+ when(mBluetoothHeadset.getConnectedDevices()).thenReturn(Arrays.asList(devices));
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+ .thenReturn(Arrays.asList(activeDevice));
+ when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
.thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
if (audioOnDevice != null) {
- when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice);
- when(mHeadsetProxy.getAudioState(audioOnDevice))
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+ .thenReturn(Arrays.asList(audioOnDevice));
+ when(mBluetoothHeadset.getAudioState(audioOnDevice))
.thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
}
}
@@ -358,8 +366,8 @@
private BluetoothRouteManager setupStateMachine(String initialState,
BluetoothDevice initialDevice) {
resetMocks();
- when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy);
- when(mDeviceManager.getHearingAidService()).thenReturn(mBluetoothHearingAid);
+ when(mDeviceManager.getBluetoothHeadset()).thenReturn(mBluetoothHeadset);
+ when(mDeviceManager.getBluetoothHearingAid()).thenReturn(mBluetoothHearingAid);
when(mDeviceManager.connectAudio(nullable(String.class))).thenReturn(true);
when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
nullable(ContentResolver.class))).thenReturn(100000L);
@@ -375,7 +383,7 @@
}
private void resetMocks() {
- clearInvocations(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter);
+ clearInvocations(mDeviceManager, mListener, mBluetoothHeadset, mTimeoutsAdapter);
}
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 5592cf4..91ec7f3 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -17,7 +17,10 @@
package com.android.server.telecom.tests;
import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.IAudioService;
import android.os.HandlerThread;
@@ -151,6 +154,49 @@
@MediumTest
@Test
+ public void testStreamRingMuteChange() {
+ CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+ mContext,
+ mockCallsManager,
+ mockBluetoothRouteManager,
+ mockWiredHeadsetManager,
+ mockStatusBarNotifier,
+ mAudioServiceFactory,
+ CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
+ mThreadHandler.getLooper());
+ stateMachine.setCallAudioManager(mockCallAudioManager);
+ CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
+ stateMachine.initialize(initState);
+
+ // Make sure we register a receiver for the STREAM_MUTE_CHANGED_ACTION so we can see if the
+ // ring stream unmutes.
+ ArgumentCaptor<BroadcastReceiver> brCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mContext, times(3)).registerReceiver(brCaptor.capture(), filterCaptor.capture());
+ boolean foundValid = false;
+ for (int ix = 0; ix < brCaptor.getAllValues().size(); ix++) {
+ BroadcastReceiver receiver = brCaptor.getAllValues().get(ix);
+ IntentFilter filter = filterCaptor.getAllValues().get(ix);
+ if (!filter.hasAction(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
+ continue;
+ }
+
+ // Fake out a call to the broadcast receiver and make sure we call into audio manager
+ // to trigger re-evaluation of ringing.
+ Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, AudioManager.STREAM_RING);
+ receiver.onReceive(mContext, intent);
+ verify(mockCallAudioManager).onRingerModeChange();
+ foundValid = true;
+ }
+ assertTrue(foundValid);
+ }
+
+ @MediumTest
+ @Test
public void testSpeakerPersistence() {
CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
mContext,
@@ -276,6 +322,10 @@
waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
verifyNewSystemCallAudioState(initState, expectedMidState);
+ // clear out the handler state before resetting mocks in order to avoid introducing a
+ // CallAudioState that has a null list of supported BT devices
+ waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+ waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
resetMocks();
// Now, switch back to BT explicitly
diff --git a/tests/src/com/android/server/telecom/tests/CallDiagnosticServiceControllerTest.java b/tests/src/com/android/server/telecom/tests/CallDiagnosticServiceControllerTest.java
new file mode 100644
index 0000000..d420f1d
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/CallDiagnosticServiceControllerTest.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2021 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.tests;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.telecom.ParcelableCall;
+
+import com.android.internal.telecom.ICallDiagnosticService;
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallDiagnosticServiceController;
+import com.android.server.telecom.TelecomSystem;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class CallDiagnosticServiceControllerTest {
+ private static final String TEST_CDS_PACKAGE = "com.test.stuff";
+ private static final String TEST_PACKAGE = "com.android.telecom.calldiagnosticservice";
+ private static final String TEST_CLASS =
+ "com.android.telecom.calldiagnosticservice.TestService";
+ private static final ComponentName TEST_COMPONENT = new ComponentName(TEST_PACKAGE, TEST_CLASS);
+ private static final List<ResolveInfo> RESOLVE_INFOS = new ArrayList<>();
+ private static final ResolveInfo TEST_RESOLVE_INFO = new ResolveInfo();
+ static {
+ TEST_RESOLVE_INFO.serviceInfo = new ServiceInfo();
+ TEST_RESOLVE_INFO.serviceInfo.packageName = TEST_PACKAGE;
+ TEST_RESOLVE_INFO.serviceInfo.name = TEST_CLASS;
+ TEST_RESOLVE_INFO.serviceInfo.permission = Manifest.permission.BIND_CALL_DIAGNOSTIC_SERVICE;
+ RESOLVE_INFOS.add(TEST_RESOLVE_INFO);
+ }
+ private static final String ID_1 = "1";
+ private static final String ID_2 = "2";
+
+ @Mock
+ private CallDiagnosticServiceController.ContextProxy mContextProxy;
+ @Mock
+ private Call mCall;
+ @Mock
+ private Call mCallTwo;
+ @Mock
+ private ICallDiagnosticService mICallDiagnosticService;
+ private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
+
+ private CallDiagnosticServiceController mCallDiagnosticService;
+ private ServiceConnection mServiceConnection;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mCall.getId()).thenReturn(ID_1);
+ when(mCall.isSimCall()).thenReturn(true);
+ when(mCall.isExternalCall()).thenReturn(false);
+
+ when(mCallTwo.getId()).thenReturn(ID_2);
+ when(mCallTwo.isSimCall()).thenReturn(true);
+ when(mCallTwo.isExternalCall()).thenReturn(false);
+ mServiceConnection = null;
+
+ // Mock out the context and other junk that we depend on.
+ when(mContextProxy.queryIntentServicesAsUser(any(Intent.class), anyInt(), anyInt()))
+ .thenReturn(RESOLVE_INFOS);
+ when(mContextProxy.bindServiceAsUser(any(Intent.class), any(ServiceConnection.class),
+ anyInt(), any(UserHandle.class))).thenReturn(true);
+ when(mContextProxy.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
+
+ mCallDiagnosticService = new CallDiagnosticServiceController(mContextProxy,
+ TEST_PACKAGE, mLock);
+ }
+
+ /**
+ * Verify no binding takes place for a non-sim call.
+ */
+ @Test
+ public void testNoBindOnNonSimCall() {
+ Call mockCall = Mockito.mock(Call.class);
+ when(mockCall.isSimCall()).thenReturn(false);
+
+ mCallDiagnosticService.onCallAdded(mockCall);
+
+ verify(mContextProxy, never()).bindServiceAsUser(any(Intent.class),
+ any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+ }
+
+ /**
+ * Verify no binding takes place for a SIM external call.
+ */
+ @Test
+ public void testNoBindOnExternalCall() {
+ Call mockCall = Mockito.mock(Call.class);
+ when(mockCall.isSimCall()).thenReturn(true);
+ when(mockCall.isExternalCall()).thenReturn(true);
+
+ mCallDiagnosticService.onCallAdded(mockCall);
+
+ verify(mContextProxy, never()).bindServiceAsUser(any(Intent.class),
+ any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+ }
+
+ /**
+ * Verify a valid SIM call causes binding to initiate.
+ */
+ @Test
+ public void testAddSimCallCausesBind() throws RemoteException {
+ mCallDiagnosticService.onCallAdded(mCall);
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(
+ ServiceConnection.class);
+ verify(mContextProxy).bindServiceAsUser(intentCaptor.capture(),
+ serviceConnectionCaptor.capture(), anyInt(), any(UserHandle.class));
+ assertEquals(TEST_PACKAGE, intentCaptor.getValue().getPackage());
+
+ // Now we'll pretend bind completed and we sent back the binder.
+ IBinder mockBinder = mock(IBinder.class);
+ when(mockBinder.queryLocalInterface(anyString())).thenReturn(mICallDiagnosticService);
+ serviceConnectionCaptor.getValue().onServiceConnected(TEST_COMPONENT, mockBinder);
+ mServiceConnection = serviceConnectionCaptor.getValue();
+
+ // Make sure it's sent
+ verify(mICallDiagnosticService).initializeDiagnosticCall(any(ParcelableCall.class));
+ }
+
+ /**
+ * Verify removing the active call causes it to be removed from the CallDiagnosticService and
+ * that an unbind takes place.
+ */
+ @Test
+ public void testRemoveSimCallCausesRemoveAndUnbind() throws RemoteException {
+ testAddSimCallCausesBind();
+ mCallDiagnosticService.onCallRemoved(mCall);
+
+ verify(mICallDiagnosticService).removeDiagnosticCall(eq(ID_1));
+ verify(mContextProxy).unbindService(eq(mServiceConnection));
+ }
+
+ /**
+ * Try to add and remove two and verify bind/unbind.
+ */
+ @Test
+ public void testAddTwo() throws RemoteException {
+ testAddSimCallCausesBind();
+ mCallDiagnosticService.onCallAdded(mCallTwo);
+ verify(mICallDiagnosticService, times(2)).initializeDiagnosticCall(
+ any(ParcelableCall.class));
+
+ mCallDiagnosticService.onCallRemoved(mCall);
+ // Not yet!
+ verify(mContextProxy, never()).unbindService(eq(mServiceConnection));
+
+ mCallDiagnosticService.onCallRemoved(mCallTwo);
+
+ verify(mICallDiagnosticService).removeDiagnosticCall(eq(ID_1));
+ verify(mICallDiagnosticService).removeDiagnosticCall(eq(ID_2));
+ verify(mContextProxy).unbindService(eq(mServiceConnection));
+ }
+
+ /**
+ * Verifies we can override the call diagnostic service package to a test package (used by CTS
+ * tests).
+ */
+ @Test
+ public void testTestOverride() {
+ mCallDiagnosticService.setTestCallDiagnosticService(TEST_CDS_PACKAGE);
+ mCallDiagnosticService.onCallAdded(mCall);
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContextProxy).bindServiceAsUser(intentCaptor.capture(),
+ any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+ assertEquals(TEST_CDS_PACKAGE, intentCaptor.getValue().getPackage());
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index dfc3258..b9f5667 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -40,7 +41,9 @@
import android.location.Country;
import android.location.CountryDetector;
import android.location.CountryListener;
+import android.location.Location;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.SystemClock;
@@ -52,6 +55,7 @@
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
@@ -172,7 +176,7 @@
when(userManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
when(userManager.hasUserRestriction(any(String.class), any(UserHandle.class)))
.thenReturn(false);
- when(userManager.getUsers(any(Boolean.class)))
+ when(userManager.getAliveUsers())
.thenReturn(Arrays.asList(userInfo, otherUserInfo, managedProfileUserInfo));
when(userManager.getUserInfo(eq(CURRENT_USER_ID))).thenReturn(userInfo);
when(userManager.getUserInfo(eq(OTHER_USER_ID))).thenReturn(otherUserInfo);
@@ -819,6 +823,54 @@
@SmallTest
@Test
+ public void testCallComposerElements() {
+ Call fakeCall = makeFakeCall(
+ DisconnectCause.LOCAL, // disconnectCauseCode
+ false, // isConference
+ true, // isIncoming
+ 1L, // creationTimeMillis
+ 1000L, // ageMillis
+ TEL_PHONEHANDLE, // callHandle
+ mDefaultAccountHandle, // phoneAccountHandle
+ NO_VIDEO_STATE, // callVideoState
+ POST_DIAL_STRING, // postDialDigits
+ VIA_NUMBER_STRING, // viaNumber
+ UserHandle.of(CURRENT_USER_ID)
+ );
+ String subject = "segmentation fault";
+ // =)
+ double lat = 40.649723;
+ double lon = -80.082090;
+ Location location = new Location("");
+ location.setLatitude(lat);
+ location.setLongitude(lon);
+
+ Uri fakeProviderUri = Uri.parse("content://nothing_to_see_here/12345");
+
+ Bundle extras = new Bundle();
+ extras.putInt(TelecomManager.EXTRA_PRIORITY, TelecomManager.PRIORITY_URGENT);
+ extras.putString(TelecomManager.EXTRA_CALL_SUBJECT, subject);
+ extras.putParcelable(TelecomManager.EXTRA_LOCATION, location);
+ extras.putParcelable(TelecomManager.EXTRA_PICTURE_URI, fakeProviderUri);
+ when(fakeCall.getIntentExtras()).thenReturn(extras);
+
+ mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE,
+ CallState.DISCONNECTED);
+ ContentValues locationValues = verifyLocationInsertionWithCapture(CURRENT_USER_ID);
+ assertEquals(lat, locationValues.getAsDouble(CallLog.Locations.LATITUDE), 0);
+ assertEquals(lon, locationValues.getAsDouble(CallLog.Locations.LONGITUDE), 0);
+
+ ContentValues callLogValues = verifyInsertionWithCapture(CURRENT_USER_ID);
+ assertEquals(subject, callLogValues.getAsString(Calls.SUBJECT));
+ assertEquals(fakeProviderUri.toString(),
+ callLogValues.getAsString(Calls.COMPOSER_PHOTO_URI));
+ assertEquals(TelecomManager.PRIORITY_URGENT,
+ (int) callLogValues.getAsInteger(Calls.PRIORITY));
+ assertNotNull(callLogValues.getAsString(Calls.LOCATION));
+ }
+
+ @SmallTest
+ @Test
public void testDoNotLogConferenceWithNoChildren() {
Call fakeCall = makeFakeCall(
DisconnectCause.LOCAL, // disconnectCauseCode
@@ -976,6 +1028,14 @@
return captor.getValue();
}
+ private ContentValues verifyLocationInsertionWithCapture(int userId) {
+ Uri uri = ContentProvider.maybeAddUserId(CallLog.Locations.CONTENT_URI, userId);
+ ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
+ verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).times(1)).insert(
+ eq(uri), captor.capture());
+ return captor.getValue();
+ }
+
private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming,
long creationTimeMillis, long ageMillis, Uri callHandle,
PhoneAccountHandle phoneAccountHandle, int callVideoState,
diff --git a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
index ff16880..0a896a8 100644
--- a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
@@ -65,8 +65,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import java.util.ArrayList;
-
@RunWith(JUnit4.class)
public class CallRedirectionProcessorTest extends TelecomTestCase {
@Mock private Context mContext;
@@ -151,7 +149,7 @@
}
private void setIsInCarMode(boolean isInCarMode) {
- when(mSystemStateHelper.isCarMode()).thenReturn(isInCarMode);
+ when(mSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(isInCarMode);
}
private void enableUserDefinedCallRedirectionService() {
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index c7b3a7e..68caf67 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -93,6 +93,16 @@
.setShouldShowNotification(true)
.build();
+ private static final CallFilteringResult PASS_RESULT_WITH_NAME =
+ new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldAddToCallLog(true)
+ .setShouldShowNotification(true)
+ .setCallScreeningAppName(APP_NAME)
+ .setCallScreeningComponentName(COMPONENT_NAME.flattenToString())
+ .build();
+
@Override
@Before
public void setUp() throws Exception {
@@ -235,8 +245,14 @@
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.allowCall(CALL_ID);
- assertEquals(PASS_RESULT,
+ CallScreeningService.CallResponse allowCallResponse =
+ new CallScreeningService.CallResponse.Builder()
+ .setDisallowCall(false)
+ .setRejectCall(false)
+ .setSilenceCall(false)
+ .build();
+ csAdapter.onScreeningResponse(CALL_ID, COMPONENT_NAME, allowCallResponse.toParcelable());
+ assertEquals(PASS_RESULT_WITH_NAME,
resultFuture.toCompletableFuture().get(
CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
TimeUnit.MILLISECONDS));
@@ -264,12 +280,16 @@
ServiceConnection serviceConnection = verifyBindingIntent();
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
+ CallScreeningService.CallResponse disallowCallResponse =
+ new CallScreeningService.CallResponse.Builder()
+ .setDisallowCall(true)
+ .setRejectCall(true)
+ .setSkipCallLog(false)
+ .setSkipNotification(false)
+ .build();
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.disallowCall(CALL_ID,
- true, // shouldReject
- true, //shouldAddToCallLog
- true, // shouldShowNotification
- COMPONENT_NAME);
+ csAdapter.onScreeningResponse(CALL_ID, COMPONENT_NAME, disallowCallResponse.toParcelable());
+
assertEquals(expectedResult,
resultFuture.toCompletableFuture().get(
CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
@@ -286,6 +306,8 @@
.setShouldSilence(true)
.setShouldAddToCallLog(true)
.setShouldShowNotification(true)
+ .setCallScreeningAppName(APP_NAME)
+ .setCallScreeningComponentName(COMPONENT_NAME.flattenToString())
.build();
CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
@@ -296,7 +318,13 @@
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.silenceCall(CALL_ID);
+ CallScreeningService.CallResponse silenceCallResponse =
+ new CallScreeningService.CallResponse.Builder()
+ .setDisallowCall(false)
+ .setRejectCall(false)
+ .setSilenceCall(true)
+ .build();
+ csAdapter.onScreeningResponse(CALL_ID, COMPONENT_NAME, silenceCallResponse.toParcelable());
assertEquals(expectedResult,
resultFuture.toCompletableFuture().get(
CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
@@ -314,6 +342,7 @@
.setShouldSilence(false)
.setShouldScreenViaAudio(true)
.setCallScreeningAppName(APP_NAME)
+ .setCallScreeningComponentName(COMPONENT_NAME.flattenToString())
.build();
CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
CallScreeningServiceFilter.PACKAGE_TYPE_DEFAULT_DIALER, mContext, mCallsManager,
@@ -323,8 +352,17 @@
ServiceConnection serviceConnection = verifyBindingIntent();
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
+
+ CallScreeningService.CallResponse additionalScreeningResponse =
+ new CallScreeningService.CallResponse.Builder()
+ .setDisallowCall(false)
+ .setRejectCall(false)
+ .setSilenceCall(false)
+ .setShouldScreenCallViaAudioProcessing(true)
+ .build();
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.screenCallFurther(CALL_ID);
+ csAdapter.onScreeningResponse(CALL_ID, COMPONENT_NAME,
+ additionalScreeningResponse.toParcelable());
assertEquals(expectedResult,
resultFuture.toCompletableFuture().get(
CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 8378e3b..da72933 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -36,11 +37,14 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -52,6 +56,8 @@
import android.os.UserHandle;
import android.telecom.CallerInfo;
import android.telecom.Connection;
+import android.telecom.DisconnectCause;
+import android.telecom.Log;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -67,6 +73,7 @@
import com.android.server.telecom.CallAudioManager;
import com.android.server.telecom.CallAudioModeStateMachine;
import com.android.server.telecom.CallAudioRouteStateMachine;
+import com.android.server.telecom.CallDiagnosticServiceController;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.CallsManager;
@@ -74,6 +81,7 @@
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory;
+import com.android.server.telecom.ConnectionServiceWrapper;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.EmergencyCallHelper;
import com.android.server.telecom.HeadsetMediaButton;
@@ -196,6 +204,7 @@
@Mock private CallAudioRouteStateMachine.Factory mCallAudioRouteStateMachineFactory;
@Mock private CallAudioModeStateMachine mCallAudioModeStateMachine;
@Mock private CallAudioModeStateMachine.Factory mCallAudioModeStateMachineFactory;
+ @Mock private CallDiagnosticServiceController mCallDiagnosticServiceController;
@Mock private BluetoothStateReceiver mBluetoothStateReceiver;
@Mock private RoleManagerAdapter mRoleManagerAdapter;
@Mock private ToastFactory mToastFactory;
@@ -226,6 +235,8 @@
doNothing().when(mRoleManagerAdapter).setCurrentUserHandle(any());
when(mDisconnectedCallNotifierFactory.create(any(Context.class),any(CallsManager.class)))
.thenReturn(mDisconnectedCallNotifier);
+ when(mTimeoutsAdapter.getCallDiagnosticServiceTimeoutMillis(any(ContentResolver.class)))
+ .thenReturn(2000L);
mCallsManager = new CallsManager(
mComponentContextFixture.getTestDouble().getApplicationContext(),
mLock,
@@ -253,6 +264,7 @@
mCallAudioRouteStateMachineFactory,
mCallAudioModeStateMachineFactory,
mInCallControllerFactory,
+ mCallDiagnosticServiceController,
mRoleManagerAdapter,
mToastFactory);
@@ -1103,6 +1115,46 @@
assertFalse(mCallsManager.isInEmergencyCall());
}
+
+ @SmallTest
+ @Test
+ public void testBlockNonEmergencyCallDuringEmergencyCall() throws Exception {
+ // Setup a call which the network identified as an emergency call.
+ Call ongoingCall = addSpyCall();
+ ongoingCall.setConnectionProperties(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
+ assertTrue(mCallsManager.isInEmergencyCall());
+
+ Call newCall = addSpyCall(CallState.NEW);
+ ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
+ doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();
+
+ // Ensure contact info lookup succeeds
+ doAnswer(invocation -> {
+ Uri handle = invocation.getArgument(0);
+ CallerInfo info = new CallerInfo();
+ CompletableFuture<Pair<Uri, CallerInfo>> callerInfoFuture = new CompletableFuture<>();
+ callerInfoFuture.complete(new Pair<>(handle, info));
+ return callerInfoFuture;
+ }).when(mCallerInfoLookupHelper).startLookup(any(Uri.class));
+
+ // Ensure we have candidate phone account handle info.
+ when(mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(any(), any())).thenReturn(
+ SIM_1_HANDLE);
+ when(mPhoneAccountRegistrar.getCallCapablePhoneAccounts(any(), anyBoolean(),
+ any(), anyInt(), anyInt())).thenReturn(
+ new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
+ mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
+ SIM_2_HANDLE.getUserHandle(), service);
+
+ CompletableFuture<Call> callFuture = mCallsManager.startOutgoingCall(
+ newCall.getHandle(), newCall.getTargetPhoneAccount(), new Bundle(),
+ UserHandle.CURRENT, new Intent(), "com.test.stuff");
+
+ verify(service, timeout(TEST_TIMEOUT)).createConnectionFailed(any());
+ Call result = callFuture.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertNull(result);
+ }
+
@SmallTest
@Test
public void testHasEmergencyCallIncomingCallPermitted() {
@@ -1201,6 +1253,21 @@
verify(ringingCall).reject(anyBoolean(), any(), any());
}
+ @SmallTest
+ @Test
+ public void testMakeRoomForOutgoingCallConnecting() {
+ Call ongoingCall = addSpyCall(SIM_2_HANDLE, CallState.CONNECTING);
+
+ Call newCall = createCall(SIM_1_HANDLE, CallState.NEW);
+ when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
+ .thenReturn(false);
+ newCall.setHandle(Uri.fromParts("tel", "5551213", null),
+ TelecomManager.PRESENTATION_ALLOWED);
+
+ assertTrue(mCallsManager.makeRoomForOutgoingCall(newCall));
+ verify(ongoingCall).disconnect(anyLong(), anyString());
+ }
+
/**
* Verifies that changes to a {@link PhoneAccount}'s
* {@link PhoneAccount#CAPABILITY_VIDEO_CALLING} capability will be reflected on a call.
@@ -1505,6 +1572,59 @@
eq(CallState.ACTIVE));
}
+ /**
+ * Verifies where a call diagnostic service is NOT in use that we don't try to relay to the
+ * CallDiagnosticService and that we get a synchronous disconnect.
+ * @throws Exception
+ */
+ @MediumTest
+ @Test
+ public void testDisconnectCallSynchronous() throws Exception {
+ Call callSpy = addSpyCall();
+ callSpy.setIsSimCall(true);
+ when(mCallDiagnosticServiceController.isConnected()).thenReturn(false);
+ mCallsManager.markCallAsDisconnected(callSpy, new DisconnectCause(DisconnectCause.ERROR));
+
+ verify(mCallDiagnosticServiceController, never()).onCallDisconnected(any(Call.class),
+ any(DisconnectCause.class));
+ verify(callSpy).setDisconnectCause(any(DisconnectCause.class));
+ }
+
+ @MediumTest
+ @Test
+ public void testDisconnectCallAsynchronous() throws Exception {
+ Call callSpy = addSpyCall();
+ callSpy.setIsSimCall(true);
+ when(mCallDiagnosticServiceController.isConnected()).thenReturn(true);
+ when(mCallDiagnosticServiceController.onCallDisconnected(any(Call.class),
+ any(DisconnectCause.class))).thenReturn(true);
+ mCallsManager.markCallAsDisconnected(callSpy, new DisconnectCause(DisconnectCause.ERROR));
+
+ verify(mCallDiagnosticServiceController).onCallDisconnected(any(Call.class),
+ any(DisconnectCause.class));
+ verify(callSpy, never()).setDisconnectCause(any(DisconnectCause.class));
+ }
+
+ /**
+ * Verifies that if call state goes from DIALING to DISCONNECTED, and a call diagnostic service
+ * IS in use, it would call onCallDisconnected of the CallDiagnosticService
+ * @throws Exception
+ */
+ @MediumTest
+ @Test
+ public void testDisconnectDialingCall() throws Exception {
+ Call callSpy = addSpyCall(CallState.DIALING);
+ callSpy.setIsSimCall(true);
+ when(mCallDiagnosticServiceController.isConnected()).thenReturn(true);
+ when(mCallDiagnosticServiceController.onCallDisconnected(any(Call.class),
+ any(DisconnectCause.class))).thenReturn(true);
+ mCallsManager.markCallAsDisconnected(callSpy, new DisconnectCause(DisconnectCause.ERROR));
+
+ verify(mCallDiagnosticServiceController).onCallDisconnected(any(Call.class),
+ any(DisconnectCause.class));
+ verify(callSpy, never()).setDisconnectCause(any(DisconnectCause.class));
+ }
+
private Call addSpyCall() {
return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
}
diff --git a/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java b/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
index dbfcdb1..4ad46ae 100644
--- a/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
@@ -21,9 +21,6 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertNull;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
import android.app.UiModeManager;
import com.android.server.telecom.CarModeTracker;
@@ -33,7 +30,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import org.mockito.Mock;
@RunWith(JUnit4.class)
public class CarModeTrackerTest extends TelecomTestCase {
@@ -110,7 +106,7 @@
@Test
public void testForceExitCarMode() {
testEnterCarModeBasic();
- mCarModeTracker.forceExitCarMode(CAR_MODE_APP1_PACKAGE_NAME);
+ mCarModeTracker.forceRemove(CAR_MODE_APP1_PACKAGE_NAME);
assertFalse(mCarModeTracker.isInCarMode());
assertNull(mCarModeTracker.getCurrentCarModePackage());
}
@@ -226,4 +222,109 @@
CAR_MODE_APP3_PACKAGE_NAME);
assertNull(mCarModeTracker.getCurrentCarModePackage());
}
+
+ /**
+ * Verifies that setting automotive projection by itself works.
+ */
+ @Test
+ public void testSetAutomotiveProjectionBasic() {
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
+ assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+ // We should be tracking our car mode app.
+ assertEquals(1, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ }
+
+ /**
+ * Verifies that if we set automotive projection more than once with the same package, nothing
+ * changes.
+ */
+ @Test
+ public void testSetAutomotiveProjectionMultipleTimes() {
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
+ // Should still only have one app.
+ assertEquals(1, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ // It should be the same one.
+ assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+ }
+
+ /**
+ * Verifies that if we set automotive projection more than once, the new package overrides.
+ */
+ @Test
+ public void testSetAutomotiveProjectionMultipleTimesDifferentPackages() {
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP2_PACKAGE_NAME);
+ // Should still only have one app.
+ assertEquals(1, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ // It should be the newer one.
+ assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+ }
+
+ /**
+ * Verifies that releasing automotive projection works as expected.
+ */
+ @Test
+ public void testReleaseAutomotiveProjectionBasic() {
+ // Releasing before something's set shouldn't break anything.
+ mCarModeTracker.handleReleaseAutomotiveProjection();
+ assertEquals(0, mCarModeTracker.getCarModeApps().size());
+ assertFalse(mCarModeTracker.isInCarMode());
+
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP1_PACKAGE_NAME);
+ mCarModeTracker.handleReleaseAutomotiveProjection();
+ // Should be gone now.
+ assertEquals(0, mCarModeTracker.getCarModeApps().size());
+ assertFalse(mCarModeTracker.isInCarMode());
+ }
+
+ /**
+ * Verifies that setting automotive projection overrides but doesn't overwrite car mode apps.
+ */
+ @Test
+ public void testAutomotiveProjectionOverridesCarMode() {
+ mCarModeTracker.handleEnterCarMode(50, CAR_MODE_APP1_PACKAGE_NAME);
+ mCarModeTracker.handleSetAutomotiveProjection(CAR_MODE_APP4_PACKAGE_NAME);
+
+ // Should have two apps now, the car mode and the automotive projection one.
+ assertEquals(2, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+
+ // Automotive projection takes priority.
+ assertEquals(CAR_MODE_APP4_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+
+ // If we add another car mode app, automotive projection still has priority.
+ mCarModeTracker.handleEnterCarMode(Integer.MAX_VALUE, CAR_MODE_APP2_PACKAGE_NAME);
+ assertEquals(3, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ assertEquals(CAR_MODE_APP4_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+
+ // If we release automotive projection, we go back to the prioritized list of plain car
+ // mode apps.
+ mCarModeTracker.handleReleaseAutomotiveProjection();
+ assertEquals(2, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ assertEquals(CAR_MODE_APP2_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+
+ // Make sure we didn't mess with the first app that was added.
+ mCarModeTracker.handleExitCarMode(Integer.MAX_VALUE, CAR_MODE_APP2_PACKAGE_NAME);
+ assertEquals(1, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+ }
+
+ /**
+ * Verifies that releasing automotive projection doesn't interfere with plain car mode apps.
+ */
+ @Test
+ public void testReleaseAutomotiveProjectionNoopForCarModeApps() {
+ mCarModeTracker.handleEnterCarMode(50, CAR_MODE_APP1_PACKAGE_NAME);
+ mCarModeTracker.handleReleaseAutomotiveProjection();
+ assertEquals(1, mCarModeTracker.getCarModeApps().size());
+ assertTrue(mCarModeTracker.isInCarMode());
+ assertEquals(CAR_MODE_APP1_PACKAGE_NAME, mCarModeTracker.getCurrentCarModePackage());
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index a4302b6..2463847 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -30,7 +30,10 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.StatusBarManager;
+import android.app.UiModeManager;
import android.app.role.RoleManager;
+import android.content.AttributionSource;
+import android.content.AttributionSourceState;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -47,6 +50,7 @@
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.hardware.SensorPrivacyManager;
import android.location.Country;
import android.location.CountryDetector;
import android.media.AudioManager;
@@ -55,8 +59,11 @@
import android.os.IInterface;
import android.os.PersistableBundle;
import android.os.PowerWhitelistManager;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.VibratorManager;
+import android.permission.PermissionCheckerManager;
import android.telecom.CallAudioState;
import android.telecom.ConnectionService;
import android.telecom.Log;
@@ -68,6 +75,7 @@
import android.telephony.TelephonyManager;
import android.telephony.TelephonyRegistryManager;
import android.test.mock.MockContext;
+import android.util.DisplayMetrics;
import java.io.File;
import java.io.IOException;
@@ -79,7 +87,9 @@
import java.util.Map;
import java.util.concurrent.Executor;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -113,6 +123,11 @@
}
@Override
+ public Context createContextAsUser(UserHandle userHandle, int flags) {
+ return this;
+ }
+
+ @Override
public String getPackageName() {
return "com.android.server.telecom.tests";
}
@@ -206,6 +221,14 @@
return mRoleManager;
case Context.TELEPHONY_REGISTRY_SERVICE:
return mTelephonyRegistryManager;
+ case Context.UI_MODE_SERVICE:
+ return mUiModeManager;
+ case Context.VIBRATOR_MANAGER_SERVICE:
+ return mVibratorManager;
+ case Context.PERMISSION_CHECKER_SERVICE:
+ return mPermissionCheckerManager;
+ case Context.SENSOR_PRIVACY_SERVICE:
+ return mSensorPrivacyManager;
default:
return null;
}
@@ -227,6 +250,14 @@
return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
} else if (svcClass == TelephonyRegistryManager.class) {
return Context.TELEPHONY_REGISTRY_SERVICE;
+ } else if (svcClass == UiModeManager.class) {
+ return Context.UI_MODE_SERVICE;
+ } else if (svcClass == VibratorManager.class) {
+ return Context.VIBRATOR_MANAGER_SERVICE;
+ } else if (svcClass == PermissionCheckerManager.class) {
+ return Context.PERMISSION_CHECKER_SERVICE;
+ } else if (svcClass == SensorPrivacyManager.class) {
+ return Context.SENSOR_PRIVACY_SERVICE;
}
throw new UnsupportedOperationException();
}
@@ -252,6 +283,11 @@
}
@Override
+ public AttributionSource getAttributionSource() {
+ return mAttributionSource;
+ }
+
+ @Override
public ContentResolver getContentResolver() {
return new ContentResolver(mApplicationContextSpy) {
@Override
@@ -296,12 +332,23 @@
}
@Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ return null;
+ }
+
+ @Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return null;
}
@Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler, int flags) {
+ return null;
+ }
+
+ @Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return null;
@@ -360,6 +407,11 @@
}
@Override
+ public int checkSelfPermission(String permission) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
public void enforceCallingOrSelfPermission(String permission, String message) {
// Don't bother enforcing anything in mock.
}
@@ -439,6 +491,10 @@
}
}
+ private static final String PACKAGE_NAME = "com.android.server.telecom.tests";
+ private final AttributionSource mAttributionSource =
+ new AttributionSource.Builder(Process.myUid()).setPackageName(PACKAGE_NAME).build();
+
private final Multimap<String, ComponentName> mComponentNamesByAction =
ArrayListMultimap.create();
private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
@@ -469,6 +525,7 @@
private final Resources.Theme mResourcesTheme = mock(Resources.Theme.class);
private final Resources mResources = mock(Resources.class);
private final Context mApplicationContextSpy = spy(mApplicationContext);
+ private final DisplayMetrics mDisplayMetrics = mock(DisplayMetrics.class);
private final PackageManager mPackageManager = mock(PackageManager.class);
private final Executor mMainExecutor = mock(Executor.class);
private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext));
@@ -486,7 +543,12 @@
private final RoleManager mRoleManager = mock(RoleManager.class);
private final TelephonyRegistryManager mTelephonyRegistryManager =
mock(TelephonyRegistryManager.class);
+ private final VibratorManager mVibratorManager = mock(VibratorManager.class);
+ private final UiModeManager mUiModeManager = mock(UiModeManager.class);
+ private final PermissionCheckerManager mPermissionCheckerManager =
+ mock(PermissionCheckerManager.class);
private final PermissionInfo mPermissionInfo = mock(PermissionInfo.class);
+ private final SensorPrivacyManager mSensorPrivacyManager = mock(SensorPrivacyManager.class);
private TelecomManager mTelecomManager = mock(TelecomManager.class);
@@ -495,6 +557,9 @@
when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
when(mResources.getString(anyInt())).thenReturn("");
when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
+ when(mResources.newTheme()).thenReturn(mResourcesTheme);
+ when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+ mDisplayMetrics.density = 3.125f;
mResourceConfiguration.setLocale(Locale.TAIWAN);
// TODO: Move into actual tests
@@ -537,9 +602,10 @@
}).when(mPackageManager).queryBroadcastReceiversAsUser((Intent) any(), anyInt(), anyInt());
// By default, tests use non-ui apps instead of 3rd party companion apps.
- when(mPackageManager.checkPermission(
- matches(Manifest.permission.CALL_COMPANION_APP), anyString()))
- .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mPermissionCheckerManager.checkPermission(
+ matches(Manifest.permission.CALL_COMPANION_APP), any(AttributionSourceState.class),
+ nullable(String.class), anyBoolean(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(PermissionCheckerManager.PERMISSION_HARD_DENIED);
try {
when(mPackageManager.getPermissionInfo(anyString(), anyInt())).thenReturn(
@@ -548,6 +614,7 @@
}
when(mPermissionInfo.isAppOp()).thenReturn(true);
+ when(mVibratorManager.getVibratorIds()).thenReturn(new int[0]);
// Used in CreateConnectionProcessor to rank emergency numbers by viability.
// For the test, make them all equal to INVALID so that the preferred PhoneAccount will be
@@ -615,11 +682,15 @@
serviceInfo.name = componentName.getClassName();
mServiceInfoByComponentName.put(componentName, serviceInfo);
- // Used in InCallController to check permissions for CONTROL_INCALL_EXPERIENCE
+ // Used in InCallController to check permissions for CONTROL_INCALL_fvEXPERIENCE
when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[] {
componentName.getPackageName() });
when(mPackageManager.checkPermission(eq(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
eq(componentName.getPackageName()))).thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mPermissionCheckerManager.checkPermission(
+ eq(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
+ any(AttributionSourceState.class), anyString(), anyBoolean(), anyBoolean(),
+ anyBoolean(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
}
public void addIntentReceiver(String action, ComponentName name) {
@@ -662,6 +733,10 @@
return mTelephonyManager;
}
+ public NotificationManager getNotificationManager() {
+ return mNotificationManager;
+ }
+
private void addService(String action, ComponentName name, IInterface service) {
mComponentNamesByAction.put(action, name);
mServiceByComponentName.put(name, service);
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 5b4e800..6e6646f 100755
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -34,6 +34,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.telecom.CallAudioState;
+import android.telecom.CallScreeningService;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
@@ -437,6 +438,10 @@
@Override
public void handoverComplete(String callId, Session.Info sessionInfo) {}
+
+ @Override
+ public void onCallFilteringCompleted(String callId,
+ Connection.CallFilteringCompletionInfo completionInfo, Session.Info sessionInfo) { }
}
FakeConnectionServiceDelegate mConnectionServiceDelegate;
diff --git a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
index 845a838..1a649dc 100644
--- a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
@@ -41,6 +41,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -546,6 +547,26 @@
verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
}
+ /**
+ * Ensures that a self-managed phone account won't be considered when attempting to place an
+ * emergency call.
+ */
+ @SmallTest
+ @Test
+ public void testDontAttemptSelfManaged() {
+ when(mMockCall.isEmergencyCall()).thenReturn(true);
+ when(mMockCall.isTestEmergencyCall()).thenReturn(false);
+ when(mMockCall.getHandle()).thenReturn(Uri.parse(""));
+
+ PhoneAccount selfManagedAcct = makePhoneAccount("sm-acct",
+ PhoneAccount.CAPABILITY_SELF_MANAGED
+ | PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS);
+ phoneAccounts.add(selfManagedAcct);
+
+ mTestCreateConnectionProcessor.process();
+ verify(mMockCall, never()).setTargetPhoneAccount(any(PhoneAccountHandle.class));
+ }
+
@SmallTest
@Test
public void testEmergencyCallSimFailToConnectionManager() throws Exception {
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 0b926fe..f661878 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -18,13 +18,16 @@
import static com.android.server.telecom.InCallController.IN_CALL_SERVICE_NOTIFICATION_ID;
import static com.android.server.telecom.InCallController.NOTIFICATION_TAG;
+import static com.android.server.telecom.tests.TelecomSystemTest.TEST_TIMEOUT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
@@ -41,14 +44,19 @@
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.UiModeManager;
+import android.content.AttributionSource;
+import android.content.AttributionSourceState;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.PermissionChecker;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -61,7 +69,9 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Process;
import android.os.UserHandle;
+import android.permission.PermissionCheckerManager;
import android.telecom.CallAudioState;
import android.telecom.InCallService;
import android.telecom.ParcelableCall;
@@ -72,10 +82,10 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.telecom.IInCallAdapter;
import com.android.internal.telecom.IInCallService;
import com.android.server.telecom.Analytics;
-import com.android.server.telecom.BluetoothHeadsetProxy;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.CarModeTracker;
@@ -96,23 +106,27 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import org.mockito.invocation.InvocationOnMock;
+import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.CompletableFuture;
@RunWith(JUnit4.class)
public class InCallControllerTests extends TelecomTestCase {
@Mock CallsManager mMockCallsManager;
@Mock PhoneAccountRegistrar mMockPhoneAccountRegistrar;
- @Mock BluetoothHeadsetProxy mMockBluetoothHeadset;
@Mock SystemStateHelper mMockSystemStateHelper;
@Mock PackageManager mMockPackageManager;
+ @Mock PermissionCheckerManager mMockPermissionCheckerManager;
@Mock Call mMockCall;
@Mock Resources mMockResources;
@Mock AppOpsManager mMockAppOpsManager;
@@ -178,8 +192,12 @@
when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
+ when(mMockContext.getSystemService(eq(PermissionCheckerManager.class)))
+ .thenReturn(mMockPermissionCheckerManager);
when(mMockPackageManager.getPermissionInfo(anyString(), anyInt())).thenReturn(
mMockPermissionInfo);
+ when(mMockContext.getAttributionSource()).thenReturn(new AttributionSource(Process.myUid(),
+ "com.android.server.telecom.tests", null));
mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
mEmergencyCallHelper, mCarModeTracker, mClockProxy);
@@ -210,21 +228,37 @@
}
return null;
}).when(mMockPackageManager).getPackagesForUid(anyInt());
- when(mMockPackageManager.checkPermission(
+
+ when(mMockPermissionCheckerManager.checkPermission(
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
- matches(COMPANION_PKG))).thenReturn(PackageManager.PERMISSION_DENIED);
- when(mMockPackageManager.checkPermission(
+ matchesAttributionSourcePackage(COMPANION_PKG), nullable(String.class),
+ anyBoolean(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ when(mMockPermissionCheckerManager.checkPermission(
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
- matches(CAR_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mMockPackageManager.checkPermission(
+ matchesAttributionSourcePackage(CAR_PKG), nullable(String.class),
+ anyBoolean(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ when(mMockPermissionCheckerManager.checkPermission(
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
- matches(CAR2_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mMockPackageManager.checkPermission(
+ matchesAttributionSourcePackage(CAR2_PKG), nullable(String.class),
+ anyBoolean(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ when(mMockPermissionCheckerManager.checkPermission(
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
- matches(NONUI_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
- when(mMockPackageManager.checkPermission(
+ matchesAttributionSourcePackage(NONUI_PKG), nullable(String.class),
+ anyBoolean(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ when(mMockPermissionCheckerManager.checkPermission(
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
- matches(APPOP_NONUI_PKG))).thenReturn(PackageManager.PERMISSION_DENIED);
+ matchesAttributionSourcePackage(APPOP_NONUI_PKG), nullable(String.class),
+ anyBoolean(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
when(mMockCallsManager.getAudioState()).thenReturn(new CallAudioState(false, 0, 0));
}
@@ -243,14 +277,53 @@
when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
- when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
mSystemStateListener.onCarModeChanged(666, CAR_PKG, true);
verify(mCarModeTracker).handleEnterCarMode(666, CAR_PKG);
assertTrue(mCarModeTracker.isInCarMode());
mSystemStateListener.onPackageUninstalled(CAR_PKG);
- verify(mCarModeTracker).forceExitCarMode(CAR_PKG);
+ verify(mCarModeTracker).forceRemove(CAR_PKG);
+ assertFalse(mCarModeTracker.isInCarMode());
+ }
+
+ /**
+ * Ensure that if we remove a random unrelated app we don't exit car mode.
+ */
+ @SmallTest
+ @Test
+ public void testRandomAppRemovalInCarMode() {
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+ when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
+
+ mSystemStateListener.onCarModeChanged(666, CAR_PKG, true);
+ verify(mCarModeTracker).handleEnterCarMode(666, CAR_PKG);
+ assertTrue(mCarModeTracker.isInCarMode());
+
+ mSystemStateListener.onPackageUninstalled("com.foo.test");
+ verify(mCarModeTracker, never()).forceRemove(CAR_PKG);
+ assertTrue(mCarModeTracker.isInCarMode());
+ }
+
+ @SmallTest
+ @Test
+ public void testAutomotiveProjectionAppRemoval() {
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+ when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
+
+ mSystemStateListener.onAutomotiveProjectionStateSet(CAR_PKG);
+ verify(mCarModeTracker).handleSetAutomotiveProjection(CAR_PKG);
+ assertTrue(mCarModeTracker.isInCarMode());
+
+ mSystemStateListener.onPackageUninstalled(CAR_PKG);
+ verify(mCarModeTracker).forceRemove(CAR_PKG);
assertFalse(mCarModeTracker.isInCarMode());
}
@@ -439,7 +512,7 @@
// Pretend that the call has gone away.
when(mMockCallsManager.getCalls()).thenReturn(Collections.emptyList());
mInCallController.onCallRemoved(mMockCall);
- waitForHandlerAction(new Handler(Looper.getMainLooper()), TelecomSystemTest.TEST_TIMEOUT);
+ waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
verify(mMockPackageManager).revokeRuntimePermission(eq(SYS_PKG),
eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle));
@@ -786,7 +859,7 @@
setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
// Enable car mode
- when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
mInCallController.handleCarModeChange(UiModeManager.DEFAULT_PRIORITY, CAR_PKG, true);
// Now bind; we should only bind to one app.
@@ -816,7 +889,7 @@
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
matches(CAR_PKG))).thenReturn(PackageManager.PERMISSION_DENIED);
// Enable car mode
- when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
// Register the fact that the invalid app entered car mode.
mInCallController.handleCarModeChange(UiModeManager.DEFAULT_PRIORITY, CAR_PKG, true);
@@ -841,39 +914,45 @@
@MediumTest
@Test
public void testBindToService_ThirdPartyApp() throws Exception {
- setupMocks(false /* isExternalCall */);
- setupMockPackageManager(false /* default */, false /* nonui */, true /* appop_nonui */,
- true /* system */, false /* external calls */, false /* self mgd in default */,
- false /* self mgd in car*/);
+ final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .strictness(Strictness.WARN)
+ .spyStatic(PermissionChecker.class)
+ .startMocking();
+ try {
+ setupMocks(false /* isExternalCall */);
+ setupMockPackageManager(false /* default */, false /* nonui */, true /* appop_nonui */,
+ true /* system */, false /* external calls */, false /* self mgd in default */,
+ false /* self mgd in car*/);
- // Enable Third Party Companion App
- when(mMockPackageManager.getPermissionInfo(anyString(), anyInt())).thenReturn(
- mMockPermissionInfo);
- when(mMockPermissionInfo.isAppOp()).thenReturn(true);
- when(mMockAppOpsManager.unsafeCheckOpRawNoThrow(matches(
- AppOpsManager.OPSTR_MANAGE_ONGOING_CALLS), eq(APPOP_NONUI_UID),
- matches(APPOP_NONUI_PKG))).thenReturn(AppOpsManager.MODE_ALLOWED);
+ // Enable Third Party Companion App
+ ExtendedMockito.doReturn(PermissionChecker.PERMISSION_GRANTED).when(() ->
+ PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
+ any(Context.class), eq(Manifest.permission.MANAGE_ONGOING_CALLS),
+ anyInt(), any(AttributionSource.class), nullable(String.class)));
- // Now bind; we should bind to the system dialer and app op non ui app.
- mInCallController.bindToServices(mMockCall);
+ // Now bind; we should bind to the system dialer and app op non ui app.
+ mInCallController.bindToServices(mMockCall);
- // Bind InCallServices
- ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext, times(2)).bindServiceAsUser(
- bindIntentCaptor.capture(),
- any(ServiceConnection.class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
- eq(UserHandle.CURRENT));
+ // Bind InCallServices
+ ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockContext, times(2)).bindServiceAsUser(
+ bindIntentCaptor.capture(),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
- // Verify bind
- assertEquals(2, bindIntentCaptor.getAllValues().size());
+ // Verify bind
+ assertEquals(2, bindIntentCaptor.getAllValues().size());
- // Should have first bound to the system dialer.
- verifyBinding(bindIntentCaptor, 0, SYS_PKG, SYS_CLASS);
+ // Should have first bound to the system dialer.
+ verifyBinding(bindIntentCaptor, 0, SYS_PKG, SYS_CLASS);
- // Should have next bound to the third party app op non ui app.
- verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS);
+ // Should have next bound to the third party app op non ui app.
+ verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS);
+ } finally {
+ mockitoSession.finishMocking();
+ }
}
/**
@@ -951,6 +1030,31 @@
*/
@MediumTest
@Test
+ public void testRandomAppRemovalWhenNotInCarMode() throws Exception {
+ setupMocks(true /* isExternalCall */);
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+ // Bind to default dialer.
+ mInCallController.bindToServices(mMockCall);
+
+ // Uninstall an unrelated app.
+ mSystemStateListener.onPackageUninstalled("com.joe.stuff");
+
+ // Bind InCallServices, just once; we should not re-bind to the same app.
+ ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockContext).bindServiceAsUser(
+ bindIntentCaptor.capture(),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
+ }
+
+ /**
+ * Ensures that the {@link InCallController} will bind to a higher priority car mode service
+ * when one becomes available.
+ */
+ @MediumTest
+ @Test
public void testCarmodeRebindHigherPriority() throws Exception {
setupMocks(true /* isExternalCall */);
setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
@@ -958,7 +1062,7 @@
mInCallController.bindToServices(mMockCall);
// Enable car mode and enter car mode at default priority.
- when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
mInCallController.handleCarModeChange(UiModeManager.DEFAULT_PRIORITY, CAR_PKG, true);
// And change to the second car mode app.
@@ -1105,7 +1209,7 @@
// Now switch to car mode.
// Enable car mode and enter car mode at default priority.
- when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
mInCallController.handleCarModeChange(UiModeManager.DEFAULT_PRIORITY, CAR_PKG, true);
ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -1145,7 +1249,7 @@
// Now switch to car mode.
// Enable car mode and enter car mode at default priority.
- when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ when(mMockSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(true);
mInCallController.handleCarModeChange(UiModeManager.DEFAULT_PRIORITY, CAR_PKG, true);
// We currently will bind to the car-mode InCallService even if there are no calls available
@@ -1379,6 +1483,28 @@
}
}).when(mMockPackageManager).queryIntentServicesAsUser(
any(Intent.class), anyInt(), eq(CURRENT_USER_ID));
+
+ if (useDefaultDialer) {
+ when(mMockPackageManager
+ .getComponentEnabledSetting(new ComponentName(DEF_PKG, DEF_CLASS)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+ }
+
+ when(mMockPackageManager
+ .getComponentEnabledSetting(new ComponentName(SYS_PKG, SYS_CLASS)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
+ when(mMockPackageManager
+ .getComponentEnabledSetting(new ComponentName(CAR_PKG, CAR_CLASS)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
+ when(mMockPackageManager
+ .getComponentEnabledSetting(new ComponentName(COMPANION_PKG, COMPANION_CLASS)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
+ when(mMockPackageManager
+ .getComponentEnabledSetting(new ComponentName(CAR2_PKG, CAR2_CLASS)))
+ .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}
private void setupMockPackageManagerLocationPermission(final String pkg,
@@ -1388,4 +1514,24 @@
? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED);
}
+
+ private static AttributionSourceState matchesAttributionSourcePackage(
+ @Nullable String packageName) {
+ return argThat(new PackageNameArgumentMatcher(packageName));
+ }
+
+ private static class PackageNameArgumentMatcher implements
+ ArgumentMatcher<AttributionSourceState> {
+ @Nullable
+ private final String mPackgeName;
+
+ PackageNameArgumentMatcher(@Nullable String packageName) {
+ mPackgeName = packageName;
+ }
+
+ @Override
+ public boolean matches(@NonNull AttributionSourceState attributionSource) {
+ return Objects.equals(mPackgeName, attributionSource.packageName);
+ }
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
index db44dcd..2b05430 100644
--- a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
@@ -29,6 +29,8 @@
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -65,11 +67,13 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -79,6 +83,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -132,6 +137,7 @@
}
}
+ private static final long TIMEOUT_DELAY = 5000;
private static final Uri TEL_CALL_HANDLE = Uri.parse("tel:+11915552620");
private static final Uri SIP_CALL_HANDLE = Uri.parse("sip:testaddress@testdomain.com");
private static final String CALLER_NAME = "Fake Name";
@@ -139,6 +145,7 @@
private static final String MISSED_CALLS_TITLE = "Missed Calls";
private static final String MISSED_CALLS_MSG = "%s missed calls";
private static final String USER_CALL_ACTIVITY_LABEL = "Phone";
+ private static final String DEFAULT_DIALER_PACKAGE = "com.android.server.telecom.test";
private static final int REQUEST_ID = 0;
private static final long CALL_TIMESTAMP;
@@ -213,6 +220,49 @@
cancelNotificationTestInternal(SECONARY_USER);
}
+ @SmallTest
+ @Test
+ public void testDefaultDialerClear() {
+ MissedCallNotifier missedCallNotifier = setupMissedCallNotificationThroughDefaultDialer();
+ missedCallNotifier.clearMissedCalls(PRIMARY_USER);
+
+ ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendBroadcastAsUser(intentArgumentCaptor.capture(), any(),
+ anyString(), any());
+ Intent sentIntent = intentArgumentCaptor.getValue();
+ assertEquals(0, sentIntent.getIntExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, -1));
+ }
+
+ @SmallTest
+ @Test
+ public void testDefaultDialerIncrement() {
+ MissedCallNotifier missedCallNotifier = setupMissedCallNotificationThroughDefaultDialer();
+ PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
+ MissedCallNotifier.CallInfo fakeCall = makeFakeCallInfo(TEL_CALL_HANDLE, CALLER_NAME,
+ CALL_TIMESTAMP, phoneAccount.getAccountHandle());
+
+ missedCallNotifier.showMissedCallNotification(fakeCall);
+ ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendBroadcastAsUser(intentArgumentCaptor.capture(), any(),
+ anyString(), any());
+
+ Intent sentIntent = intentArgumentCaptor.getValue();
+ assertEquals(1, sentIntent.getIntExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, -1));
+ }
+
+ private MissedCallNotifier setupMissedCallNotificationThroughDefaultDialer() {
+ mComponentContextFixture.addIntentReceiver(
+ TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION, COMPONENT_NAME);
+ when(mDefaultDialerCache.getDefaultDialerApplication(anyInt())).thenReturn(
+ DEFAULT_DIALER_PACKAGE);
+
+ Notification.Builder builder1 = makeNotificationBuilder("builder1");
+ Notification.Builder builder2 = makeNotificationBuilder("builder2");
+ MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
+ makeNotificationBuilderFactory(builder1, builder1, builder2, builder2);
+ return makeMissedCallNotifier(fakeBuilderFactory, PRIMARY_USER);
+ }
+
private void cancelNotificationTestInternal(UserHandle userHandle) {
Notification.Builder builder1 = makeNotificationBuilder("builder1");
Notification.Builder builder2 = makeNotificationBuilder("builder2");
@@ -458,7 +508,7 @@
CallLog.Calls.PRESENTATION_ALLOWED, CALL_TIMESTAMP)
.build();
- when(cp.query(anyString(), nullable(String.class), eq(queryUri), nullable(String[].class),
+ when(cp.query(any(), eq(queryUri), nullable(String[].class),
nullable(Bundle.class), nullable(ICancellationSignal.class)))
.thenReturn(mockMissedCallsCursor);
@@ -528,7 +578,7 @@
PRIMARY_USER.getIdentifier());
IContentProvider cp = getContentProviderForUser(PRIMARY_USER.getIdentifier());
- when(cp.query(anyString(), nullable(String.class), eq(queryUri), nullable(String[].class),
+ when(cp.query(any(), eq(queryUri), nullable(String[].class),
nullable(Bundle.class), nullable(ICancellationSignal.class)))
.thenReturn(mockMissedCallsCursor);
@@ -611,7 +661,7 @@
assertNotNull("Not expecting null options bundle", bundleCaptor.getValue());
BroadcastOptions options = new BroadcastOptions(bundleCaptor.getValue());
assertTrue("App must have a temporary exemption set.",
- options.getTemporaryAppWhitelistDuration() > 0);
+ options.getTemporaryAppAllowlistDuration() > 0);
// A notification should never be posted by Telecom
verify(mNotificationManager, never()).notifyAsUser(nullable(String.class), anyInt(),
diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
index a5b78b7..e6c6bac 100644
--- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
+++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
@@ -110,7 +110,7 @@
when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(
any(PhoneAccountHandle.class))).thenReturn(mPhoneAccount);
when(mPhoneAccount.isSelfManaged()).thenReturn(true);
- when(mSystemStateHelper.isCarMode()).thenReturn(false);
+ when(mSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(false);
}
@Override
diff --git a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
index 6c941fe..a503283 100644
--- a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
+++ b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
@@ -1,13 +1,12 @@
package com.android.server.telecom.tests;
-import static com.android.server.telecom.TelecomSystem.*;
+import static com.android.server.telecom.TelecomSystem.SyncRoot;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
@@ -17,6 +16,7 @@
import android.telecom.Connection;
import android.telecom.ParcelableCall;
import android.telecom.PhoneAccountHandle;
+import android.telephony.ims.ImsCallProfile;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.telecom.Call;
@@ -26,7 +26,6 @@
import com.android.server.telecom.ParcelableCallUtils;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneNumberUtilsAdapter;
-import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.ui.ToastFactory;
import org.junit.After;
@@ -98,6 +97,7 @@
Bundle parceledExtras = call.getExtras();
assertFalse(parceledExtras.containsKey(Connection.EXTRA_SIP_INVITE));
+ assertTrue(parceledExtras.containsKey(ImsCallProfile.EXTRA_IS_BUSINESS_CALL));
assertFalse(parceledExtras.containsKey("SomeExtra"));
assertTrue(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
}
@@ -115,6 +115,7 @@
Bundle parceledExtras = call.getExtras();
assertTrue(parceledExtras.containsKey(Connection.EXTRA_SIP_INVITE));
+ assertTrue(parceledExtras.containsKey(ImsCallProfile.EXTRA_IS_BUSINESS_CALL));
assertTrue(parceledExtras.containsKey("SomeExtra"));
assertTrue(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
}
@@ -128,6 +129,7 @@
Bundle parceledExtras = call.getExtras();
assertTrue(parceledExtras.containsKey(Connection.EXTRA_SIP_INVITE));
+ assertTrue(parceledExtras.containsKey(ImsCallProfile.EXTRA_IS_BUSINESS_CALL));
assertFalse(parceledExtras.containsKey("SomeExtra"));
assertFalse(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
}
@@ -141,6 +143,7 @@
Bundle parceledExtras = call.getExtras();
assertFalse(parceledExtras.containsKey(Connection.EXTRA_SIP_INVITE));
+ assertFalse(parceledExtras.containsKey(ImsCallProfile.EXTRA_IS_BUSINESS_CALL));
assertFalse(parceledExtras.containsKey("SomeExtra"));
assertFalse(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
}
@@ -192,6 +195,7 @@
extras.putString(Connection.EXTRA_SIP_INVITE, "scary data");
extras.putString("SomeExtra", "Extra Extra");
extras.putString(Connection.EXTRA_CALL_SUBJECT, "Blah");
+ extras.putBoolean(ImsCallProfile.EXTRA_IS_BUSINESS_CALL, true);
return extras;
}
}
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 38f63d2..0e93481 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -79,6 +79,16 @@
}
@Override
+ public VibrationEffect resolve(int defaultAmplitude) {
+ return this;
+ }
+
+ @Override
+ public VibrationEffect scale(float scaleFactor) {
+ return this;
+ }
+
+ @Override
public void validate() {
// not needed
}
diff --git a/tests/src/com/android/server/telecom/tests/SessionTest.java b/tests/src/com/android/server/telecom/tests/SessionTest.java
index 6a14a64..4be3dad 100644
--- a/tests/src/com/android/server/telecom/tests/SessionTest.java
+++ b/tests/src/com/android/server/telecom/tests/SessionTest.java
@@ -173,6 +173,36 @@
}
/**
+ * Ensure creating two sessions and setting the child as the parent to itself doesn't cause a
+ * crash due to infinite recursion.
+ */
+ @SmallTest
+ @Test
+ public void testRecursion_toString_childCircDep() {
+ Log.startSession("testParent");
+ // Running in the same thread, so mark as invisible subsession
+ Session childSession = Log.getSessionManager()
+ .createSubsession(true /*isStartedFromActiveSession*/);
+ Log.continueSession(childSession, "child");
+ Session parentSession = childSession.getParentSession();
+ // Create a circular dependency and ensure we do not crash
+ childSession.setParentSession(childSession);
+
+ // Make sure calling these methods does not result in a crash
+ try {
+ parentSession.toString();
+ childSession.toString();
+ } catch (Exception e) {
+ fail("Exception: " + e.getMessage());
+ } finally {
+ // End child
+ Log.endSession();
+ // End parent
+ Log.endSession();
+ }
+ }
+
+ /**
* Ensure creating two sessions that are parent/child of each other does not lead to a crash
* or infinite recursion when using Session#getInfo.
*/
diff --git a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
index 893ae3d..dc7d1fd 100644
--- a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
@@ -48,6 +48,7 @@
import com.android.server.telecom.SystemStateHelper;
import com.android.server.telecom.SystemStateHelper.SystemStateListener;
+import com.android.server.telecom.TelecomSystem;
import org.junit.After;
import org.junit.Before;
@@ -60,6 +61,7 @@
import org.mockito.internal.util.reflection.FieldSetter;
import java.util.List;
+import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -77,6 +79,7 @@
@Mock SensorManager mSensorManager;
@Mock Intent mIntentEnter;
@Mock Intent mIntentExit;
+ TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
@Override
@Before
@@ -91,6 +94,8 @@
when(mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)).thenReturn(mGravitySensor);
when(mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)).thenReturn(mProxSensor);
+ doReturn(mUiModeManager).when(mContext).getSystemService(UiModeManager.class);
+
mComponentContextFixture.putFloatResource(
R.dimen.device_on_ear_xy_gravity_threshold, 5.5f);
mComponentContextFixture.putFloatResource(
@@ -106,7 +111,7 @@
@SmallTest
@Test
public void testListeners() throws Exception {
- SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
+ SystemStateHelper systemStateHelper = new SystemStateHelper(mContext, mLock);
assertFalse(systemStateHelper.removeListener(mSystemStateListener));
systemStateHelper.addListener(mSystemStateListener);
@@ -117,17 +122,53 @@
@SmallTest
@Test
public void testQuerySystemForCarMode_True() {
- when(mContext.getSystemService(Context.UI_MODE_SERVICE)).thenReturn(mUiModeManager);
when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
- assertTrue(new SystemStateHelper(mContext).isCarMode());
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@Test
public void testQuerySystemForCarMode_False() {
- when(mContext.getSystemService(Context.UI_MODE_SERVICE)).thenReturn(mUiModeManager);
when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_NORMAL);
- assertFalse(new SystemStateHelper(mContext).isCarMode());
+ assertFalse(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
+ }
+
+ @SmallTest
+ @Test
+ public void testQuerySystemForAutomotiveProjection_True() {
+ when(mUiModeManager.getActiveProjectionTypes())
+ .thenReturn(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE);
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
+
+ when(mUiModeManager.getActiveProjectionTypes())
+ .thenReturn(UiModeManager.PROJECTION_TYPE_ALL);
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
+ }
+
+ @SmallTest
+ @Test
+ public void testQuerySystemForAutomotiveProjection_False() {
+ when(mUiModeManager.getActiveProjectionTypes())
+ .thenReturn(UiModeManager.PROJECTION_TYPE_NONE);
+ assertFalse(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
+ }
+
+ @SmallTest
+ @Test
+ public void testQuerySystemForAutomotiveProjectionAndCarMode_True() {
+ when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
+ when(mUiModeManager.getActiveProjectionTypes())
+ .thenReturn(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE);
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
+ }
+
+ @SmallTest
+ @Test
+ public void testQuerySystemForAutomotiveProjectionOrCarMode_nullService() {
+ when(mContext.getSystemService(UiModeManager.class))
+ .thenReturn(mUiModeManager) // Without this, class construction will throw NPE.
+ .thenReturn(null);
+ assertFalse(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@@ -135,7 +176,7 @@
public void testPackageRemoved() {
ArgumentCaptor<BroadcastReceiver> receiver =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- new SystemStateHelper(mContext).addListener(mSystemStateListener);
+ new SystemStateHelper(mContext, mLock).addListener(mSystemStateListener);
verify(mContext, atLeastOnce())
.registerReceiver(receiver.capture(), any(IntentFilter.class));
Intent packageRemovedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
@@ -149,7 +190,7 @@
public void testReceiverAndIntentFilter() {
ArgumentCaptor<IntentFilter> intentFilterCaptor =
ArgumentCaptor.forClass(IntentFilter.class);
- new SystemStateHelper(mContext);
+ new SystemStateHelper(mContext, mLock);
verify(mContext, times(2)).registerReceiver(
any(BroadcastReceiver.class), intentFilterCaptor.capture());
@@ -186,7 +227,7 @@
public void testOnEnterExitCarMode() {
ArgumentCaptor<BroadcastReceiver> receiver =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- new SystemStateHelper(mContext).addListener(mSystemStateListener);
+ new SystemStateHelper(mContext, mLock).addListener(mSystemStateListener);
verify(mContext, atLeastOnce())
.registerReceiver(receiver.capture(), any(IntentFilter.class));
@@ -204,6 +245,40 @@
@SmallTest
@Test
+ public void testOnSetReleaseAutomotiveProjection() {
+ SystemStateHelper systemStateHelper = new SystemStateHelper(mContext, mLock);
+ // We don't care what listener is registered, that's an implementation detail, but we need
+ // to call methods on whatever it is.
+ ArgumentCaptor<UiModeManager.OnProjectionStateChangedListener> listenerCaptor =
+ ArgumentCaptor.forClass(UiModeManager.OnProjectionStateChangedListener.class);
+ verify(mUiModeManager).addOnProjectionStateChangedListener(
+ eq(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), any(), listenerCaptor.capture());
+ systemStateHelper.addListener(mSystemStateListener);
+
+ String packageName1 = "Sufjan Stevens";
+ String packageName2 = "The Ascension";
+
+ // Should pay attention to automotive projection, though.
+ listenerCaptor.getValue().onProjectionStateChanged(
+ UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, Set.of(packageName2));
+ verify(mSystemStateListener).onAutomotiveProjectionStateSet(packageName2);
+
+ // Without any automotive projection, it should see it as released.
+ listenerCaptor.getValue().onProjectionStateChanged(
+ UiModeManager.PROJECTION_TYPE_NONE, Set.of());
+ verify(mSystemStateListener).onAutomotiveProjectionStateReleased();
+
+ // Try the whole thing again, with different values.
+ listenerCaptor.getValue().onProjectionStateChanged(
+ UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, Set.of(packageName1));
+ verify(mSystemStateListener).onAutomotiveProjectionStateSet(packageName1);
+ listenerCaptor.getValue().onProjectionStateChanged(
+ UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, Set.of());
+ verify(mSystemStateListener, times(2)).onAutomotiveProjectionStateReleased();
+ }
+
+ @SmallTest
+ @Test
public void testDeviceOnEarCorrectlyDetected() {
doAnswer(invocation -> {
SensorEventListener listener = invocation.getArgument(0);
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 0dfe29a..3cec50b 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -460,10 +460,10 @@
@Test
public void testGetPhoneAccount() throws RemoteException {
makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
- assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16)
- .getAccountHandle());
- assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17)
- .getAccountHandle());
+ assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16,
+ mContext.getPackageName()).getAccountHandle());
+ assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17,
+ mContext.getPackageName()).getAccountHandle());
}
@SmallTest
@@ -1202,6 +1202,39 @@
}
/**
+ * Ensure self-managed calls cannot be ended using {@link TelecomManager#endCall()}.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testCannotEndSelfManagedCall() throws Exception {
+ Call call = mock(Call.class);
+ when(call.isSelfManaged()).thenReturn(true);
+ when(call.getState()).thenReturn(CallState.ACTIVE);
+ when(mFakeCallsManager.getFirstCallWithState(any()))
+ .thenReturn(call);
+ assertFalse(mTSIBinder.endCall(TEST_PACKAGE));
+ verify(mFakeCallsManager, never()).disconnectCall(eq(call));
+ }
+
+ /**
+ * Ensure self-managed calls cannot be answered using {@link TelecomManager#acceptRingingCall()}
+ * or {@link TelecomManager#acceptRingingCall(int)}.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testCannotAnswerSelfManagedCall() throws Exception {
+ Call call = mock(Call.class);
+ when(call.isSelfManaged()).thenReturn(true);
+ when(call.getState()).thenReturn(CallState.ACTIVE);
+ when(mFakeCallsManager.getFirstCallWithState(any()))
+ .thenReturn(call);
+ mTSIBinder.acceptRingingCall(TEST_PACKAGE);
+ verify(mFakeCallsManager, never()).answerCall(eq(call), anyInt());
+ }
+
+ /**
* Register phone accounts for the supplied PhoneAccountHandles to make them
* visible to all users (via the isVisibleToCaller method in TelecomServiceImpl.
* @param handles the handles for which phone accounts should be created for.
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 5c1cdc4..7f462d4 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -365,7 +365,7 @@
// Next, create the TelecomSystem, our system under test
setupTelecomSystem();
- // Need to reset teseting tag here
+ // Need to reset testing tag here
Log.setTag(TESTING_TAG);
// Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
@@ -401,11 +401,9 @@
mConnectionServiceFixtureA.waitForHandlerToClear();
mConnectionServiceFixtureB.waitForHandlerToClear();
- // Print out any incomplete sessions for debugging tests
- String sessions = Log.getSessionManager().printActiveSessions();
- if (!TextUtils.isEmpty(sessions)) {
- Log.w(this, "Active Sessions:\n" + sessions);
- }
+ // Forcefully clean all sessions at the end of the test, which will also log any stale
+ // sessions for debugging.
+ Log.getSessionManager().cleanupStaleSessions(0);
mTelecomSystem = null;
super.tearDown();