Merge "Allow reject request in ANSWERED state"
diff --git a/Android.bp b/Android.bp
index 50a41d0..0d89b00 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,24 @@
+genrule {
+ name: "statslog-telecom-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telecom"
+ + " --javaPackage com.android.server.telecom --javaClass TelecomStatsLog",
+ out: ["com/android/server/telecom/TelecomStatsLog.java"],
+}
+
+filegroup {
+ name: "Telecom-srcs",
+ srcs: [
+ "src/**/*.java",
+ ":statslog-telecom-java-gen",
+ ],
+}
+
// Build the Telecom service.
android_app {
name: "Telecom",
srcs: [
- "src/**/*.java",
+ ":Telecom-srcs",
"proto/**/*.proto",
],
resource_dirs: ["res"],
@@ -25,7 +41,7 @@
static_libs: [
"android-ex-camera2",
"guava",
- "mockito-target-inline",
+ "mockito-target-extended",
"androidx.test.rules",
"platform-test-annotations",
"androidx.legacy_legacy-support-core-ui",
@@ -36,7 +52,7 @@
],
srcs: [
"tests/src/**/*.java",
- "src/**/*.java",
+ ":Telecom-srcs",
"proto/**/*.proto",
],
proto: {
@@ -54,7 +70,10 @@
"android.test.runner",
],
- jni_libs: ["libdexmakerjvmtiagent"],
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
aaptflags: [
"--auto-add-overlay",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3003aad..327d0a2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,80 +15,75 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.server.telecom"
- coreApp="true"
- android:sharedUserId="android.uid.system">
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.server.telecom"
+ coreApp="true"
+ android:sharedUserId="android.uid.system">
- <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION" />
- <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT" />
+ <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION"/>
+ <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT"/>
<!-- Prevents the activity manager from delaying any activity-start
requests by this package, including requests immediately after
the user presses "home". -->
- <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE" />
- <uses-permission android:name="android.permission.BIND_INCALL_SERVICE" />
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO" />
- <uses-permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION" />
- <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
- <uses-permission android:name="android.permission.HANDLE_CALL_INTENT" />
- <uses-permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
- <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE"/>
+ <uses-permission android:name="android.permission.BIND_INCALL_SERVICE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+ <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO"/>
+ <uses-permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION"/>
+ <uses-permission android:name="android.permission.CALL_PRIVILEGED"/>
+ <uses-permission android:name="android.permission.HANDLE_CALL_INTENT"/>
+ <uses-permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS"/>
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<!-- Required to determine source of ongoing audio recordings. -->
- <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
- <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
- <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.SEND_SMS" />
- <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
- <uses-permission android:name="android.permission.VIBRATE" />
- <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <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="android.permission.MODIFY_AUDIO_ROUTING"/>
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+ <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.SEND_SMS"/>
+ <uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <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"/>
- <permission
- android:name="android.permission.BROADCAST_CALLLOG_INFO"
- android:label="Broadcast the call type/duration information"
- android:protectionLevel="signature|system"/>
+ <permission android:name="android.permission.BROADCAST_CALLLOG_INFO"
+ android:label="Broadcast the call type/duration information"
+ android:protectionLevel="signature|system"/>
- <permission
- android:name="android.permission.PROCESS_CALLLOG_INFO"
- android:label="Register to handle the broadcasted call type/duration information"
- android:protectionLevel="signature|system"/>
+ <permission android:name="android.permission.PROCESS_CALLLOG_INFO"
+ android:label="Register to handle the broadcasted call type/duration information"
+ android:protectionLevel="signature|system"/>
- <permission
- android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION"
- android:label="Broadcast phone account registration"
- android:protectionLevel="signature|system"/>
+ <permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION"
+ android:label="Broadcast phone account registration"
+ android:protectionLevel="signature|system"/>
- <permission
- android:name="android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"
- android:label="Process phone account registration"
- android:protectionLevel="signature|system"/>
+ <permission android:name="android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"
+ android:label="Process phone account registration"
+ android:protectionLevel="signature|system"/>
- <permission
- android:name="android.permission.HANDLE_CALL_INTENT"
- android:label="Protects handling the call intent via the TelecomManager API."
- android:protectionLevel="signature|system"/>
+ <permission android:name="android.permission.HANDLE_CALL_INTENT"
+ android:label="Protects handling the call intent via the TelecomManager API."
+ android:protectionLevel="signature|system"/>
<application android:label="@string/telecommAppLabel"
- android:icon="@mipmap/ic_launcher_phone"
- android:allowBackup="false"
- android:supportsRtl="true"
- android:process="system"
- android:usesCleartextTraffic="false"
- android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true">
+ android:icon="@mipmap/ic_launcher_phone"
+ android:allowBackup="false"
+ android:supportsRtl="true"
+ android:process="system"
+ android:usesCleartextTraffic="false"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
<!-- CALL vs CALL_PRIVILEGED vs CALL_EMERGENCY
We have three different intents through which a call can be initiated each with its
@@ -104,60 +99,61 @@
<!-- Activity that displays UI for managing blocked numbers. -->
<activity android:name=".settings.BlockedNumbersActivity"
- android:label="@string/blocked_numbers"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:theme="@style/Theme.Telecom.BlockedNumbers"
- android:process=":ui"
- android:exported="true">
+ android:label="@string/blocked_numbers"
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:theme="@style/Theme.Telecom.BlockedNumbers"
+ android:process=":ui"
+ android:exported="true">
<intent-filter>
- <action android:name="android.telecom.action.MANAGE_BLOCKED_NUMBERS" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.telecom.action.MANAGE_BLOCKED_NUMBERS"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".settings.CallBlockDisabledActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance"
- android:theme="@style/Theme.Telecomm.Transparent"
- android:process=":ui">
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Telecomm.Transparent"
+ android:process=":ui">
</activity>
<!-- Activity that starts the outgoing call process by listening to CALL intent which
- contain contact information in the intent's data. CallActivity handles any data
- URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
- contacts provider entries. Any data not fitting the schema described is ignored. -->
+ contain contact information in the intent's data. CallActivity handles any data
+ URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
+ contacts provider entries. Any data not fitting the schema described is ignored. -->
<activity android:name=".components.UserCallActivity"
- android:label="@string/userCallActivityLabel"
- android:theme="@style/Theme.Telecomm.Transparent"
- android:permission="android.permission.CALL_PHONE"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:label="@string/userCallActivityLabel"
+ android:theme="@style/Theme.Telecomm.Transparent"
+ android:permission="android.permission.CALL_PHONE"
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:exported="true">
<!-- CALL action intent filters for the various ways of initiating an outgoing call. -->
<intent-filter>
- <action android:name="android.intent.action.CALL" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="tel" />
+ <action android:name="android.intent.action.CALL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="tel"/>
</intent-filter>
<!-- Specify an icon for SIP calls so that quick contacts widget shows a special SIP
- icon for calls to SIP addresses. -->
+ icon for calls to SIP addresses. -->
<intent-filter android:icon="@drawable/ic_launcher_sip_call">
- <action android:name="android.intent.action.CALL" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="sip" />
+ <action android:name="android.intent.action.CALL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="sip"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.CALL" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="voicemail" />
+ <action android:name="android.intent.action.CALL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="voicemail"/>
</intent-filter>
<!-- Omit default category below so that all Intents sent to this filter must be
- explicit. -->
+ explicit. -->
<intent-filter>
- <action android:name="android.intent.action.CALL" />
- <data android:mimeType="vnd.android.cursor.item/phone" />
- <data android:mimeType="vnd.android.cursor.item/phone_v2" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <action android:name="android.intent.action.CALL"/>
+ <data android:mimeType="vnd.android.cursor.item/phone"/>
+ <data android:mimeType="vnd.android.cursor.item/phone_v2"/>
+ <data android:mimeType="vnd.android.cursor.item/person"/>
</intent-filter>
</activity>
@@ -167,30 +163,30 @@
processed. High priority of 1000 is used in all intent filters to prevent anything but
the system from processing this intent (b/8871505). -->
<activity-alias android:name="PrivilegedCallActivity"
- android:targetActivity=".components.UserCallActivity"
- android:permission="android.permission.CALL_PRIVILEGED"
- android:process=":ui">
+ android:targetActivity=".components.UserCallActivity"
+ android:permission="android.permission.CALL_PRIVILEGED"
+ android:process=":ui">
<intent-filter android:priority="1000">
- <action android:name="android.intent.action.CALL_PRIVILEGED" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="tel" />
+ <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="tel"/>
</intent-filter>
<intent-filter android:priority="1000"
- android:icon="@drawable/ic_launcher_sip_call">
- <action android:name="android.intent.action.CALL_PRIVILEGED" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="sip" />
+ android:icon="@drawable/ic_launcher_sip_call">
+ <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="sip"/>
</intent-filter>
<intent-filter android:priority="1000">
- <action android:name="android.intent.action.CALL_PRIVILEGED" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="voicemail" />
+ <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="voicemail"/>
</intent-filter>
<intent-filter android:priority="1000">
- <action android:name="android.intent.action.CALL_PRIVILEGED" />
- <data android:mimeType="vnd.android.cursor.item/phone" />
- <data android:mimeType="vnd.android.cursor.item/phone_v2" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+ <data android:mimeType="vnd.android.cursor.item/phone"/>
+ <data android:mimeType="vnd.android.cursor.item/phone_v2"/>
+ <data android:mimeType="vnd.android.cursor.item/person"/>
</intent-filter>
</activity-alias>
@@ -200,131 +196,129 @@
1000 is used in all intent filters to prevent anything but the system from processing
this intent (b/8871505). -->
<!-- TODO: Is there really a notion of an emergency SIP number? If not, can
- that scheme be removed from this activity? -->
+ that scheme be removed from this activity? -->
<activity-alias android:name="EmergencyCallActivity"
- android:targetActivity=".components.UserCallActivity"
- android:permission="android.permission.CALL_PRIVILEGED"
- android:process=":ui">
+ android:targetActivity=".components.UserCallActivity"
+ android:permission="android.permission.CALL_PRIVILEGED"
+ android:process=":ui">
<intent-filter android:priority="1000">
- <action android:name="android.intent.action.CALL_EMERGENCY" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="tel" />
+ <action android:name="android.intent.action.CALL_EMERGENCY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="tel"/>
</intent-filter>
<intent-filter android:priority="1000"
- android:icon="@drawable/ic_launcher_sip_call">
- <action android:name="android.intent.action.CALL_EMERGENCY" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="sip" />
+ android:icon="@drawable/ic_launcher_sip_call">
+ <action android:name="android.intent.action.CALL_EMERGENCY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="sip"/>
</intent-filter>
<intent-filter android:priority="1000">
- <action android:name="android.intent.action.CALL_EMERGENCY" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="voicemail" />
+ <action android:name="android.intent.action.CALL_EMERGENCY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="voicemail"/>
</intent-filter>
<intent-filter android:priority="1000">
- <action android:name="android.intent.action.CALL_EMERGENCY" />
- <data android:mimeType="vnd.android.cursor.item/phone" />
- <data android:mimeType="vnd.android.cursor.item/phone_v2" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <action android:name="android.intent.action.CALL_EMERGENCY"/>
+ <data android:mimeType="vnd.android.cursor.item/phone"/>
+ <data android:mimeType="vnd.android.cursor.item/phone_v2"/>
+ <data android:mimeType="vnd.android.cursor.item/person"/>
</intent-filter>
</activity-alias>
- <receiver android:name=".components.TelecomBroadcastReceiver" android:exported="false"
- android:process="system">
+ <receiver android:name=".components.TelecomBroadcastReceiver"
+ android:exported="false"
+ android:process="system">
<intent-filter>
- <action android:name="com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS" />
- <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION" />
- <action android:name="com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION" />
- <action android:name="com.android.server.telecom.ACTION_ANSWER_FROM_NOTIFICATION" />
- <action android:name="com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION" />
- <action android:name="com.android.server.telecom.PROCEED_WITH_CALL" />
- <action android:name="com.android.server.telecom.CANCEL_CALL" />
- <action android:name="com.android.server.telecom.PROCEED_WITH_REDIRECTED_CALL" />
- <action android:name="com.android.server.telecom.CANCEL_REDIRECTED_CALL" />
+ <action android:name="com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS"/>
+ <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION"/>
+ <action android:name="com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION"/>
+ <action android:name="com.android.server.telecom.ACTION_ANSWER_FROM_NOTIFICATION"/>
+ <action android:name="com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION"/>
+ <action android:name="com.android.server.telecom.PROCEED_WITH_CALL"/>
+ <action android:name="com.android.server.telecom.CANCEL_CALL"/>
+ <action android:name="com.android.server.telecom.PROCEED_WITH_REDIRECTED_CALL"/>
+ <action android:name="com.android.server.telecom.CANCEL_REDIRECTED_CALL"/>
</intent-filter>
</receiver>
<receiver android:name=".components.AppUninstallBroadcastReceiver"
- android:process="system">
+ android:process="system"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
- <data android:scheme="package" />
+ <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
+ <data android:scheme="package"/>
</intent-filter>
</receiver>
<activity android:name=".RespondViaSmsSettings"
- android:label="@string/respond_via_sms_setting_title"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:theme="@style/Theme.Telecom.DialerSettings"
- android:process=":ui">
+ android:label="@string/respond_via_sms_setting_title"
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:theme="@style/Theme.Telecom.DialerSettings"
+ android:process=":ui"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <action android:name="android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.MAIN"/>
+ <action android:name="android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".settings.EnableAccountPreferenceActivity"
- android:label="@string/enable_account_preference_title"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:theme="@style/Theme.Telecom.DialerSettings"
- android:process=":ui">
+ android:label="@string/enable_account_preference_title"
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:theme="@style/Theme.Telecom.DialerSettings"
+ android:process=":ui"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".components.ErrorDialogActivity"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance"
- android:theme="@style/Theme.Telecomm.Transparent"
- android:process=":ui">
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Telecomm.Transparent"
+ android:process=":ui">
</activity>
<activity android:name=".ui.ConfirmCallDialogActivity"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance"
- android:theme="@style/Theme.Telecomm.Transparent"
- android:process=":ui">
- </activity>
-
- <activity android:name=".ui.CallRedirectionConfirmDialogActivity"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance"
- android:theme="@style/Theme.Telecomm.Transparent"
- android:process=":ui">
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Telecomm.Transparent"
+ android:process=":ui">
</activity>
<activity android:name=".ui.CallRedirectionTimeoutDialogActivity"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance"
- android:theme="@style/Theme.Telecomm.Transparent"
- android:process=":ui">
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Telecomm.Transparent"
+ android:process=":ui">
</activity>
<activity android:name=".ui.TelecomDeveloperMenu"
- android:label="@string/developer_title"
- android:exported="false"
- android:process=":ui" />
+ android:label="@string/developer_title"
+ android:exported="false"
+ android:process=":ui"/>
<service android:name=".components.BluetoothPhoneService"
- android:singleUser="true"
- android:process="system">
+ android:singleUser="true"
+ android:process="system"
+ android:exported="true">
<intent-filter>
- <action android:name="android.bluetooth.IBluetoothHeadsetPhone" />
+ <action android:name="android.bluetooth.IBluetoothHeadsetPhone"/>
</intent-filter>
</service>
<service android:name=".components.TelecomService"
- android:singleUser="true"
- android:process="system">
+ android:singleUser="true"
+ android:process="system"
+ android:exported="true">
<intent-filter>
- <action android:name="android.telecom.ITelecomService" />
+ <action android:name="android.telecom.ITelecomService"/>
</intent-filter>
</service>
diff --git a/OWNERS b/OWNERS
index 94409ef..39be2c1 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,6 @@
breadley@google.com
hallliu@google.com
tgunn@google.com
-paulye@google.com
+xiaotonj@google.com
+shuoq@google.com
+rgreenwalt@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 75feeb6..2e14650 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -16,5 +16,15 @@
}
]
}
+ ],
+ "presubmit-large": [
+ {
+ "name": "CtsTelecomTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
]
}
diff --git a/res/raw/record.ogg b/res/raw/record.ogg
index a023e6d..732b42f 100644
--- a/res/raw/record.ogg
+++ b/res/raw/record.ogg
Binary files differ
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 9e86012..2857be3 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Boodskap"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Oproep is ontkoppel"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Die oproep na <xliff:g id="CALLER">%s</xliff:g> is ontkoppel as gevolg van \'n noodoproep wat gemaak word."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Jou oproep is ontkoppel as gevolg van \'n noodoproep wat gemaak word."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Agtergrondoproep"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> het \'n oproep in die agtergrond geplaas. Hierdie program kan dalk toegang tot oudio kry en dit oor die oproep speel."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> het opgehou reageer"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Jou oproep het die foonprogram gebruik wat saam met jou toestel gekom het"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Oproep stilgemaak."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Luidsprekerfoon geaktiveer."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kan nie nou praat nie. Hoe\'s dit?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Oproepblokkering"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Agtergrondoproepe"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Oproepe is ontkoppel"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Omgevalde foonprogramme"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"As jy hierdie oproep maak, sal dit jou <xliff:g id="OTHER_APP">%1$s</xliff:g>-oproep beëindig."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Kies hoe om hierdie oproep te maak"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Herlei oproep deur <xliff:g id="OTHER_APP">%1$s</xliff:g> te gebruik"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 4d17ade..df8215c 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 6b16d51..7e204d0 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -74,10 +73,10 @@
<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>
+ <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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 13d843e..2f5de68 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 1f4b36d..d79343f 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mesaj"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Əlaqəsi kəsilmiş zəng"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Hazırda təcili zəng edildiyi üçün <xliff:g id="CALLER">%s</xliff:g> ilə zəng kəsilib."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Təcili zəng edildiyinə görə zənginizin əlaqəsi kəsildi."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Arxa fon zəngi"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> arxa fonda zəng edib. Bu tətbiq zəng ilə daxil ola və oxuda bilər."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> tətbiqində xəta baş verdi"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Zəng üçün cihazda əvvəlcədən quraşdırılan telefon tətbiqindən istifadə edildi"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Səssiz zəng edin."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Spikerfon aktivdir."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"İndi danışmaq olmur. Nə olub?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Zəngi Bloklama"</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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Xəta baş verən telefon tətbiqləri"</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>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 155b439..eba8c5c 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -20,7 +20,7 @@
<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>
- <string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"Propušten poziv za Work"</string>
+ <string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"Propušten poslovni poziv"</string>
<string name="notification_missedCallsTitle" msgid="3910479625507893809">"Propušteni pozivi"</string>
<string name="notification_missedCallsMsg" msgid="5055782736170916682">"Broj propuštenih poziva: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
<string name="notification_missedCallTicker" msgid="6731461957487087769">"Propušten poziv od: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Poruka"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Poziv je prekinut"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Poziv sa <xliff:g id="CALLER">%s</xliff:g> je prekinut jer se upućuje hitni poziv."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Poziv je prekinut jer se upućuje hitni poziv."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Poziv u pozadini"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikacija <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> je uputila poziv u pozadini. Ona može da pristupa zvuku i pušta ga tokom poziva."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> više ne reaguje"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Poziv je koristio aplikaciju za telefoniranje koju ste dobili uz uređaj"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Zvuk poziva je isključen."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Spikerfon je omogućen."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"U gužvi sam. O čemu se radi?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokiranje poziva"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Pozivi u pozadini"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Prekinuti pozivi"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplikacije za telefoniranje koje su otkazale"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ako uputite ovaj poziv, završićete <xliff:g id="OTHER_APP">%1$s</xliff:g> poziv."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Izaberite kako želite da uputite ovaj poziv"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Preusmeri poziv pomoću: <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 26ad420..b6dd707 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -27,16 +27,17 @@
<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>
+ <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_crashedInCallService_title" msgid="7440244344965656743">"Збой у праграме \"Тэлефон\""</string>
- <string name="notification_crashedInCallService_body" msgid="2307501918379604204">"У праграме \"<xliff:g id="IN_CALL_SERVICE_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="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>
- <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_2" msgid="2052951316129952406">"Я зараз перазваню."</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>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 24363de..7afddc2 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index e288710..cf04d40 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index fd53b1c..1968357 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Poruka"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Poziv je prekinut"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Poziv upućen kontaktu <xliff:g id="CALLER">%s</xliff:g> je prekinut zbog upućivanja hitnog poziva."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Poziv je prekinut zbog upućivanja hitnog poziva."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Poziv u pozadini"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikacija <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> je uputila poziv u pozadini. Ova aplikacija može pristupati zvuku i reproducirati ga tokom poziva."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Aplikacija <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> je prestala reagirati"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Za poziv se koristila aplikacija za telefon koju ste dobili uz uređaj"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Zvuk poziva je isključen."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Zvučnik je omogućen."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Ne mogu sada pričati. O čemu se radi?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokiranje poziva"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Pozivi u pozadini"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Prekinuti pozivi"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Padovi aplikacija za telefon"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Upućivanje ovog poziva će prekinuti poziv: <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Odaberite kako želite uputiti ovaj poziv"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Preusmjeri poziv pomoću aplikacije <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
@@ -115,7 +113,7 @@
<string name="phone_settings_payphone_txt" msgid="5003987966052543965">"Telefonska govornica"</string>
<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 neidentificiranih pozivalaca"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokiraj pozive neidentificiranih pozivaoca"</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>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index c230735..69a7b6e 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Missatge"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Trucada desconnectada"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"La trucada a <xliff:g id="CALLER">%s</xliff:g> s\'ha desconnectat perquè s\'ha fet una trucada d\'emergència."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"La teva trucada s\'ha desconnectat perquè s\'ha fet una trucada d\'emergència."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Trucada en segon pla"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ha fet una trucada en segon pla. És possible que aquesta aplicació estigui accedint a l\'àudio i reproduint-lo a través de la trucada."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> ha deixat de respondre"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"A la trucada s\'ha fet servir l\'aplicació de telèfon que hi ha al dispositiu"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Trucada silenciada."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Altaveu activat."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Ara no puc parlar. Què passa?"</string>
@@ -46,7 +45,7 @@
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"Resposta ràpida"</string>
<string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"Missatge enviat a <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"No s\'ha pogut enviar el missatge a <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
- <string name="enable_account_preference_title" msgid="6949224486748457976">"Comptes de trucades"</string>
+ <string name="enable_account_preference_title" msgid="6949224486748457976">"Comptes de trucada"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Només es permeten les trucades d\'emergència."</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Aquesta aplicació no pot fer trucades sortints sense el permís del telèfon."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"Per realitzar una trucada, introdueix un número vàlid."</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Bloqueig de trucades"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Trucades en segon pla"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Trucades desconnectades"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplicacions del telèfon que han fallat"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"En fer aquesta trucada, finalitzarà la de l\'aplicació <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Tria com vols fer aquesta trucada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Desvia la trucada amb <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 384e6bb..1730a30 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Zpráva"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Hovor byl odpojen"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Hovor s volajícím <xliff:g id="CALLER">%s</xliff:g> byl odpojen, protože začalo být prováděno tísňové volání."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Váš hovor byl odpojen, protože bylo zahájeno tísňové volání."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Hovor na pozadí"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikace <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> přesunula hovor na pozadí. Tato aplikace může v hovoru používat a přehrávat zvuk."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Aplikace <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> přestala reagovat"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Při hovoru byla použita předinstalovaná telefonní aplikace"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Hovor ztlumen."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Reproduktor je zapnutý."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Teď nemůžu mluvit, o co jde?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokování hovorů"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Hovory na pozadí"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Odpojené hovory"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplikace, které spadly"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Uskutečněním tohoto hovoru ukončíte hovor <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Vyberte, jak chcete tento hovor provést"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Přesměrovat hovor přes aplikaci <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 5b634ff..6a208c4 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -19,7 +19,7 @@
<string name="telecommAppLabel" product="default" msgid="3077225713817780583">"Opkaldsstyring"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Opkald"</string>
<string name="unknown" msgid="6993977514360123431">"Ukendt"</string>
- <string name="notification_missedCallTitle" msgid="5060387047205532974">"Ubesvarede opkald"</string>
+ <string name="notification_missedCallTitle" msgid="5060387047205532974">"Ubesvaret opkald"</string>
<string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"Ubesvaret arbejdsopkald"</string>
<string name="notification_missedCallsTitle" msgid="3910479625507893809">"Ubesvarede opkald"</string>
<string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ubesvarede opkald"</string>
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Besked"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Afbrudt opkald"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Opkaldet til <xliff:g id="CALLER">%s</xliff:g> er blevet afbrudt, fordi der foretages et nødopkald."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Dit opkald er blevet afbrudt, fordi der foretages et nødopkald."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Opkald i baggrunden"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> har foretaget et opkald i baggrunden. Denne app har muligvis adgang til og afspiller lyd i opkaldet."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> svarer ikke"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Dit opkald brugte den opkaldsapp, din enhed er født med"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Lyd slået fra opkald."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Højttalertelefon aktiveret."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kan ikke tale nu. Hvad sker der?"</string>
@@ -67,7 +66,7 @@
<string name="blocked_numbers_msg" msgid="2797422132329662697">"Du modtager ikke opkald og sms-beskeder fra blokerede numre."</string>
<string name="block_number" msgid="3784343046852802722">"Tilføj et nummer"</string>
<string name="unblock_dialog_body" msgid="2723393535797217261">"Vil du fjerne blokeringen af <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
- <string name="unblock_button" msgid="8732021675729981781">"Fjern blokeringen"</string>
+ <string name="unblock_button" msgid="8732021675729981781">"Fjern blokering"</string>
<string name="add_blocked_dialog_body" msgid="8599974422407139255">"Bloker opkald og sms-beskeder fra"</string>
<string name="add_blocked_number_hint" msgid="8769422085658041097">"Telefonnummer"</string>
<string name="block_button" msgid="485080149164258770">"Bloker"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Opkaldsblokering"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Opkald i baggrunden"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Afbrudte opkald"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Opkaldsapps, der er gået ned"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Hvis du foretager dette opkald, afsluttes dit opkald i <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Vælg, hvordan du vil foretage dette opkald"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Omdiriger opkaldet ved hjælp af <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 0ff2932..c434ecc 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -21,19 +21,18 @@
<string name="unknown" msgid="6993977514360123431">"Unbekannt"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Entgangener Anruf"</string>
<string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"Verpasster geschäftlicher Anruf"</string>
- <string name="notification_missedCallsTitle" msgid="3910479625507893809">"Entgangene Anrufe"</string>
- <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> entgangene Anrufe"</string>
+ <string name="notification_missedCallsTitle" msgid="3910479625507893809">"Verpasste Anrufe"</string>
+ <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> verpasste Anrufe"</string>
<string name="notification_missedCallTicker" msgid="6731461957487087769">"Entgangener Anruf von <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
<string name="notification_missedCall_call_back" msgid="7900333283939789732">"Zurückrufen"</string>
<string name="notification_missedCall_message" msgid="4054698824390076431">"Nachricht"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Anruf beendet"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Der Anruf mit <xliff:g id="CALLER">%s</xliff:g> wurde beendet, weil ein Notruf getätigt wurde."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Der Anruf wurde beendet, weil ein Notruf getätigt wurde."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Anruf im Hintergrund"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> hat einen Anruf in den Hintergrund verschoben. Diese App greift möglicherweise auf den Anruf zu und spielt Audio darüber ab."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> reagiert nicht mehr"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Für den Anruf wurde die auf deinem Gerät vorinstallierte App verwendet"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Anruf stummgeschaltet"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Freisprechfunktion aktiviert"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kann jetzt nicht sprechen. Was gibt\'s?"</string>
@@ -48,7 +47,7 @@
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"Fehler beim Senden der Nachricht an <xliff:g id="PHONE_NUMBER">%s</xliff:g>"</string>
<string name="enable_account_preference_title" msgid="6949224486748457976">"Anrufkonten"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Es sind nur Notrufe erlaubt."</string>
- <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Diese App darf ohne die Berechtigung \"Standard-App für Telefonie\" keine ausgehenden Anrufe tätigen."</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Diese App darf ohne die Berechtigung \"Telefon-App\" keine ausgehenden Anrufe tätigen."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"Gib eine gültige Nummer ein."</string>
<string name="duplicate_video_call_not_allowed" msgid="5754746140185781159">"Der Anruf kann momentan nicht hinzugefügt werden."</string>
<string name="no_vm_number" msgid="2179959110602180844">"Fehlende Mailbox-Nummer"</string>
@@ -64,7 +63,7 @@
<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>
- <string name="blocked_numbers_msg" msgid="2797422132329662697">"Du erhältst keine Anrufe oder SMS von blockierten Nummern."</string>
+ <string name="blocked_numbers_msg" msgid="2797422132329662697">"Du erhältst von blockierten Nummern keine Anrufe oder SMS."</string>
<string name="block_number" msgid="3784343046852802722">"Nummer hinzufügen"</string>
<string name="unblock_dialog_body" msgid="2723393535797217261">"Blockierung von <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g> aufheben?"</string>
<string name="unblock_button" msgid="8732021675729981781">"Blockierung aufheben"</string>
@@ -96,12 +95,11 @@
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"Dieser Anruf kann aufgrund deiner Anrufe in <xliff:g id="OTHER_CALL">%1$s</xliff:g> nicht getätigt werden."</string>
<string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"Dieser Anruf kann aufgrund eines Anrufs in einer anderen App nicht getätigt werden."</string>
<string name="notification_channel_incoming_call" msgid="5245550964701715662">"Eingehende Anrufe"</string>
- <string name="notification_channel_missed_call" msgid="7168893015283909012">"Entgangene Anrufe"</string>
+ <string name="notification_channel_missed_call" msgid="7168893015283909012">"Verpasste Anrufe"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Anrufblockierung"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Anrufe im Hintergrund"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Beendete Anrufe"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Abgestürzte Telefon-Apps"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Durch diesen Anruf wird der Anruf in <xliff:g id="OTHER_APP">%1$s</xliff:g> beendet."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Wie möchtest du anrufen?"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Mit <xliff:g id="OTHER_APP">%1$s</xliff:g> weiterleiten"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index ff771a8..ab523c1 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index d61e0e4..4de7584 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Disconnected call"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"The call to <xliff:g id="CALLER">%s</xliff:g> has been disconnected due to an emergency call being placed."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Your call has been disconnected due to an emergency call being placed."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Background call"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> has placed a call into the background. This app may be accessing and playing audio over the call."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> stopped responding"</string>
+ <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>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Call Blocking"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Background calls"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Disconnected calls"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Crashed phone apps"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Placing this call will end your <xliff:g id="OTHER_APP">%1$s</xliff:g> call."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Choose how to make this call"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirect call using <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index d61e0e4..4de7584 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Disconnected call"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"The call to <xliff:g id="CALLER">%s</xliff:g> has been disconnected due to an emergency call being placed."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Your call has been disconnected due to an emergency call being placed."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Background call"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> has placed a call into the background. This app may be accessing and playing audio over the call."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> stopped responding"</string>
+ <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>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Call Blocking"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Background calls"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Disconnected calls"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Crashed phone apps"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Placing this call will end your <xliff:g id="OTHER_APP">%1$s</xliff:g> call."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Choose how to make this call"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirect call using <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index d61e0e4..4de7584 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Disconnected call"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"The call to <xliff:g id="CALLER">%s</xliff:g> has been disconnected due to an emergency call being placed."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Your call has been disconnected due to an emergency call being placed."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Background call"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> has placed a call into the background. This app may be accessing and playing audio over the call."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> stopped responding"</string>
+ <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>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Call Blocking"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Background calls"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Disconnected calls"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Crashed phone apps"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Placing this call will end your <xliff:g id="OTHER_APP">%1$s</xliff:g> call."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Choose how to make this call"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirect call using <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index d61e0e4..4de7584 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Disconnected call"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"The call to <xliff:g id="CALLER">%s</xliff:g> has been disconnected due to an emergency call being placed."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Your call has been disconnected due to an emergency call being placed."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Background call"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> has placed a call into the background. This app may be accessing and playing audio over the call."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> stopped responding"</string>
+ <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>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Call Blocking"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Background calls"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Disconnected calls"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Crashed phone apps"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Placing this call will end your <xliff:g id="OTHER_APP">%1$s</xliff:g> call."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Choose how to make this call"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirect call using <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 6c70fb0..3b3a983 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -28,10 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Disconnected call"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"The call to <xliff:g id="CALLER">%s</xliff:g> has been disconnected due to an emergency call being placed."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Your call has been disconnected due to an emergency call being placed."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Background call"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> has placed a call into the background. This app may be accessing and playing audio over the call."</string>
- <string name="notification_crashedInCallService_title" msgid="7440244344965656743">"Crashed phone app"</string>
- <string name="notification_crashedInCallService_body" msgid="2307501918379604204">"Your Phone app <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> has crashed. You call was continued using the Phone app that came with your device."</string>
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> stopped responding"</string>
+ <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 up?"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index c3e713f..826b877 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mensaje"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Se desconectó la llamada"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Se desconectó la llamada a <xliff:g id="CALLER">%s</xliff:g> porque se está realizando una llamada de emergencia."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Se desconectó tu llamada porque se está haciendo una llamada de emergencia."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Llamada en 2.° plano"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> movió una a segundo plano. Es posible que esta app acceda a la llamada y reproduzca audio."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> dejó de responder"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Tu llamada se hizo con la app de teléfono que venía en tu dispositivo"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Llamada silenciada"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Altavoz habilitado"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"No puedo hablar ahora. ¿Todo bien?"</string>
@@ -100,8 +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 desconectadas"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Apps de teléfono con fallas"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Si realizas esta llamada, 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 realizar esta llamada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redireccionar la llamada mediante <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 6383933..e124de4 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mensaje"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Llamada interrumpida"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Se ha interrumpido la llamada a <xliff:g id="CALLER">%s</xliff:g> debido a una llamada de emergencia."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Se ha interrumpido tu llamada debido a una llamada de emergencia."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Llamada en segundo plano"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ha llamado en segundo plano. Puede que esta aplicación acceda al audio y lo reproduzca durante la llamada."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> ha dejado de responder"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"La llamada se utilizó la aplicación para teléfonos que venía con tu dispositivo"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Llamada silenciada"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Altavoz habilitado"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"No puedo hablar. ¿Es importante?"</string>
@@ -46,7 +45,7 @@
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"Respuesta rápida"</string>
<string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"Mensaje enviado a <xliff:g id="PHONE_NUMBER">%s</xliff:g>"</string>
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"No se ha podido enviar el mensaje al <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
- <string name="enable_account_preference_title" msgid="6949224486748457976">"Cuentas de llamadas"</string>
+ <string name="enable_account_preference_title" msgid="6949224486748457976">"Cuentas de llamada"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Solo se permiten llamadas de emergencia."</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Esta aplicación no puede hacer llamadas sin permiso del teléfono."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"Para realizar una llamada, introduce un número válido."</string>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplicaciones para teléfonos con bloqueos"</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>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 6d1b515..bb291ad 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Sõnum"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Kõne on katkestatud"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Kõne helistajaga <xliff:g id="CALLER">%s</xliff:g> on katkestatud, kuna alustati hädaabikõnet."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Teie kõne katkestati, kuna alustati hädaabikõnet."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Taustal olev kõne"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> lülitas kõne taustale. See rakendus võib helile juurde pääseda ja seda kõne ajal esitada."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> lõpetas reageerimise"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Teie kõne kasutas teie seadmega kaasas olnud telefonirakendust"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Kõne on summutatud."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Valjuhääldi on sisse lülitatud."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Ei saa praegu rääkida. Milles asi?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Kõnede blokeerimine"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Taustal olevad kõned"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Katkestatud kõned"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Kokkujooksnud telefonirakendused"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Selle kõne tegemisel lõpetatakse pooleliolev kõne rakenduses <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Valige, kuidas soovite helistada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Suuna kõne ümber rakenduse <xliff:g id="OTHER_APP">%1$s</xliff:g> abil"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 8fd7a10..c8956cd 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mezua"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Deia deskonektatu egin da"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"<xliff:g id="CALLER">%s</xliff:g> deitzaileari egiten ari zinen deia deskonektatu da larrialdi-dei bat egiten ari zarelako."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Deia deskonektatu egin da, larrialdi-dei bat egiten ari zarelako."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Atzeko planoko deia"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> aplikazioak atzeko planoan jarri du deia. Baliteke aplikazioak audioa atzitzea eta erreproduzitzea deian zehar."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Erantzuteari utzi dio <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> aplikazioak"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Gailuaren telefono-aplikazioarekin egin da deia"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Deiaren audioa desaktibatu da."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Bozgorailua gaitu da."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Ezin dut hitz egin. Arazoren bat al dago?"</string>
@@ -99,9 +98,8 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"Dei galduak"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Deiak blokeatzeko aukera"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Atzeko planoko deiak"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Deiak deskonektatu egin dira"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Deskonektatutako deiak"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Huts egin duten telefonoko aplikazioak"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Dei hau egiten baduzu, amaitu egingo da <xliff:g id="OTHER_APP">%1$s</xliff:g> aplikazioko deia."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Aukeratu dei hau egiteko modua"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Birbideratu deia <xliff:g id="OTHER_APP">%1$s</xliff:g> aplikazioaren bidez"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 53de698..c873159 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -28,16 +28,15 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
- <string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"همین حالا با شما تماس میگیرم.."</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_4" msgid="9141132488345561047">"اکنون نمیتوانم صحبت کنم. بعداً به من زنگ میزنید؟"</string>
<string name="respond_via_sms_setting_title" msgid="4762275482898830160">"پاسخهای سریع"</string>
@@ -82,13 +81,13 @@
<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="notification_incoming_call" msgid="1233481138362230894">"<xliff:g id="CALL_VIA">%1$s</xliff:g> تماس از <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
- <string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_VIA">%1$s</xliff:g> تماس ویدیویی از <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_VIA">%1$s</xliff:g> تماس تصویری از <xliff:g id="CALL_FROM">%2$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_video_call" msgid="8572022039304239958">"پاسخگویی به تماس ویدیویی <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_video_call" msgid="1988508241432031327">"پاسخگویی به تماس ویدیویی درحال انجامتان پایان میدهد"</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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 933afc6..cf57d62 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Viesti"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Puhelu katkaistu"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Puhelu vastaanottajalle <xliff:g id="CALLER">%s</xliff:g> on katkaistu hätäpuhelun soittamisen vuoksi."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Puhelusi on katkaistu hätäpuhelun soittamisen vuoksi."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Taustapuhelu"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> on asettanut puhelun taustalle. Tämä sovellus voi käyttää ja toistaa ääntä puhelun päällä."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> lakkasi vastaamasta"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Puhelu soitettiin laitteen mukana tulleella puhelinsovelluksella"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Puhelu mykistetty."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Kaiutin käytössä."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"En voi vastata. Mitä asiaa?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Puhelujen esto"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Taustapuhelut"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Katkaistut puhelut"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Kaatuneet puhelinsovellukset"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Tämän puhelun soittaminen päättää puhelun sovelluksessa <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Valitse, miten puhelu soitetaan"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Uudelleenohjaa puhelu sovelluksella <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 8e1eb71..74faab9 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Appel déconnecté"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"L\'appel à <xliff:g id="CALLER">%s</xliff:g> a été déconnecté en raison d\'un appel d\'urgence qui a été passé."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Votre appel a été déconnecté en raison d\'un appel d\'urgence en cours de lancement."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Appel en arrière-plan"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> a passé un appel en arrière-plan. Cette application peut accéder à l\'audio de l\'appel et faire jouer un contenu audio par l\'intermédiaire de l\'appel."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> a arrêté de répondre"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Votre appel a utilisé l\'application Téléphone intégrée à votre appareil"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Son coupé"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Haut-parleur activé"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Peux pas parler. Quoi de neuf?"</string>
@@ -77,7 +76,7 @@
<string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"Lorsque vous communiquez avec les services d\'urgence par téléphone ou par message texte, la fonctionnalité de blocage est désactivée pour que ceux-ci puissent vous joindre."</string>
<string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Réactiver le blocage maintenant"</string>
<string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"Le numéro <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> a été bloqué."</string>
- <string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"Le numéro <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> a été débloqué."</string>
+ <string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"Le numéro <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> a été débloqué"</string>
<string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"Impossible de bloquer le numéro d\'urgence."</string>
<string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"Le numéro <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> a déjà été bloqué."</string>
<string name="toast_personal_call_msg" msgid="5817631570381795610">"Utilisation du clavier personnel pour faire l\'appel…"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blocage des appels"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Appels en arrière-plan"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Appels déconnectés"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Applications téléphoniques qui ont planté"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Si vous passez cet appel, vous mettrez fin à l\'appel <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<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>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 5791e3b..c2a95a2 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -28,18 +28,17 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Message"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Appel interrompu"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"L\'appel avec <xliff:g id="CALLER">%s</xliff:g> a été interrompu en raison d\'un appel d\'urgence."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Votre appel a été interrompu en raison d\'un appel d\'urgence."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Appel en arrière-plan"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> a placé un appel en arrière-plan. Il est possible que cette application lise des fichiers audio pendant l\'appel."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> a cessé de répondre"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"L\'appel s\'est poursuivi dans l\'application d\'appel préinstallée sur votre appareil"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Son coupé"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Haut-parleur activé"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Je ne peux pas répondre. Ça va ?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"Je te rappelle tout de suite."</string>
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"Je t\'appelle plus tard."</string>
- <string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Peux pas répondre. On se rappelle ?"</string>
+ <string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Je ne peux pas répondre. On se rappelle ?"</string>
<string name="respond_via_sms_setting_title" msgid="4762275482898830160">"Réponses rapides"</string>
<string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"Modifier les réponses rapides"</string>
<string name="respond_via_sms_setting_summary" msgid="8054571501085436868"></string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blocage d\'appels"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Appels en arrière-plan"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Appels interrompus"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Applications téléphoniques ayant planté"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Si vous passez cet appel, vous mettrez fin à celui qui est en cours dans l\'application <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<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 avec <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
@@ -115,7 +113,7 @@
<string name="phone_settings_payphone_txt" msgid="5003987966052543965">"Cabines téléphoniques"</string>
<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">"Bloquez les appels provenant de personnes non identifiées"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquer les appels provenant de personnes non identifiées"</string>
<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>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index e97648d..42c55d6 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mensaxe"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Chamada desconectada"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Desconectouse a chamada a <xliff:g id="CALLER">%s</xliff:g> porque se realizou unha chamada de emerxencia."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Desconectouse a chamada porque se realizou unha chamada de emerxencia."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Chamada seg. plano"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> chamou en segundo plano. Pode que esta aplicación acceda ao audio e o reproduza durante a chamada."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> deixou de responder"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Usouse a aplicación para teléfonos que ven co teu dispositivo na chamada"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Chamada silenciada"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Altofalante activado"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Non podo falar agora. Que pasa?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Bloqueo de chamadas"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Chamadas en segundo plano"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Chamadas desconectadas"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Fallaron as aplicacións de teléfono"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ao facer esta chamada, finalizarase o túa chamada de <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Escolle como facer esta chamada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirixir a chamada con <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index b8e8d19..7455080 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -19,7 +19,7 @@
<string name="telecommAppLabel" product="default" msgid="3077225713817780583">"કૉલ સંચાલન"</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_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>
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -46,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>
@@ -66,8 +65,8 @@
<string name="blocked_numbers" msgid="8322134197039865180">"અવરોધિત નંબરો"</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="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_number_hint" msgid="8769422085658041097">"ફોન નંબર"</string>
<string name="block_button" msgid="485080149164258770">"અવરોધિત કરો"</string>
@@ -77,7 +76,7 @@
<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>
+ <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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 459f765..ed623b8 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -67,7 +66,7 @@
<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="unblock_button" msgid="8732021675729981781">"अनब्लॉक करें"</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>
@@ -77,7 +76,7 @@
<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>
+ <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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 406f4ba..ff38e54 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Poruka"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Prekinuti poziv"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Poziv upućen <xliff:g id="CALLER">%s</xliff:g> prekinut je zbog uspostavljanja hitnog poziva."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Poziv je prekinut zbog hitnog poziva."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Poziv u pozadini"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikacija <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> prebacila je poziv u pozadinu. Ta aplikacija možda pristupa zvuku i reproducira ga putem poziva."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> više ne odgovara"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Vaš je poziv upotrijebio aplikaciju telefona koju ste dobili na uređaju"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Zvuk poziva isključen."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Zvučnik je omogućen."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Sada ne mogu razgovarati. Što ima?"</string>
@@ -77,7 +76,7 @@
<string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"Nakon što nazovete broj hitne službe ili pošaljete poruku na njega, blokada će se isključiti kako bi vam se hitna služba mogla javiti."</string>
<string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"Ponovno omogući sada"</string>
<string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"Broj <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> blokiran je"</string>
- <string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"Broj <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> deblokiran je"</string>
+ <string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"Broj <xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> je deblokiran"</string>
<string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"Broj hitne službe ne može se blokirati."</string>
<string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"Broj <xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> već je blokiran."</string>
<string name="toast_personal_call_msg" msgid="5817631570381795610">"Za upućivanje poziva upotrebljava se osobni program za biranje"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokiranje poziva"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Pozivi u pozadini"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Prekinuti pozivi"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Rušenja aplikacija telefona"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Upućivanjem ovog poziva prekinut ćete poziv u aplikaciji <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Odaberite kako ćete uputiti poziv"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Preusmjeri poziv putem aplikacije <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index ecb75b3..55e5535 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Üzenet"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Bontott hívás"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Az Ön és <xliff:g id="CALLER">%s</xliff:g> közötti hívást a szolgáltató egy segélyhívás kezdeményezése miatt bontotta."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Segélyhívást kezdeményeztek, ezért az Ön hívását megszakítottuk."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Háttérbeli hívás"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"A(z) <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> a háttérbe helyezett egy hívást. Ez az alkalmazás hozzáférhet a híváshoz, és hangot játszhat le benne."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"A(z) <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> lefagyott"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"A hívása a készülékhez mellékelt telefonalkalmazást használta"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Hívás némítva."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Kihangosítás engedélyezve."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Most nem alkalmas. Mi újság?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Hívásletiltás"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Háttérbeli hívások"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Bontott hívások"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Telefonalkalmazások összeomlása"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ha hívást indít, azzal megszakítja a(z) <xliff:g id="OTHER_APP">%1$s</xliff:g>-hívást."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"A hívás módjának kiválasztása"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Hívás átirányítása a következővel: <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 508db51..6987dab 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -99,9 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 9b5b401..23ebb73 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Pesan"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Panggilan terputus"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Panggilan kepada <xliff:g id="CALLER">%s</xliff:g> terputus karena ada panggilan darurat."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Panggilan Anda terputus karena ada panggilan darurat."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Panggilan latar belakang"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> telah menempatkan panggilan telepon ke latar belakang. Aplikasi ini mungkin mengakses dan memutar audio melalui panggilan telepon."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> berhenti merespons"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Panggilan Anda menggunakan aplikasi telepon bawaan perangkat Anda"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Panggilan disenyapkan."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Pengeras suara ponsel diaktifkan."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Tak bisa bicara sekarang. Ada apa?"</string>
@@ -82,13 +81,13 @@
<string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> sudah diblokir."</string>
<string name="toast_personal_call_msg" msgid="5817631570381795610">"Menggunakan telepon pribadi untuk melakukan panggilan"</string>
<string name="notification_incoming_call" msgid="1233481138362230894">"<xliff:g id="CALL_VIA">%1$s</xliff:g> panggilan dari <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
- <string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_VIA">%1$s</xliff:g> video call dari <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_VIA">%1$s</xliff:g> panggilan video dari <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
<string name="answering_ends_other_call" msgid="8653544281903986641">"Menjawab panggilan akan mengakhiri panggilan <xliff:g id="CALL_VIA">%1$s</xliff:g> Anda"</string>
<string name="answering_ends_other_calls" msgid="3702302838456922535">"Menjawab panggilan akan mengakhiri panggilan <xliff:g id="CALL_VIA">%1$s</xliff:g> Anda"</string>
- <string name="answering_ends_other_video_call" msgid="8572022039304239958">"Menjawab panggilan akan mengakhiri video call <xliff:g id="CALL_VIA">%1$s</xliff:g> Anda"</string>
+ <string name="answering_ends_other_video_call" msgid="8572022039304239958">"Menjawab panggilan akan mengakhiri panggilan video <xliff:g id="CALL_VIA">%1$s</xliff:g> Anda"</string>
<string name="answering_ends_other_managed_call" msgid="4031778317409881805">"Menjawab panggilan akan mengakhiri panggilan yang sedang berlangsung"</string>
<string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"Menjawab panggilan akan mengakhiri panggilan yang sedang berlangsung"</string>
- <string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Menjawab panggilan akan mengakhiri video call yang sedang berlangsung"</string>
+ <string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Menjawab panggilan akan mengakhiri panggilan video yang sedang berlangsung"</string>
<string name="answer_incoming_call" msgid="2045888814782215326">"Jawab"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"Tolak"</string>
<string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Panggilan tidak dapat dilakukan karena tidak ada akun panggilan yang mendukung jenis panggilan ini."</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Pemblokiran Panggilan"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Panggilan telepon latar belakang"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Panggilan terputus"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplikasi telepon error"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Melakukan panggilan ini akan mengakhiri panggilan <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Pilih cara melakukan panggilan ini"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Alihkan panggilan menggunakan <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 6f648ed..442b9d5 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Skilaboð"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Aftengt símtal"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Símtalið til <xliff:g id="CALLER">%s</xliff:g> hefur verið aftengt vegna þess að neyðarsímtal var hringt."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Símtalið var aftengt vegna þess að neyðarsímtal var hringt."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Bakgrunnssímtal"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> hefur sett símtal í bakgrunn. Hugsanlega fær þetta forrit aðgang að hljóði yfir símtalið og spilar það."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> hætti að svara"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Símtalið þitt notaði símaforritið sem fylgdi tækinu"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Símtal þaggað."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Kveikt á hátalara."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kemst ekki í símann. Eitthvað títt?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Lokað fyrir símtöl"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Bakgrunnssímtöl"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Aftengd símtöl"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Hrun í símaforritum"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ef þú hringir mun þessu símtali í <xliff:g id="OTHER_APP">%1$s</xliff:g> ljúka."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Veldu hvernig hringt er"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Framsenda símtal með <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 2d741c3..60f32d7 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Messaggio"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Chiamata disconnessa"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"La chiamata a <xliff:g id="CALLER">%s</xliff:g> è stata disconnessa per dare priorità a una chiamata di emergenza."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"La tua chiamata è stata disconnessa per dare priorità a una chiamata di emergenza."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"In sottofondo"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ha spostato una chiamata in sottofondo. L\'app potrà accedere all\'audio e riprodurlo in sovrapposizione alla chiamata."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> non risponde più"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Per la tua chiamata è stata utilizzata l\'app per telefono integrata nel tuo dispositivo"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Chiamata disattivata."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Vivavoce attivo."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Non posso parlare ora. Che succede?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blocco delle chiamate"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Chiamate in sottofondo"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Chiamate disconnesse"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"App per telefono arrestate in modo anomalo"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Se effettui questa chiamata, la chiamata di <xliff:g id="OTHER_APP">%1$s</xliff:g> verrà terminata."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Scegli come effettuare questa chiamata"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Reindirizza la chiamata utilizzando <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index b933c44..30a909b 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 726d279..bd87d66 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -58,9 +57,9 @@
<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_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_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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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,7 +112,7 @@
<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_unknown_txt" msgid="3577926178354772728">"不明"</string>
+ <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明な発信者"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"不明な発信者からの着信をブロック"</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>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 7849339..be27e8b 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index e2a6a8d..0bab244 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -77,7 +76,7 @@
<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>
+ <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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 36b647e..58b2abf 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -28,10 +28,11 @@
<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>
<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_crashedInCallService_title" msgid="7440244344965656743">"កម្មវិធីទូរសព្ទគាំង"</string>
- <string name="notification_crashedInCallService_body" msgid="2307501918379604204">"កម្មវិធីទូរសព្ទ <xliff:g id="IN_CALL_SERVICE_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="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>
@@ -97,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>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 714cae3..6e0bb59 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -21,19 +21,18 @@
<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>
<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>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ಆ್ಯಪ್, ಕರೆಯನ್ನು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಇರಿಸಿದೆ. ಈ ಆ್ಯಪ್ ಕರೆಯ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಮತ್ತು ಪ್ಲೇ ಮಾಡಬಹುದು."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -96,12 +95,11 @@
<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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 3a22476..1a29b2e 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -64,7 +63,7 @@
<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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 0a461fd..83e498e 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index f8c64ef..64142ca 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 3193133..29090d1 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Pranešimas"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Skambutis atjungtas"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Skambutis kontaktui <xliff:g id="CALLER">%s</xliff:g> buvo atjungtas dėl atliekamo skambučio pagalbos numeriu."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Skambutis buvo atjungtas dėl atliekamo skambučio pagalbos numeriu."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Skambutis fone"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Programa „<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g>“ perkėlė skambutį į foną. Ši programa gali pasiekti ir leisti garsą vykstant skambučiui."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Programa „<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g>“ nebereaguoja"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Atliekant skambutį buvo naudojama telefono programa, kuri buvo įrenginyje jį įsigijus"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Skambutis nutildytas."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Garsiakalbis įgalintas."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Dabar negaliu kalbėti. Kas nutiko?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Skambučių blokavimas"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Skambučiai fone"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Skambučiai atjungti"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Užstrigusios telefono programos"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Atliekant šį skambutį bus užbaigtas „<xliff:g id="OTHER_APP">%1$s</xliff:g>“ skambutis."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Pasirinkite, kaip norite skambinti"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Peradresuoti skambutį naudojant programą „<xliff:g id="OTHER_APP">%1$s</xliff:g>“"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 8adf246..782777d 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Ziņojums"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Pārtraukts zvans"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Zvans lietotājam <xliff:g id="CALLER">%s</xliff:g> ir pārtraukts, jo tiek veikts ārkārtas izsaukums."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Jūsu zvans ir pārtraukts, jo tiek veikts ārkārtas izsaukums."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Saruna fonā"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> pārcēla sarunu uz darbību fonā. Sarunas laikā šī lietotne var piekļūt audio saturam un to atskaņot."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> pārtrauca reaģēt"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Zvanam tika izmantota jūsu ierīcē iebūvētā tālruņa lietotne"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Zvana skaņa ir izslēgta."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Skaļrunis ir iespējots."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Nevaru runāt. Kas gadījās?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Zvanu bloķēšana"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Sarunas fonā"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Pārtrauktie zvani"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Avarējušās tālruņa lietotnes"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Veicot šo zvanu, tiks beigts zvans lietotnē <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Izvēlieties, kā veikt šo zvanu"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Novirzīt zvanu, izmantojot lietotni <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 24eec8f..99e211f 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="3077225713817780583">"Управување со повици"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"Телефон"</string>
<string name="unknown" msgid="6993977514360123431">"Непознато"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"Пропуштен повик"</string>
@@ -24,16 +24,15 @@
<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>
+ <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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -45,7 +44,7 @@
<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_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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 40f708d..5c64034 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="3077225713817780583">"കോൾ മാനേജ്മെന്റ്"</string>
<string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ഫോണ്"</string>
<string name="unknown" msgid="6993977514360123431">"അജ്ഞാതം"</string>
<string name="notification_missedCallTitle" msgid="5060387047205532974">"മിസ്ഡ് കോൾ"</string>
@@ -24,16 +24,15 @@
<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>
+ <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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -77,7 +76,7 @@
<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>
+ <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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index b82c334..cdef26b 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -25,27 +25,26 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
- <string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"Би тань руу одоо буцаагаад залгая."</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_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_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>
@@ -72,12 +71,12 @@
<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="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_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_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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index db14186..331cf5c 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -86,9 +85,9 @@
<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_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_video_call" msgid="1988508241432031327">"उत्तर देण्यामुळे तुमचा सुरु असलेला व्हिडिओ कॉल समाप्त होईल"</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_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>
@@ -96,12 +95,11 @@
<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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index dd882a9..b43b554 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mesej"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Panggilan diputuskan sambungan"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Panggilan kepada <xliff:g id="CALLER">%s</xliff:g> telah diputuskan sambungannya kerana panggilan kecemasan sedang dibuat."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Panggilan anda telah diputuskan sambungan kerana panggilan kecemasan sedang dibuat."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Panggilan latar blkg"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> telah meletakkan panggilan dalam latar belakang Apl ini mungkin mengakses dan memainkan audio mengatasi panggilan."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> telah berhenti memberikan respons"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Panggilan anda telah menggunakan aplikasi telefon yang disertakan bersama peranti anda"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Panggilan diredam."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Telefon pembesar suara didayakan."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Sedang sibuk. Ada apa?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Sekatan Panggilan"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Panggilan latar belakang"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Panggilan diputuskan sambungan"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplikasi telefon yang ranap"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Membuat panggilan ini akan menamatkan panggilan <xliff:g id="OTHER_APP">%1$s</xliff:g> anda."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Pilih cara untuk membuat panggilan ini"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Ubah hala panggilan menggunakan <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index aadcddc..c1b3124 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -66,18 +65,18 @@
<string name="blocked_numbers" msgid="8322134197039865180">"ပိတ်ထားသည့် နံပါတ်များ"</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="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_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="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_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_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>
@@ -97,17 +96,16 @@
<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>
+ <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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
<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_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_private_num_txt" msgid="6339272760338475619">"သီးသန့်"</string>
@@ -116,7 +114,7 @@
<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_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ခေါ်ဆိုမှု ပိတ်ခြင်း"</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>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 89d5f9d..3f65c62 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Melding"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Koblet fra anropet"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Anropet til <xliff:g id="CALLER">%s</xliff:g> er koblet fra fordi et nødanrop ble utført."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Samtalen din ble brutt fordi et nødanrop ble utført."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Bakgrunnsanrop"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> har flyttet et anrop til bakgrunnen. Det kan hende denne appen bruker og spiller av lyd over anropet."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> sluttet å svare"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Anropet ble gjort med telefonappen som fulgte med enheten din"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Samtalelyd er kuttet."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Høyttaler er aktivert."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kan ikke snakke nå. Hva skjer?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Anropsblokkering"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Bakgrunnsanrop"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Frakoblede anrop"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Telefonapper som har krasjet"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Samtalen din i <xliff:g id="OTHER_APP">%1$s</xliff:g> avsluttes hvis du foretar dette anropet."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Velg hvordan du vil ringe"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Viderekoble anropet med <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 6b2617f..1e2b32f 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -27,13 +27,12 @@
<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>
+ <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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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,24 +46,24 @@
<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_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">"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_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_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>
@@ -74,11 +73,11 @@
<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>
- <string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"आपतकालीन नम्बरमाथि रोक लगाउन सकिएन।"</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="notification_incoming_call" msgid="1233481138362230894">"<xliff:g id="CALL_FROM">%2$s</xliff:g> ले गरेको <xliff:g id="CALL_VIA">%1$s</xliff:g> कल"</string>
@@ -98,15 +97,14 @@
<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>
+ <string name="notification_channel_background_calls" msgid="7785659903711350506">"ब्याकग्राउन्डका कलहरू"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"विच्छेद गरिएका कल"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
<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="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>
@@ -118,8 +116,8 @@
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अज्ञात कल गर्ने व्यक्तिहरूको कलमाथि रोक लगाउनुहोस्"</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="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>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 6f98e4b..166e95d 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Bericht"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Beëindigd gesprek"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Het gesprek met <xliff:g id="CALLER">%s</xliff:g> is beëindigd omdat er een noodoproep is geplaatst."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Je gesprek is beëindigd omdat er een noodoproep is geplaatst."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Achtergrondgesprek"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> heeft een gesprek op de achtergrond geplaatst. Deze app kan audio openen en afspelen over het gesprek."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> reageert niet meer"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Voor je gesprek is de telefoon-app van je apparaat gebruikt"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Gesprek gedempt."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Luidspreker is aan."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kan nu niet opnemen. Alles goed?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Gesprekken blokkeren"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Achtergrondgesprekken"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Beëindigde gesprekken"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Gecrashte telefoon-apps"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Als je dit gesprek start, wordt je <xliff:g id="OTHER_APP">%1$s</xliff:g>-gesprek beëindigd."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Kies hoe je dit gesprek wilt plaatsen"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Gesprek omleiden via <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 68c03ed..e0061a7 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -21,19 +21,18 @@
<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>
<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>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଏକ କଲ୍ କରିଛି। ଏହା ଆପ୍ କଲ୍ ସମୟରେ ଅଡିଓ ଆକ୍ସେସ୍ କରିପାରେ ଏବଂ ଚଲେଇପାରେ।"</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -66,8 +65,8 @@
<string name="blocked_numbers" msgid="8322134197039865180">"ବ୍ଲକ୍ କରାଯାଇଥିବା ନମ୍ବର୍"</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="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_number_hint" msgid="8769422085658041097">"ଫୋନ୍ ନମ୍ଵର୍"</string>
<string name="block_button" msgid="485080149164258770">"ବ୍ଲକ୍ କରନ୍ତୁ"</string>
@@ -77,7 +76,7 @@
<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>
+ <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>
@@ -96,18 +95,17 @@
<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>
+ <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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
<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_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_private_num_txt" msgid="6339272760338475619">"ଗୋପନୀୟ"</string>
@@ -115,9 +113,9 @@
<string name="phone_settings_payphone_txt" msgid="5003987966052543965">"ପେ-ଫୋନ୍"</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_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_settings_unknown_summary_txt" msgid="5446657192535779645">"ଅଜଣା କଲରର କଲ୍କୁ ବ୍ଲକ୍ କରନ୍ତୁ"</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>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index dd1b5c4..2b94316 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -28,12 +28,11 @@
<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>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Background call"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> has placed a call into the background. This app may be accessing and playing audio over the call."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -96,18 +95,17 @@
<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>
- <string name="notification_channel_background_calls" msgid="7785659903711350506">"Background calls"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"ਕਾਲਾਂ ਡਿਸਕਨੈਕਟ ਹੋ ਗਈਆਂ"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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="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>
<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_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_private_num_txt" msgid="6339272760338475619">"ਨਿੱਜੀ"</string>
@@ -116,7 +114,7 @@
<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_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ਕਾਲ ਬਲਾਕਿੰਗ"</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>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 21fbeb8..9cb1980 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Wiadomość"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Przerwane połączenie"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Połączenie z rozmówcą <xliff:g id="CALLER">%s</xliff:g> zostało przerwane z powodu nawiązania połączenia alarmowego."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Połączenie zostało przerwane z powodu nawiązania połączenia alarmowego."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Połączenie w tle"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikacja <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> umieściła połączenie w tle. Może ona uzyskiwać dostęp do dźwięku i odtwarzać go podczas połączenia."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Aplikacja <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> nie odpowiada"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Połączenie zostało zrealizowane za pomocą aplikacji do obsługi telefonu zainstalowanej na urządzeniu"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Połączenie wyciszone."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Głośnik włączony."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Nie mogę rozmawiać. Co słychać?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokowanie połączeń"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Połączenia w tle"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Przerwane połączenia"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplikacje telefoniczne po awarii"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Jeśli zadzwonisz, połączenie w aplikacji <xliff:g id="OTHER_APP">%1$s</xliff:g> zostanie zakończone."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Wybierz, jak chcesz zadzwonić"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Przekieruj połączenie za pomocą aplikacji <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 5e1f07f..bb5213e 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mensagem"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Chamada desligada"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"A chamada para <xliff:g id="CALLER">%s</xliff:g> foi desligada porque foi efetuada uma chamada de emergência."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"A chamada foi desligada porque foi efetuada uma chamada de emergência."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Cham. segundo plano"</string>
- <string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> colocou uma chamada em segundo plano. Esta aplicação pode estar a aceder e a reproduzir áudio sobre a chamada."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> colocou uma chamada em segundo plano. Esta app pode estar a aceder e a reproduzir áudio sobre a chamada."</string>
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> deixou de responder."</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"A chamada utilizou a app de telefone incluída com o dispositivo."</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Chamada sem som."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Alta voz ativada."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Não posso falar agora. Que se passa?"</string>
@@ -48,19 +47,19 @@
<string name="respond_via_sms_failure_format" msgid="5198680980054596391">"Falha ao enviar a mensagem para <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
<string name="enable_account_preference_title" msgid="6949224486748457976">"Contas de chamadas"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Apenas são permitidas chamadas de emergência."</string>
- <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Esta aplicação não pode fazer chamadas sem a autorização do telefone."</string>
+ <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Esta app não pode fazer chamadas sem a autorização do telefone."</string>
<string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"Para telefonar, introduza um número válido."</string>
<string name="duplicate_video_call_not_allowed" msgid="5754746140185781159">"Não é possível adicionar a chamada neste momento."</string>
<string name="no_vm_number" msgid="2179959110602180844">"Número do correio de voz em falta"</string>
<string name="no_vm_number_msg" msgid="1339245731058529388">"Não existe um número de correio de voz armazenado no cartão SIM."</string>
<string name="add_vm_number_str" msgid="5179510133063168998">"Adicionar número"</string>
- <string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"Predefinir <xliff:g id="NEW_APP">%s</xliff:g> como a sua aplicação Telefone?"</string>
+ <string name="change_default_dialer_dialog_title" msgid="5861469279421508060">"Predefinir <xliff:g id="NEW_APP">%s</xliff:g> como a sua app Telefone?"</string>
<string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"Predefinir"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"Cancelar"</string>
- <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"A aplicação <xliff:g id="NEW_APP">%s</xliff:g> poderá efetuar chamadas e controlar todos os aspetos das mesmas. Apenas as aplicações em que confia devem ser escolhidas como a aplicação de telefone predefinida."</string>
- <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Predefinir <xliff:g id="NEW_APP">%s</xliff:g> como a sua aplicação Telefone?"</string>
+ <string name="change_default_dialer_warning_message" msgid="8461963987376916114">"A app <xliff:g id="NEW_APP">%s</xliff:g> poderá efetuar chamadas e controlar todos os aspetos das mesmas. Apenas as aplicações em que confia devem ser escolhidas como a app de telefone predefinida."</string>
+ <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Predefinir <xliff:g id="NEW_APP">%s</xliff:g> como a sua app Telefone?"</string>
<string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> deixará de poder filtrar as chamadas."</string>
- <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> poderá ver informações sobre os autores das chamadas que não se encontrem nos seus contactos e poderá bloquear estas chamadas. Apenas deve predefinir como aplicação de filtro de chamadas as aplicações nas quais confia."</string>
+ <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> poderá ver informações sobre os autores das chamadas que não se encontrem nos seus contactos e poderá bloquear estas chamadas. Apenas deve predefinir como app de filtro de chamadas as aplicações nas quais confia."</string>
<string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"Predefinir"</string>
<string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"Cancelar"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"Números bloqueados"</string>
@@ -94,19 +93,18 @@
<string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Não é possível efetuar a chamada porque não existem contas de chamadas que suportem chamadas deste tipo."</string>
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"Não é possível efetuar a chamada devido à sua chamada do <xliff:g id="OTHER_CALL">%1$s</xliff:g>."</string>
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"Não é possível efetuar a chamada devido às suas chamadas do <xliff:g id="OTHER_CALL">%1$s</xliff:g>."</string>
- <string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"Não é possível efetuar a chamada devido a uma chamada noutra aplicação."</string>
+ <string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"Não é possível efetuar a chamada devido a uma chamada noutra app."</string>
<string name="notification_channel_incoming_call" msgid="5245550964701715662">"Chamadas recebidas"</string>
<string name="notification_channel_missed_call" msgid="7168893015283909012">"Chamadas não atendidas"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Bloqueio de chamadas"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Chamadas em segundo plano"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Chamadas desligadas"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
- <string name="alert_outgoing_call" msgid="5319895109298927431">"Ao efetuar esta chamada, irá terminar a chamada na aplicação <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Apps Telefone com falhas"</string>
+ <string name="alert_outgoing_call" msgid="5319895109298927431">"Ao efetuar esta chamada, irá terminar a chamada na app <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Escolha como pretende efetuar esta chamada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirecionar chamada através de <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
<string name="alert_place_unredirect_outgoing_call" msgid="2467608535225764006">"Ligar com o meu número de telefone"</string>
- <string name="alert_redirect_outgoing_call_timeout" msgid="5568101425637373060">"Não é possível efetuar uma chamada através da aplicação <xliff:g id="OTHER_APP">%1$s</xliff:g>. Experimente utilizar uma aplicação de redirecionamento de chamadas diferente ou contactar o programador para obter ajuda."</string>
+ <string name="alert_redirect_outgoing_call_timeout" msgid="5568101425637373060">"Não é possível efetuar uma chamada através da app <xliff:g id="OTHER_APP">%1$s</xliff:g>. Experimente utilizar uma app de redirecionamento de chamadas diferente ou contactar o programador para obter ajuda."</string>
<string name="phone_settings_call_blocking_txt" msgid="7311523114822507178">"Bloqueio de chamadas"</string>
<string name="phone_settings_number_not_in_contact_txt" msgid="2602249106007265757">"Números não incluídos nos Contactos"</string>
<string name="phone_settings_number_not_in_contact_summary_txt" msgid="963327038085718969">"Bloquear números que não estejam na sua lista de Contactos"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index aafbcd3..5d88619 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mensagem"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Chamada desconectada"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"A chamada para <xliff:g id="CALLER">%s</xliff:g> foi desconectada porque uma chamada de emergência está sendo realizada."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Sua chamada foi desconectada porque uma chamada de emergência está sendo feita."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Chamada em 2º plano"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"O app <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> colocou uma chamada em segundo plano. Talvez ele esteja acessando e tocando o áudio durante a chamada."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"O app <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> parou de responder"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"A chamada usou o aplicativo de telefone que veio com seu dispositivo"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Chamada sem áudio."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Viva-voz ativado."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Não posso falar agora. Manda um SMS, por favor?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Bloqueio de chamadas"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Chamadas em segundo plano"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Chamadas desconectadas"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Falha com os apps de telefone"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Se você ligar agora, sua chamada será encerrada no <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Escolha como fazer esta chamada"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirecionar a chamada usando o <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 1f8c2c6..a95d4a4 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mesaj"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Apel deconectat"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Apelul către <xliff:g id="CALLER">%s</xliff:g> a fost deconectat deoarece a fost inițiat un apel de urgență."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Apelul a fost deconectat deoarece a fost inițiat un apel de urgență."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Apel în fundal"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> a inițiat un apel în fundal. Este posibil ca această aplicație să acceseze și să redea mesaje audio peste apel."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> nu mai răspunde"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Apelul dvs. a folosit aplicația Telefon instalată pe dispozitiv"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Apel cu sunet dezactivat."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Difuzor activat."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Nu pot acum. Despre ce e vorba?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blocarea apelurilor"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Apeluri în fundal"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Apeluri deconectate"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplicații pentru telefon blocate"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Dacă inițiați acest apel, cel din <xliff:g id="OTHER_APP">%1$s</xliff:g> va fi încheiat."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Alegeți cum vreți să inițiați apelul"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Redirecționați apelul folosind <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index f9c365c..a50907a 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -28,17 +28,16 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
- <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_2" msgid="2052951316129952406">"Я сейчас перезвоню."</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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 8ff82be..b73272b 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 1e1040f..0d79f1a 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Napísať"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Zrušený hovor"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Hovor kontaktu <xliff:g id="CALLER">%s</xliff:g> bol zrušený, aby mohlo prebehnúť tiesňové volanie."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Váš hovor bol zrušený, aby mohlo prebehnúť tiesňové volanie."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Hovor na pozadí"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikácia <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> umiestnila hovor do pozadia. Táto aplikácia môže mať počas hovoru prístup k zvuku a prehrávať ho."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Aplikácia <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> prestala reagovať"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Na hovor bola použitá telefónna aplikácia, ktorá bola vopred nainštalovaná vo vašom zariadení"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Zvuk hovoru bol vypnutý."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Reproduktor je povolený."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Teraz nemôžem hovoriť, o čo ide?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokovanie hovorov"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Hovory na pozadí"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Zrušené hovory"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Zrútené telefónne aplikácie"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ak uskutočníte tento hovor, hovor cez <xliff:g id="OTHER_APP">%1$s</xliff:g> bude ukončený."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Vyberte, ako chcete tento hovor uskutočniť"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Presmerovať hovor cez aplikáciu <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index b3514a8..5595c40 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Sporočilo"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Klic je prekinjen"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Klic za stik <xliff:g id="CALLER">%s</xliff:g> je prekinjen zaradi vzpostavljanja klica v sili."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Klic je prekinjen zaradi vzpostavljanja klica v sili."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Klic v ozadju"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Aplikacija <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> je klic premaknila v ozadje. Ta aplikacija morda dostopa do zvoka in ga predvaja prek klica."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Aplikacija <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> se ne odziva več"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Klic je bil opravljen prek aplikacije za klicanje, ki jo je v napravo namestil proizvajalec"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Klic izključen."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Zvočnik omogočen."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Zdaj ne morem govoriti. Za kaj gre?"</string>
@@ -99,9 +98,8 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"Neodgovorjeni klici"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Blokiranje klicev"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Klici v ozadju"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Klici so prekinjeni"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Prekinjeni klici"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Zrušene aplikacije za klicanje"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Če opravite ta klic, bo končan klic prek aplikacije <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Izberite, kako želite opraviti klic"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Preusmeri klic z aplikacijo <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 925831e..53f4efc 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mesazh"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Telefonatë e shkëputur"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Telefonata me <xliff:g id="CALLER">%s</xliff:g> është shkëputur sepse është kryer një telefonatë urgjence."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Telefonata jote është shkëputur sepse është kryer një telefonatë urgjence."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Telefonatë në sfond"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> e ka vendosur një telefonatë në sfond. Ky aplikacion mund të ketë qasje dhe të luajë audio mbi telefonatë."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> nuk përgjigjet më"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Telefonata jote ka përdorur aplikacionin e telefonit që ke marrë me pajisjen tënde"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Telefonata kaloi në heshtje."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Altoparlanti u aktivizua."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Nuk flas dot tani. Si është puna?"</string>
@@ -66,7 +65,7 @@
<string name="blocked_numbers" msgid="8322134197039865180">"Numrat e bllokuar"</string>
<string name="blocked_numbers_msg" msgid="2797422132329662697">"Nuk do të marrësh telefonata ose mesazhe me tekst nga numrat e bllokuar."</string>
<string name="block_number" msgid="3784343046852802722">"Shto një numër"</string>
- <string name="unblock_dialog_body" msgid="2723393535797217261">"Zhblloko <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+ <string name="unblock_dialog_body" msgid="2723393535797217261">"Të zhbllokohet <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
<string name="unblock_button" msgid="8732021675729981781">"Zhblloko"</string>
<string name="add_blocked_dialog_body" msgid="8599974422407139255">"Blloko telefonatat dhe mesazhet me tekst nga"</string>
<string name="add_blocked_number_hint" msgid="8769422085658041097">"Numri i telefonit"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Bllokimi i telefonatave"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Telefonatat në sfond"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Telefonatat e shkëputura"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Aplikacionet e telefonit që kanë pësuar ndërprerje aksidentale"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Kryerja e kësaj telefonate do të mbyllë telefonatën tënde në <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Zgjidh se si do ta kryesh këtë telefonatë"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Ridrejtoje telefonatën duke përdorur <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index fa11c92..adfece0 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -20,7 +20,7 @@
<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">"Пропуштен позив за Work"</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_missedCallTicker" msgid="6731461957487087769">"Пропуштен позив од: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 69efbe2..70c4566 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Sms:a"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Samtalet kopplades från"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Samtalet <xliff:g id="CALLER">%s</xliff:g> kopplades från eftersom ett nödsamtal ringdes."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Samtalets kopplades bort på grund av ett nödsamtal."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Bakgrundssamtal"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> har ringt ett samtal i bakgrunden. Denna app kan få åtkomst till och spela upp ljud från samtalet."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> slutade svara"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Samtalet använde telefonappen som medföljer enheten"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Samtalets ljud avstängt."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Högtalartelefon aktiverad."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Kan inte prata nu. Läget?"</string>
@@ -58,9 +57,9 @@
<string name="change_default_dialer_dialog_affirmative" msgid="8604665314757739550">"Ange standard"</string>
<string name="change_default_dialer_dialog_negative" msgid="8648669840052697821">"Avbryt"</string>
<string name="change_default_dialer_warning_message" msgid="8461963987376916114">"<xliff:g id="NEW_APP">%s</xliff:g> kan ringa och styra allt omkring samtal. Endast appar du litar på bör ställas in som standardtelefonapp."</string>
- <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Vill du göra <xliff:g id="NEW_APP">%s</xliff:g> till din standardapp för samtalsspärr?"</string>
- <string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> kommer inte längre att användas för samtalsspärr."</string>
- <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> kommer att kunna se information om uppringare som inte finns i dina kontakter och blockera dessa samtal. Endast appar du litar på bör ställas in som standardapp för samtalsspärr."</string>
+ <string name="change_default_call_screening_dialog_title" msgid="5365787219927262408">"Vill du göra <xliff:g id="NEW_APP">%s</xliff:g> till din standardapp för samtalsfiltrering?"</string>
+ <string name="change_default_call_screening_warning_message_for_disable_old_app" msgid="2039830033533243164">"<xliff:g id="OLD_APP">%s</xliff:g> kommer inte längre att användas för samtalsfiltrering."</string>
+ <string name="change_default_call_screening_warning_message" msgid="9020537562292754269">"<xliff:g id="NEW_APP">%s</xliff:g> kommer att kunna se information om uppringare som inte finns i dina kontakter och blockera dessa samtal. Endast appar du litar på bör ställas in som standardapp för samtalsfiltrering."</string>
<string name="change_default_call_screening_dialog_affirmative" msgid="7162433828280058647">"Ange standard"</string>
<string name="change_default_call_screening_dialog_negative" msgid="1839266125623106342">"Avbryt"</string>
<string name="blocked_numbers" msgid="8322134197039865180">"Blockerade nummer"</string>
@@ -99,9 +98,8 @@
<string name="notification_channel_missed_call" msgid="7168893015283909012">"Missade samtal"</string>
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Samtalsblockering"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Bakgrundssamtal"</string>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Samtalen kopplades från"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Frånkopplade samtal"</string>
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Kraschade telefonappar"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ringer du det här samtalet avslutas samtalet i <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Välj hur du vill ringa samtalet"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Omdirigera samtal med <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 2cd1cbe..8b8a40c 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Ujumbe"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Simu imekatwa"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Simu uliyompigia <xliff:g id="CALLER">%s</xliff:g> imekatwa kwa sababu kuna simu ya dharura inayopigwa."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Simu yako imekatwa kwa sababu kuna simu ya dharura inayopigwa."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Simu ya chinichini"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> inapiga simu chinichini. Huenda programu hii inafikia na kucheza sauti huku simu ikiendelea."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> imeacha kufanya kazi"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Ulipiga simu kwa kutumia Programu ya simu iliyokuja na kifaa chako"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Simu imezimwa."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Spika za simu zimewezeshwa"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Siwezi kuongea sasa. Kuna nini?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Kuzuia Simu"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Simu za chinichini"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Simu zilizokatwa"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Programu za simu zilizoacha kufanya kazi"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ukipiga simu hii, simu yako kwenye <xliff:g id="OTHER_APP">%1$s</xliff:g> itakatwa."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Chagua jinsi utakavyopiga simu hii"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Elekeza simu ukitumia <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 2cc8590..ee48214 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 828e558..58eb225 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -21,19 +21,18 @@
<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_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>
<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>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> కాల్ను నేపథ్యంలోకి పంపింది. కాల్ ద్వారా ఈ యాప్, ఆడియోను యాక్సెస్ ఇంకా ప్లే చేస్తుండవచ్చు."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -95,13 +94,12 @@
<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_missed_call" msgid="7168893015283909012">"సమాధానం ఇవ్వని కాల్లు"</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>
- <string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"డిస్కనెక్ట్ చేసిన కాల్లు"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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="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>
@@ -120,6 +118,6 @@
<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="developer_title" msgid="9146088855661672353">"టెలికామ్ డెవలపర్ మెనూ"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"అత్యవసర కాల్లో వున్నప్పుడు కాల్లను స్వీకరించడానికి వీలుపడదు."</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index c605fb2..615abb9 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -63,7 +62,7 @@
<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" msgid="8322134197039865180">"หมายเลขที่บล็อก"</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>
@@ -95,13 +94,12 @@
<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>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"สายถูกตัด"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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,7 +112,7 @@
<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_unknown_txt" msgid="3577926178354772728">"ไม่ทราบ"</string>
+ <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ไม่รู้จัก"</string>
<string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"บล็อกสายจากผู้โทรที่ไม่สามารถระบุได้"</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>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 3925b0b..998abef 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -28,20 +28,19 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Padalhan ng mensahe"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Nadiskonektang tawag"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Nadiskonekta ang tawag kay <xliff:g id="CALLER">%s</xliff:g> dahil sa ginagawang pang-emergency na tawag."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Nadiskonekta ang iyong tawag dahil sa ginagawang pang-emergency na tawag."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Tawag sa background"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"Naglagay ng tawag ang <xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> sa background. Posibleng ina-access at pine-play ng app na ito ang audio sa tawag."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"Huminto ang <xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> sa pagtugon"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Ginamit ng tawag mo ang app na telepono na kasama sa iyong device"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Naka-mute ang tawag."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Pinapagana ang speakerphone."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Di masagot ngayon. Ano\'ng meron?"</string>
<string name="respond_via_sms_canned_response_2" msgid="2052951316129952406">"Ako na lang ang tatawag sa \'yo."</string>
<string name="respond_via_sms_canned_response_3" msgid="6656147963478092035">"Tawagan kita mamaya."</string>
<string name="respond_via_sms_canned_response_4" msgid="9141132488345561047">"Di masagot ngayon. Tawag ka mamaya?"</string>
- <string name="respond_via_sms_setting_title" msgid="4762275482898830160">"Mga mabilisang tugon"</string>
- <string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"I-edit ang mga quick response"</string>
+ <string name="respond_via_sms_setting_title" msgid="4762275482898830160">"Mga mabilis na sagot"</string>
+ <string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"I-edit ang mabilis na sagot"</string>
<string name="respond_via_sms_setting_summary" msgid="8054571501085436868"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"Mabilisang tugon"</string>
<string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"Naipadala ang mensahe sa <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Pag-block ng Tawag"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Mga tawag sa background"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Nadiskonektang mga tawag"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Nag-crash na mga phone app"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Tatapusin ng pagtawag na ito ang iyong tawag sa <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Piliin kung paano gagawin ang tawag na ito"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"I-redirect ang tawag gamit ang <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 051bad8..2e02f8c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Mesaj gönder"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Aramanın bağlantısı kesildi"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Bir acil durum araması yapıldığı için <xliff:g id="CALLER">%s</xliff:g> ile olan görüşmenin bağlantısı kesildi."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Bir acil durum araması yapıldığı için görüşmenizin bağlantısı kesildi."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Arka plandaki arama"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> arka plana bir arama yerleştirdi. Bu uygulama arama üzerinden sese erişiyor ve ses çalıyor olabilir."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> yanıt vermeyi durdurdu"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Görüşmeniz için, cihazınızla gelen telefon uygulaması kullanıldı"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Çağrı sesi kapatıldı."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Hoparlör etkin."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Şimdi konuşamam. Konu nedir?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Çağrı Engelleme"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Arka plandaki aramalar"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Bağlantısı kesilen aramalar"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Kilitlenen telefon uygulamaları"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Bu çağrıyı yaptığınızda <xliff:g id="OTHER_APP">%1$s</xliff:g> çağrınız sona erecek."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Bu aramanın nasıl yapılacağını seçin"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"<xliff:g id="OTHER_APP">%1$s</xliff:g> uygulamasını kullanarak aramayı yönlendir"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a19a2c0..d86b3eb 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index ef15c14..20cca1b 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -99,14 +98,13 @@
<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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
<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="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>
@@ -120,6 +118,6 @@
<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="developer_title" msgid="9146088855661672353">"ٹیلی کام ڈویلپر مینو"</string>
<string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ہنگامی کال کے دوران کالز نہیں لی جائیں گی۔"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 849c98f..3271245 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">"Qo‘ng‘iroqlar boshqaruvi"</string>
+ <string name="telecommAppLabel" product="default" msgid="3077225713817780583">"Chaqiruvlar boshqaruvi"</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>
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"SMS"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Chaqiruv tugatildi"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Favqulodda chaqiruv amalga oshirilayotgani uchun <xliff:g id="CALLER">%s</xliff:g> bilan suhbatingiz tugatildi."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Favqulodda chaqiruv amalga oshirilayotgani uchun joriy chaqiruvingiz to‘xtatildi."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Orqa fondagi chaqiruv"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> ilovasi chaqiruvni orqa fonga joyladi. Bu ilova ovozli chaqiruvga kirishi yoki unda audio ijro etishi mumkin."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> javob bermayapti"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Chaqiruv qurilmangizga avvaldan o‘rnatilgan ilova orqali amalga oshirildi"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Qo‘ng‘iroq ovozi o‘chirildi."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Karnaychalar yoqildi."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Hozir gaplasholmayman. Tinchlikmi?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Chaqiruvlarni bloklash"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Orqa fondagi chaqiruvlar"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Tugatilgan chaqiruvlar"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Ishdan chiqqan telefon ilovalari"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Bu qo‘ng‘iroqni amalga oshirsangiz, <xliff:g id="OTHER_APP">%1$s</xliff:g> qo‘ng‘irog‘i tugatiladi."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Telefon qilish usulini tanlang"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Chaqiruv <xliff:g id="OTHER_APP">%1$s</xliff:g> orqali qayta uzatilsin"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index b604e7b..c6fe44a 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Tin nhắn"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Cuộc gọi bị ngắt kết nối"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Cuộc gọi đến <xliff:g id="CALLER">%s</xliff:g> đã bị ngắt kết nối do một cuộc gọi khẩn cấp được thực hiện."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Cuộc gọi của bạn đã bị ngắt kết nối do một cuộc gọi khẩn cấp đang được thực hiện."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Cuộc gọi trong nền"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> đã gọi điện ở chế độ nền. Ứng dụng này có thể đang truy cập và phát âm thanh qua cuộc gọi."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> đã dừng phản hồi"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Cuộc gọi của bạn đã dùng ứng dụng dành cho điện thoại đi kèm với thiết bị"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Đã tắt tiếng cuộc gọi."</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Đã bật loa ngoài."</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Giờ tôi không nói chuyện được. Có việc gì không?"</string>
@@ -82,13 +81,13 @@
<string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> đã bị chặn."</string>
<string name="toast_personal_call_msg" msgid="5817631570381795610">"Sử dụng trình quay số cá nhân để gọi điện"</string>
<string name="notification_incoming_call" msgid="1233481138362230894">"Cuộc gọi <xliff:g id="CALL_VIA">%1$s</xliff:g> từ <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
- <string name="notification_incoming_video_call" msgid="5795968314037063900">"Cuộc gọi điện video <xliff:g id="CALL_VIA">%1$s</xliff:g> từ <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
+ <string name="notification_incoming_video_call" msgid="5795968314037063900">"Cuộc gọi video <xliff:g id="CALL_VIA">%1$s</xliff:g> từ <xliff:g id="CALL_FROM">%2$s</xliff:g>"</string>
<string name="answering_ends_other_call" msgid="8653544281903986641">"Trả lời sẽ kết thúc cuộc gọi <xliff:g id="CALL_VIA">%1$s</xliff:g> của bạn"</string>
<string name="answering_ends_other_calls" msgid="3702302838456922535">"Trả lời sẽ kết thúc cuộc gọi <xliff:g id="CALL_VIA">%1$s</xliff:g> của bạn"</string>
- <string name="answering_ends_other_video_call" msgid="8572022039304239958">"Trả lời sẽ kết thúc cuộc gọi điện video <xliff:g id="CALL_VIA">%1$s</xliff:g> của bạn"</string>
+ <string name="answering_ends_other_video_call" msgid="8572022039304239958">"Trả lời sẽ kết thúc cuộc gọi video <xliff:g id="CALL_VIA">%1$s</xliff:g> của bạn"</string>
<string name="answering_ends_other_managed_call" msgid="4031778317409881805">"Trả lời sẽ kết thúc cuộc gọi đang diễn ra của bạn"</string>
<string name="answering_ends_other_managed_calls" msgid="3974069768615307659">"Trả lời sẽ kết thúc cuộc gọi đang diễn ra của bạn"</string>
- <string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Trả lời sẽ kết thúc cuộc gọi điện video đang diễn ra của bạn"</string>
+ <string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Trả lời sẽ kết thúc cuộc gọi video đang diễn ra của bạn"</string>
<string name="answer_incoming_call" msgid="2045888814782215326">"Trả lời"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"Từ chối"</string>
<string name="cant_call_due_to_no_supported_service" msgid="1635626384149947077">"Không thể thực hiện cuộc gọi do không có tài khoản hỗ trợ loại cuộc gọi này."</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Chặn cuộc gọi"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Cuộc gọi trong nền"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Các cuộc gọi bị ngắt kết nối"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Các ứng dụng điện thoại bị lỗi"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Thực hiện cuộc gọi này sẽ kết thúc cuộc gọi <xliff:g id="OTHER_APP">%1$s</xliff:g> của bạn."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Chọn cách thực hiện cuộc gọi này"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Chuyển hướng cuộc gọi bằng cách sử dụng <xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3a33647..bbda818 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 7ccf89b..0f26c9d 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -58,9 +57,9 @@
<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_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_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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index b4f89fa..7c98928 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -28,12 +28,11 @@
<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>
<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>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <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="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>
@@ -100,8 +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>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <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>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index cd3a880..30c147d 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -28,12 +28,11 @@
<string name="notification_missedCall_message" msgid="4054698824390076431">"Umlayezo"</string>
<string name="notification_disconnectedCall_title" msgid="1790131923692416928">"Ikholi enqanyuliwe"</string>
<string name="notification_disconnectedCall_body" msgid="600491714584417536">"Ikholi eya ku-<xliff:g id="CALLER">%s</xliff:g> inqanyuliwe ngenxa yekholi yesimo esiphuthumayo efakwayo."</string>
+ <string name="notification_disconnectedCall_generic_body" msgid="5282765206349184853">"Ikholi yakho inqanyuliwe ngenxa yekholi yesimo esiphuthumayo eyenziwe."</string>
<string name="notification_audioProcessing_title" msgid="1619035039880584575">"Ikholi engemuva"</string>
<string name="notification_audioProcessing_body" msgid="6397005913770420388">"<xliff:g id="AUDIO_PROCESSING_APP_NAME">%s</xliff:g> yenze ikholi ngemuva. Kungenzeka ukuthi lolu hlelo lokusebenza lufinyelela futhi ludlala okulalelwayo ngaphezu kwekholi."</string>
- <!-- no translation found for notification_crashedInCallService_title (7440244344965656743) -->
- <skip />
- <!-- no translation found for notification_crashedInCallService_body (2307501918379604204) -->
- <skip />
+ <string name="notification_incallservice_not_responding_title" msgid="5347557574288598548">"<xliff:g id="IN_CALL_SERVICE_APP_NAME">%s</xliff:g> iyeke ukuphendula"</string>
+ <string name="notification_incallservice_not_responding_body" msgid="9209308270131968623">"Ikholi yakho isebenzise uhlelo lokusebenza lefoni elize nedivayisi yakho"</string>
<string name="accessibility_call_muted" msgid="2968461092554300779">"Ikholu ithulisiwe"</string>
<string name="accessibility_speakerphone_enabled" msgid="555386652061614267">"Isipikha sefoni sinikwe amandla"</string>
<string name="respond_via_sms_canned_response_1" msgid="6332561460870382561">"Angikwazi ukukhuluma okwamanje. Kwenzenjani?"</string>
@@ -100,8 +99,7 @@
<string name="notification_channel_call_blocking" msgid="2028807677868598710">"Ukuvimbela ikholi"</string>
<string name="notification_channel_background_calls" msgid="7785659903711350506">"Amakholi angemuva"</string>
<string name="notification_channel_disconnected_calls" msgid="8228636543997645757">"Amakholi anqanyuliwe"</string>
- <!-- no translation found for notification_channel_in_call_service_crash (7313237519166984267) -->
- <skip />
+ <string name="notification_channel_in_call_service_crash" msgid="7313237519166984267">"Izinhlelo zokusebenza ezikhubazekile zefoni"</string>
<string name="alert_outgoing_call" msgid="5319895109298927431">"Ukwenza le kholi kuzoqeda enye ikholi yakho ye-<xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
<string name="alert_redirect_outgoing_call_or_not" msgid="665409645789521636">"Khetha ukuthi uyibeka kanjani le kholi"</string>
<string name="alert_place_outgoing_call_with_redirection" msgid="5221065030959024121">"Qondisa kabusha ikholi usebenzisa i-<xliff:g id="OTHER_APP">%1$s</xliff:g>"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 52b688c..b617ae1 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -24,6 +24,7 @@
<dimen name="blocked_numbers_large_padding">16dp</dimen>
<dimen name="blocked_numbers_extra_large_padding">32dp</dimen>
<dimen name="blocked_numbers_button_bottom_margin">20dp</dimen>
+ <dimen name="blocked_numbers_button_large_padding">15dp</dimen>
<dimen name="blocked_numbers_dialog_padding">24dp</dimen>
<dimen name="blocked_numbers_delete_icon_padding">12dp</dimen>
<dimen name="blocked_numbers_progress_bar_padding">100dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2990c42..df08d7c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -55,6 +55,13 @@
<!-- Body of the notification presented when an ongoing call is disconnected in favor of placing
an emergency call. This is required by some carriers. [CHAR LIMIT=NONE] -->
<string name="notification_disconnectedCall_body">The call to <xliff:g id="caller">%s</xliff:g> has been disconnected due to an emergency call being placed.</string>
+ <!-- Body of the notification presented when an ongoing call is disconnected in favor of placing
+ an emergency call. This version is used when the call that was disconnected was also an
+ emergency call. In this case, we want to hide the exact number dialed in order to protect
+ user privacy. [CHAR LIMIT=NONE] -->
+ <string name="notification_disconnectedCall_generic_body">
+ Your call has been disconnected due to an emergency call being placed.
+ </string>
<!-- Title for the persistent notification presented when an app has requested that a call
be put into the background so that the app can access the audio from the call
@@ -68,13 +75,14 @@
background. This app may be accessing and playing audio over the call.
</string>
- <!-- Crashed in call service notification label, used when the in call service has cranshed and
+ <!-- Crashed in call service notification label, used when the in call service has crashed and
the system fall back to use system dialer. [CHAR LIMIT=NONE] -->
- <string name="notification_crashedInCallService_title">Crashed phone app</string>
+ <string name="notification_incallservice_not_responding_title">
+ <xliff:g id="in_call_service_app_name">%s</xliff:g> stopped responding
+ </string>
<!-- Body of the notification presented when an in call service crashed. [CHAR LIMIT=NONE] -->
- <string name="notification_crashedInCallService_body">
- Your phone app <xliff:g id="in_call_service_app_name">%s</xliff:g> has crashed.
- You call was continued using the phone app that came with your device.
+ <string name="notification_incallservice_not_responding_body">
+ Your call used the phone app that came with your device
</string>
<!-- Content description of the call muted notification icon for
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 187086b..5ba0a3f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -68,7 +68,6 @@
<style name="BlockedNumbersButton" parent="BlockedNumbersTextPrimary2">
<item name="android:textColor">@color/theme_color</item>
- <item name="android:textAllCaps">true</item>
</style>
<style name="BlockedNumbersTextHead1"
@@ -83,6 +82,7 @@
<item name="android:textSize">@dimen/blocked_numbers_primary2_font_size</item>
<item name="android:fontFamily">sans-serif-regular</item>
<item name="android:lineSpacingExtra">@dimen/blocked_numbers_line_spacing</item>
+ <item name="android:capitalize">sentences</item>
</style>
<style name="BlockedNumbersTextSecondary">
@@ -90,5 +90,6 @@
<item name="android:textSize">@dimen/blocked_numbers_secondary_font_size</item>
<item name="android:fontFamily">sans-serif-regular</item>
<item name="android:lineSpacingExtra">@dimen/blocked_numbers_secondary_line_spacing</item>
+ <item name="android:capitalize">sentences</item>
</style>
</resources>
diff --git a/res/xml/activity_blocked_numbers.xml b/res/xml/activity_blocked_numbers.xml
index e137313..df1a759 100644
--- a/res/xml/activity_blocked_numbers.xml
+++ b/res/xml/activity_blocked_numbers.xml
@@ -75,9 +75,11 @@
<TextView
android:id="@+id/add_blocked"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:text="@string/block_number"
android:layout_marginBottom="@dimen/blocked_numbers_button_bottom_margin"
+ android:paddingTop="@dimen/blocked_numbers_button_large_padding"
+ android:paddingBottom="@dimen/blocked_numbers_button_large_padding"
style="@style/BlockedNumbersButton"
android:background="?android:attr/selectableItemBackgroundBorderless" />
diff --git a/res/xml/enhanced_call_blocking_settings.xml b/res/xml/enhanced_call_blocking_settings.xml
index 32c4c5d..73ed2af 100644
--- a/res/xml/enhanced_call_blocking_settings.xml
+++ b/res/xml/enhanced_call_blocking_settings.xml
@@ -41,8 +41,4 @@
android:persistent="false"
android:defaultValue="false"/>
<!--Add divider to separate this enhanced call blocking settings from other settings-->
- <Preference
- android:key="enhanced_call_blocking_divider"
- android:persistent="false"
- android:layout="@xml/layout_divider"/>
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/layout_blocked_number.xml b/res/xml/layout_blocked_number.xml
index 720d71a..9dbfc2f 100644
--- a/res/xml/layout_blocked_number.xml
+++ b/res/xml/layout_blocked_number.xml
@@ -28,6 +28,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
+ android:layout_toStartOf="@+id/delete_blocked_number"
android:paddingTop="@dimen/blocked_numbers_delete_icon_padding"
android:textDirection="ltr" />
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 410660e..8b7c37d 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -24,6 +24,7 @@
import android.telecom.Logging.EventManager;
import android.telecom.ParcelableCallAnalytics;
import android.telecom.TelecomAnalytics;
+import android.telecom.TelecomManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Base64;
@@ -36,7 +37,6 @@
import java.io.PrintWriter;
import java.time.Instant;
import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -45,8 +45,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
-import java.util.PriorityQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;
@@ -210,6 +208,9 @@
public void setCallSource(int callSource) {
}
+
+ public void setMissedReason(long missedReason) {
+ }
}
/**
@@ -244,6 +245,7 @@
public List<TelecomLogClass.InCallServiceInfo> inCallServiceInfos;
public int callProperties = 0;
public int callSource = CALL_SOURCE_UNSPECIFIED;
+ public long missedReason;
private long mTimeOfLastVideoEvent = -1;
@@ -256,6 +258,7 @@
connectionService = "";
videoEvents = new LinkedList<>();
inCallServiceInfos = new LinkedList<>();
+ missedReason = 0;
}
CallInfoImpl(CallInfoImpl other) {
@@ -274,6 +277,7 @@
this.videoEvents = other.videoEvents;
this.callProperties = other.callProperties;
this.callSource = other.callSource;
+ this.missedReason = other.missedReason;
if (other.callTerminationReason != null) {
this.callTerminationReason = new DisconnectCause(
@@ -344,6 +348,13 @@
}
@Override
+ public void setMissedReason(long missedReason) {
+ Log.d(TAG, "setting missedReason for call " + callId + ": "
+ + missedReason);
+ this.missedReason = missedReason;
+ }
+
+ @Override
public void setCallEvents(EventManager.EventRecord records) {
this.callEvents = records;
}
@@ -401,6 +412,7 @@
+ " isEmergency: " + isEmergency + '\n'
+ " callTechnologies: " + getCallTechnologiesAsString() + '\n'
+ " callTerminationReason: " + getCallDisconnectReasonString() + '\n'
+ + " missedReason: " + getMissedReasonString() + '\n'
+ " connectionService: " + connectionService + '\n'
+ " isVideoCall: " + isVideo + '\n'
+ " inCallServices: " + getInCallServicesString() + '\n'
@@ -528,6 +540,11 @@
}
}
+ private String getMissedReasonString() {
+ //TODO: Implement this
+ return null;
+ }
+
private String getInCallServicesString() {
StringBuilder s = new StringBuilder();
s.append("[\n");
@@ -576,11 +593,11 @@
// Constants for call source
public static final int CALL_SOURCE_UNSPECIFIED =
- ParcelableCallAnalytics.CALL_SOURCE_UNSPECIFIED;
+ TelecomManager.CALL_SOURCE_UNSPECIFIED;
public static final int CALL_SOURCE_EMERGENCY_DIALPAD =
- ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_DIALPAD;
+ TelecomManager.CALL_SOURCE_EMERGENCY_DIALPAD;
public static final int CALL_SOURCE_EMERGENCY_SHORTCUT =
- ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_SHORTCUT;
+ TelecomManager.CALL_SOURCE_EMERGENCY_SHORTCUT;
// Constants for video events
public static final int SEND_LOCAL_SESSION_MODIFY_REQUEST =
diff --git a/src/com/android/server/telecom/AppLabelProxy.java b/src/com/android/server/telecom/AppLabelProxy.java
new file mode 100644
index 0000000..7c00f28
--- /dev/null
+++ b/src/com/android/server/telecom/AppLabelProxy.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.telecom.Log;
+
+/**
+ * Abstracts away dependency on the {@link PackageManager} required to fetch the label for an
+ * app.
+ */
+public interface AppLabelProxy {
+ String LOG_TAG = AppLabelProxy.class.getSimpleName();
+
+ class Util {
+ /**
+ * Default impl of getAppLabel.
+ * @param pm PackageManager instance
+ * @param packageName package name to look up.
+ */
+ public static CharSequence getAppLabel(PackageManager pm, String packageName) {
+ try {
+ ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+ CharSequence result = pm.getApplicationLabel(info);
+ Log.i(LOG_TAG, "package %s: name is %s", packageName, result);
+ return result;
+ } catch (PackageManager.NameNotFoundException nnfe) {
+ Log.w(LOG_TAG, "Could not determine app label. Package name is %s", packageName);
+ }
+
+ return null;
+ }
+ }
+
+ CharSequence getAppLabel(String packageName);
+}
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index 1a7d0f7..bf2472f 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -201,10 +201,11 @@
// can know whether to trigger the vibrator.
if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
boolean hasHaptics = factory.hasHapticChannels(mRingtone);
-
Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
isVibrationEnabled);
- if (hasHaptics) {
+ SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
+ if (hasHaptics && (volumeShaperConfig == null
+ || systemSettingsUtil.enableAudioCoupledVibrationForRampingRinger())) {
AudioAttributes attributes = mRingtone.getAudioAttributes();
Log.d(this, "handlePlay: %s haptic channel",
(isVibrationEnabled ? "unmuting" : "muting"));
@@ -254,4 +255,8 @@
}
}
}
+
+ public boolean isPlaying() {
+ return mRingtone != null;
+ }
}
diff --git a/src/com/android/server/telecom/BluetoothAdapterProxy.java b/src/com/android/server/telecom/BluetoothAdapterProxy.java
index 41b4faa..ee9cde3 100644
--- a/src/com/android/server/telecom/BluetoothAdapterProxy.java
+++ b/src/com/android/server/telecom/BluetoothAdapterProxy.java
@@ -43,6 +43,10 @@
if (mBluetoothAdapter == null) {
return false;
}
- return mBluetoothAdapter.setActiveDevice(device, profiles);
+ if (device != null) {
+ return mBluetoothAdapter.setActiveDevice(device, profiles);
+ } else {
+ return mBluetoothAdapter.removeActiveDevice(profiles);
+ }
}
}
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
old mode 100755
new mode 100644
index d15a503..ffcdca9
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -16,6 +16,10 @@
package com.android.server.telecom;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -31,6 +35,7 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.CallLog;
import android.provider.ContactsContract.Contacts;
import android.telecom.CallAudioState;
import android.telecom.CallerInfo;
@@ -53,7 +58,6 @@
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
-import android.util.StatsLog;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
@@ -130,6 +134,7 @@
void onExtrasRemoved(Call c, int source, List<String> keys);
void onHandleChanged(Call call);
void onCallerDisplayNameChanged(Call call);
+ void onCallDirectionChanged(Call call);
void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);
void onTargetPhoneAccountChanged(Call call);
void onConnectionManagerPhoneAccountChanged(Call call);
@@ -197,6 +202,8 @@
@Override
public void onCallerDisplayNameChanged(Call call) {}
@Override
+ public void onCallDirectionChanged(Call call) {}
+ @Override
public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {}
@Override
public void onTargetPhoneAccountChanged(Call call) {}
@@ -258,7 +265,7 @@
/**
* One of CALL_DIRECTION_INCOMING, CALL_DIRECTION_OUTGOING, or CALL_DIRECTION_UNKNOWN
*/
- private final int mCallDirection;
+ private int mCallDirection;
/**
* The post-dial digits that were dialed after the network portion of the number
@@ -314,6 +321,8 @@
private PhoneAccountHandle mTargetPhoneAccountHandle;
+ private PhoneAccountHandle mRemotePhoneAccountHandle;
+
private UserHandle mInitiatingUser;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -506,6 +515,15 @@
*/
private boolean mIsVideoCallingSupportedByPhoneAccount = false;
+ /**
+ * Indicates whether or not this call can be pulled if it is an external call. If true, respect
+ * the Connection Capability set by the ConnectionService. If false, override the capability
+ * set and always remove the ability to pull this external call.
+ *
+ * See {@link #setIsPullExternalCallSupported(boolean)}
+ */
+ private boolean mIsPullExternalCallSupported = true;
+
private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
/**
@@ -530,7 +548,7 @@
private ParcelFileDescriptor[] mConnectionServiceToInCallStreams;
/**
- * True if we're supposed to start this call with RTT, either due to the master switch or due
+ * True if we're supposed to start this call with RTT, either due to the settings switch or due
* to an extra.
*/
private boolean mDidRequestToStartWithRtt = false;
@@ -573,7 +591,7 @@
/**
* Indicates whether this call is using one of the
- * {@link com.android.server.telecom.callfiltering.IncomingCallFilter.CallFilter} modules.
+ * {@link com.android.server.telecom.callfiltering.CallFilter} modules.
*/
private boolean mIsUsingCallFiltering = false;
@@ -596,6 +614,16 @@
private String mPostCallPackageName;
/**
+ * Call missed information code.
+ */
+ @CallLog.Calls.MissedReason private long mMissedReason;
+
+ /**
+ * Time that this call start ringing or simulated ringing.
+ */
+ private long mStartRingTime;
+
+ /**
* Persists the specified parameters and initializes the new instance.
* @param context The context.
* @param repository The connection service repository.
@@ -677,6 +705,8 @@
mClockProxy = clockProxy;
mToastFactory = toastFactory;
mCreationTimeMillis = mClockProxy.currentTimeMillis();
+ mMissedReason = MISSED_REASON_NOT_MISSED;
+ mStartRingTime = 0;
}
/**
@@ -803,21 +833,18 @@
/** {@inheritDoc} */
@Override
public String toString() {
- String component = null;
- if (mConnectionService != null && mConnectionService.getComponentName() != null) {
- component = mConnectionService.getComponentName().flattenToShortString();
- }
-
- return String.format(Locale.US, "[%s, %s, %s, %s, %s, childs(%d), has_parent(%b), %s, %s]",
+ return String.format(Locale.US, "[Call id=%s, state=%s, tpac=%s, cmgr=%s, handle=%s, "
+ + "vidst=%s, childs(%d), has_parent(%b), cap=%s, prop=%s]",
mId,
- CallState.toString(mState),
- component,
+ CallState.toString(getParcelableCallState()),
+ getTargetPhoneAccount(),
+ getConnectionManagerPhoneAccount(),
Log.piiHandle(mHandle),
getVideoStateDescription(getVideoState()),
getChildCalls().size(),
getParentCall() != null,
- Connection.capabilitiesToString(getConnectionCapabilities()),
- Connection.propertiesToString(getConnectionProperties()));
+ Connection.capabilitiesToStringShort(getConnectionCapabilities()),
+ Connection.propertiesToStringShort(getConnectionProperties()));
}
@Override
@@ -835,19 +862,63 @@
s.append(SimpleDateFormat.getDateTimeInstance().format(new Date(getCreationTimeMillis())));
s.append("]");
s.append(isIncoming() ? "(MT - incoming)" : "(MO - outgoing)");
- s.append("\n\tVia PhoneAccount: ");
+ s.append("\n\t");
+
PhoneAccountHandle targetPhoneAccountHandle = getTargetPhoneAccount();
+ PhoneAccountHandle remotePhoneAccountHandle = getRemotePhoneAccountHandle();
+ PhoneAccountHandle connectionMgrAccountHandle = getConnectionManagerPhoneAccount();
+ PhoneAccountHandle delegatePhoneAccountHandle = getDelegatePhoneAccountHandle();
+ boolean isTargetSameAsRemote = targetPhoneAccountHandle != null
+ && targetPhoneAccountHandle.equals(remotePhoneAccountHandle);
+ if (Objects.equals(delegatePhoneAccountHandle, targetPhoneAccountHandle)) {
+ s.append(">>>");
+ }
+ s.append("Target");
+ s.append(" PhoneAccount: ");
if (targetPhoneAccountHandle != null) {
s.append(targetPhoneAccountHandle);
s.append(" (");
s.append(getTargetPhoneAccountLabel());
s.append(")");
+ if (isTargetSameAsRemote) {
+ s.append("(remote)");
+ }
} else {
s.append("not set");
}
+ if (!isTargetSameAsRemote && remotePhoneAccountHandle != null) {
+ // This is a RARE case and will likely not be seen in practice but it is possible.
+ if (delegatePhoneAccountHandle.equals(remotePhoneAccountHandle)) {
+ s.append("\n\t>>>Remote PhoneAccount: ");
+ } else {
+ s.append("\n\tRemote PhoneAccount: ");
+ }
+ s.append(remotePhoneAccountHandle);
+ }
+ if (connectionMgrAccountHandle != null) {
+ if (delegatePhoneAccountHandle.equals(connectionMgrAccountHandle)) {
+ s.append("\n\t>>>Conn mgr: ");
+ } else {
+ s.append("\n\tConn mgr: ");
+ }
+ s.append(connectionMgrAccountHandle);
+ }
s.append("\n\tTo address: ");
s.append(Log.piiHandle(getHandle()));
+ if (isIncoming()) {
+ switch (mCallerNumberVerificationStatus) {
+ case Connection.VERIFICATION_STATUS_FAILED:
+ s.append(" Verstat: fail");
+ break;
+ case Connection.VERIFICATION_STATUS_NOT_VERIFIED:
+ s.append(" Verstat: not");
+ break;
+ case Connection.VERIFICATION_STATUS_PASSED:
+ s.append(" Verstat: pass");
+ break;
+ }
+ }
s.append(" Presentation: ");
switch (getHandlePresentation()) {
case TelecomManager.PRESENTATION_ALLOWED:
@@ -908,6 +979,20 @@
}
/**
+ * Similar to {@link #getState()}, except will return {@link CallState#DISCONNECTING} if the
+ * call is locally disconnecting. This is the call state which is reported to the
+ * {@link android.telecom.InCallService}s when a call is parcelled.
+ * @return The parcelable call state.
+ */
+ public int getParcelableCallState() {
+ if (isLocallyDisconnecting() &&
+ (mState != android.telecom.Call.STATE_DISCONNECTED)) {
+ return CallState.DISCONNECTING;
+ }
+ return mState;
+ }
+
+ /**
* Determines if this {@link Call} can receive call focus via the
* {@link ConnectionServiceFocusManager}.
* Only top-level calls and non-external calls are eligible.
@@ -1054,6 +1139,12 @@
case CallState.ANSWERED:
event = LogUtils.Events.SET_ANSWERED;
break;
+ case CallState.AUDIO_PROCESSING:
+ event = LogUtils.Events.SET_AUDIO_PROCESSING;
+ break;
+ case CallState.SIMULATED_RINGING:
+ event = LogUtils.Events.SET_SIMULATED_RINGING;
+ break;
}
if (event != null) {
// The string data should be just the tag.
@@ -1066,8 +1157,8 @@
}
int statsdDisconnectCause = (newState == CallState.DISCONNECTED) ?
getDisconnectCause().getCode() : DisconnectCause.UNKNOWN;
- StatsLog.write(StatsLog.CALL_STATE_CHANGED, newState, statsdDisconnectCause,
- isSelfManaged(), isExternalCall());
+ TelecomStatsLog.write(TelecomStatsLog.CALL_STATE_CHANGED, newState,
+ statsdDisconnectCause, isSelfManaged(), isExternalCall());
}
return true;
}
@@ -1176,8 +1267,14 @@
// Let's not allow resetting of the emergency flag. Once a call becomes an emergency
// call, it will remain so for the rest of it's lifetime.
if (!mIsEmergencyCall) {
- mIsEmergencyCall = mHandle != null &&
- getTelephonyManager().isEmergencyNumber(mHandle.getSchemeSpecificPart());
+ try {
+ mIsEmergencyCall = mHandle != null &&
+ getTelephonyManager().isEmergencyNumber(
+ mHandle.getSchemeSpecificPart());
+ } catch (IllegalStateException ise) {
+ Log.e(this, ise, "setHandle: can't determine if number is emergency");
+ mIsEmergencyCall = false;
+ }
mAnalytics.setCallIsEmergency(mIsEmergencyCall);
}
if (!mIsTestEmergencyCall) {
@@ -1192,11 +1289,16 @@
}
private boolean isTestEmergencyCall(String number) {
- Map<Integer, List<EmergencyNumber>> eMap = getTelephonyManager().getEmergencyNumberList();
- return eMap.values().stream().flatMap(Collection::stream)
- .anyMatch(eNumber ->
- eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST) &&
- number.equals(eNumber.getNumber()));
+ try {
+ Map<Integer, List<EmergencyNumber>> eMap =
+ getTelephonyManager().getEmergencyNumberList();
+ return eMap.values().stream().flatMap(Collection::stream)
+ .anyMatch(eNumber ->
+ eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST) &&
+ number.equals(eNumber.getNumber()));
+ } catch (IllegalStateException ise) {
+ return false;
+ }
}
public String getCallerDisplayName() {
@@ -1327,6 +1429,45 @@
checkIfRttCapable();
}
+ /**
+ * @return the {@link PhoneAccountHandle} of the remote connection service which placing this
+ * call was delegated to, or {@code null} if a remote connection service was not used.
+ */
+ public @Nullable PhoneAccountHandle getRemotePhoneAccountHandle() {
+ return mRemotePhoneAccountHandle;
+ }
+
+ /**
+ * Sets the {@link PhoneAccountHandle} of the remote connection service which placing this
+ * call was delegated to.
+ * @param accountHandle The phone account handle.
+ */
+ public void setRemotePhoneAccountHandle(PhoneAccountHandle accountHandle) {
+ mRemotePhoneAccountHandle = accountHandle;
+ }
+
+ /**
+ * Determines which {@link PhoneAccountHandle} is actually placing a call.
+ * Where {@link #getRemotePhoneAccountHandle()} is non-null, the connection manager is placing
+ * the call via a remote connection service, so the remote connection service's phone account
+ * is the source.
+ * Where {@link #getConnectionManagerPhoneAccount()} is non-null and
+ * {@link #getRemotePhoneAccountHandle()} is null, the connection manager is placing the call
+ * itself (even if the target specifies something else).
+ * Finally, if neither of the above cases apply, the target phone account is the one actually
+ * placing the call.
+ * @return The {@link PhoneAccountHandle} which is actually placing a call.
+ */
+ public @NonNull PhoneAccountHandle getDelegatePhoneAccountHandle() {
+ if (mRemotePhoneAccountHandle != null) {
+ return mRemotePhoneAccountHandle;
+ }
+ if (mConnectionManagerPhoneAccountHandle != null) {
+ return mConnectionManagerPhoneAccountHandle;
+ }
+ return mTargetPhoneAccountHandle;
+ }
+
@VisibleForTesting
public PhoneAccountHandle getTargetPhoneAccount() {
return mTargetPhoneAccountHandle;
@@ -1437,6 +1578,26 @@
}
/**
+ * Determines if pulling this external call is supported. If it is supported, we will allow the
+ * {@link Connection#CAPABILITY_CAN_PULL_CALL} capability to be added to this call's
+ * capabilities. If it is not supported, we will strip this capability before sending this
+ * call's capabilities to the InCallService.
+ * @param isPullExternalCallSupported true, if pulling this external call is supported, false
+ * otherwise.
+ */
+ public void setIsPullExternalCallSupported(boolean isPullExternalCallSupported) {
+ if (!isExternalCall()) return;
+ if (isPullExternalCallSupported == mIsPullExternalCallSupported) return;
+
+ Log.i(this, "setCanPullExternalCall: canPull=%b", isPullExternalCallSupported);
+
+ mIsPullExternalCallSupported = isPullExternalCallSupported;
+
+ // Use mConnectionCapabilities here to get the unstripped capabilities.
+ setConnectionCapabilities(mConnectionCapabilities, true /* force */);
+ }
+
+ /**
* @return {@code true} if the {@link Call} locally supports video.
*/
public boolean isLocallyVideoCapable() {
@@ -1629,7 +1790,7 @@
mCreationTimeMillis = time;
}
- long getConnectTimeMillis() {
+ public long getConnectTimeMillis() {
return mConnectTimeMillis;
}
@@ -1642,7 +1803,7 @@
}
public int getConnectionCapabilities() {
- return mConnectionCapabilities;
+ return stripUnsupportedCapabilities(mConnectionCapabilities);
}
int getConnectionProperties() {
@@ -1663,15 +1824,33 @@
l.onConnectionCapabilitiesChanged(this);
}
- int xorCaps = previousCapabilities ^ mConnectionCapabilities;
+ int strippedCaps = getConnectionCapabilities();
+ int xorCaps = previousCapabilities ^ strippedCaps;
Log.addEvent(this, LogUtils.Events.CAPABILITY_CHANGE,
"Current: [%s], Removed [%s], Added [%s]",
- Connection.capabilitiesToStringShort(mConnectionCapabilities),
+ Connection.capabilitiesToStringShort(strippedCaps),
Connection.capabilitiesToStringShort(previousCapabilities & xorCaps),
- Connection.capabilitiesToStringShort(mConnectionCapabilities & xorCaps));
+ Connection.capabilitiesToStringShort(strippedCaps & xorCaps));
}
}
+ /**
+ * For some states of Telecom, we need to modify this connection's capabilities:
+ * - A user should not be able to pull an external call during an emergency call, so
+ * CAPABILITY_CAN_PULL_CALL should be removed until the emergency call ends.
+ * @param capabilities The original capabilities.
+ * @return The stripped capabilities.
+ */
+ private int stripUnsupportedCapabilities(int capabilities) {
+ if (!mIsPullExternalCallSupported) {
+ if ((capabilities |= Connection.CAPABILITY_CAN_PULL_CALL) > 0) {
+ capabilities &= ~Connection.CAPABILITY_CAN_PULL_CALL;
+ Log.i(this, "stripCapabilitiesBasedOnState: CAPABILITY_CAN_PULL_CALL removed.");
+ }
+ }
+ return capabilities;
+ }
+
public void setConnectionProperties(int connectionProperties) {
Log.v(this, "setConnectionProperties: %s", Connection.propertiesToString(
connectionProperties));
@@ -1690,16 +1869,22 @@
mConnectionProperties = connectionProperties;
boolean didRttChange =
(changedProperties & Connection.PROPERTY_IS_RTT) == Connection.PROPERTY_IS_RTT;
- if (didRttChange && (mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
- Connection.PROPERTY_IS_RTT) {
- 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.
- mConnectionService.startRtt(this,
- getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
- mWasEverRtt = true;
- if (isEmergencyCall()) {
- mCallsManager.mute(false);
+ if (didRttChange) {
+ if ((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
+ Connection.PROPERTY_IS_RTT) {
+ 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.
+ mConnectionService.startRtt(this,
+ getInCallToCsRttPipeForCs(), getCsToInCallRttPipeForCs());
+ mWasEverRtt = true;
+ if (isEmergencyCall()) {
+ mCallsManager.mute(false);
+ }
+ } else {
+ closeRttStreams();
+ mInCallToConnectionServiceStreams = null;
+ mConnectionServiceToInCallStreams = null;
}
}
mWasHighDefAudio = (connectionProperties & Connection.PROPERTY_HIGH_DEF_AUDIO) ==
@@ -1717,6 +1902,12 @@
Log.v(this, "setConnectionProperties: external call changed isExternal = %b",
isExternal);
Log.addEvent(this, LogUtils.Events.IS_EXTERNAL, isExternal);
+ if (isExternal) {
+ // If there is an ongoing emergency call, remove the ability for this call to
+ // be pulled.
+ boolean isInEmergencyCall = mCallsManager.isInEmergencyCall();
+ setIsPullExternalCallSupported(!isInEmergencyCall);
+ }
for (Listener l : mListeners) {
l.onExternalCallChanged(this, isExternal);
}
@@ -2399,7 +2590,8 @@
}
}
- boolean isActive() {
+ @VisibleForTesting
+ public boolean isActive() {
return mState == CallState.ACTIVE;
}
@@ -2431,7 +2623,7 @@
for (Listener l : mListeners) {
l.onExtrasChanged(this, source, extras);
}
-
+
// If mExtra shows that the call using Volte, record it with mWasVolte
if (mExtras.containsKey(TelecomManager.EXTRA_CALL_NETWORK_TYPE) &&
mExtras.get(TelecomManager.EXTRA_CALL_NETWORK_TYPE)
@@ -2439,6 +2631,18 @@
mWasVolte = true;
}
+ if (extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+ setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
+ }
+
+ // 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.
+ if (mExtras.containsKey(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE)) {
+ setRemotePhoneAccountHandle(extras.getParcelable(
+ Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE));
+ }
+
// If the change originated from an InCallService, notify the connection service.
if (source == SOURCE_INCALL_SERVICE) {
if (mConnectionService != null) {
@@ -2793,7 +2997,7 @@
* ensure the InCall UI is updated with the change in parent.
* @param parentCall The new parent for this call.
*/
- void setChildOf(Call parentCall) {
+ public void setChildOf(Call parentCall) {
if (parentCall != null && !parentCall.getChildCalls().contains(this)) {
parentCall.addChildCall(this);
}
@@ -2815,7 +3019,7 @@
@VisibleForTesting
public boolean can(int capability) {
- return (mConnectionCapabilities & capability) == capability;
+ return (getConnectionCapabilities() & capability) == capability;
}
@VisibleForTesting
@@ -2831,6 +3035,11 @@
mConferenceLevelActiveCall = call;
mChildCalls.add(call);
+ // When adding a child, we will potentially adjust the various times from the calls
+ // based on the children being added. This ensures the parent of the conference has a
+ // connect time reflective of all the children added.
+ maybeAdjustConnectTime(call);
+
Log.addEvent(this, LogUtils.Events.ADD_CHILD, call);
for (Listener l : mListeners) {
@@ -2839,6 +3048,30 @@
}
}
+ /**
+ * Potentially adjust the connect and creation time of this call based on another one.
+ * Ensures that if the other call has an earlier connect time that we adjust the connect time of
+ * this call to match.
+ * <p>
+ * This is important for conference calls; as we add children to the conference we need to
+ * ensure that earlier connect time is reflected on the conference. In the past this
+ * was just done in {@link ParcelableCallUtils} when parceling the calls to the UI, but that
+ * approach would not reflect the right time on the parent as children disconnect.
+ *
+ * @param call the call to potentially use to adjust connect time.
+ */
+ private void maybeAdjustConnectTime(@NonNull Call call) {
+ long childConnectTimeMillis = call.getConnectTimeMillis();
+ long currentConnectTimeMillis = getConnectTimeMillis();
+ // Conference calls typically have a 0 connect time, so we will replace the current connect
+ // time if its zero also.
+ if (childConnectTimeMillis != 0
+ && (currentConnectTimeMillis == 0
+ || childConnectTimeMillis < getConnectTimeMillis())) {
+ setConnectTimeMillis(childConnectTimeMillis);
+ }
+ }
+
private void removeChildCall(Call call) {
if (mChildCalls.remove(call)) {
Log.addEvent(this, LogUtils.Events.REMOVE_CHILD, call);
@@ -2889,8 +3122,8 @@
}
// Is there a valid SMS application on the phone?
- if (TelephonyManager.getDefaultRespondViaMessageApplication(mContext,
- true /*updateIfNeeded*/) == null) {
+ if (mContext.getSystemService(TelephonyManager.class)
+ .getAndUpdateDefaultRespondViaMessageApplication() == null) {
return false;
}
@@ -2922,7 +3155,7 @@
* @return True if the call is ringing, else logs the action name.
*/
private boolean isRinging(String actionName) {
- if (mState == CallState.RINGING) {
+ if (mState == CallState.RINGING || mState == CallState.ANSWERED) {
return true;
}
@@ -3537,6 +3770,24 @@
}
/**
+ * Change the call direction. This is useful if it was not previously defined (for example in
+ * single caller emulation mode).
+ * @param callDirection The new direction of this call.
+ */
+ // Make sure the callDirection has been mapped to the Call definition correctly!
+ public void setCallDirection(int callDirection) {
+ if (mCallDirection != callDirection) {
+ Log.addEvent(this, LogUtils.Events.CALL_DIRECTION_CHANGED, "callDirection="
+ + callDirection);
+ mCallDirection = callDirection;
+ for (Listener l : mListeners) {
+ // Update InCallService directly, do not notify CallsManager.
+ l.onCallDirectionChanged(this);
+ }
+ }
+ }
+
+ /**
* Sets the video history based on the state and state transitions of the call. Always add the
* current video state to the video state history during a call transition except for the
* transitions DIALING->ACTIVE and RINGING->ANSWERED. In these cases, clear the history. If a
@@ -3572,8 +3823,8 @@
public void setIsUsingCallFiltering(boolean isUsingCallFiltering) {
mIsUsingCallFiltering = isUsingCallFiltering;
- }
-
+ }
+
/**
* Returns whether or not Volte call was used.
*
@@ -3646,4 +3897,20 @@
public String getPostCallPackageName() {
return mPostCallPackageName;
}
+
+ public long getMissedReason() {
+ return mMissedReason;
+ }
+
+ public void setMissedReason(long missedReason) {
+ mMissedReason = missedReason;
+ }
+
+ public long getStartRingTime() {
+ return mStartRingTime;
+ }
+
+ public void setStartRingTime(long startRingTime) {
+ mStartRingTime = startRingTime;
+ }
}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 3a84407..a6509b4 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -423,7 +423,7 @@
CallAudioRouteStateMachine.NO_INCLUDE_BLUETOOTH_IN_BASELINE);
return;
default:
- Log.wtf(this, "Invalid route specified: %d", route);
+ Log.w(this, "InCallService requested an invalid audio route: %d", route);
}
}
@@ -449,6 +449,10 @@
}
}
+ public boolean isRingtonePlaying() {
+ return mRinger.isRinging();
+ }
+
@VisibleForTesting
public boolean startRinging() {
synchronized (mCallsManager.getLock()) {
@@ -486,6 +490,11 @@
CallAudioRouteStateMachine.SWITCH_FOCUS, focusState);
}
+ public void notifyAudioOperationsComplete() {
+ mCallAudioModeStateMachine.sendMessageWithArgs(
+ CallAudioModeStateMachine.AUDIO_OPERATIONS_COMPLETE, makeArgsForModeStateMachine());
+ }
+
@VisibleForTesting
public CallAudioRouteStateMachine getCallAudioRouteStateMachine() {
return mCallAudioRouteStateMachine;
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index 5440ebf..2aa9d5d 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -151,6 +151,10 @@
public static final int RINGER_MODE_CHANGE = 5001;
+ // Used to indicate that Telecom is done doing things to the AudioManager and that it's safe
+ // to release focus for other apps to take over.
+ public static final int AUDIO_OPERATIONS_COMPLETE = 6001;
+
public static final int RUN_RUNNABLE = 9001;
private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
@@ -172,6 +176,7 @@
put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING");
put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE");
put(RINGER_MODE_CHANGE, "RINGER_MODE_CHANGE");
+ put(AUDIO_OPERATIONS_COMPLETE, "AUDIO_OPERATIONS_COMPLETE");
put(RUN_RUNNABLE, "RUN_RUNNABLE");
}};
@@ -223,12 +228,11 @@
@Override
public void enter() {
if (mIsInitialized) {
- Log.i(LOG_TAG, "Abandoning audio focus: now UNFOCUSED");
- mAudioManager.setMode(AudioManager.MODE_NORMAL);
- mAudioManager.abandonAudioFocusForCall();
-
- mMostRecentMode = AudioManager.MODE_NORMAL;
mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ mMostRecentMode = AudioManager.MODE_NORMAL;
+ // Don't release focus here -- wait until we get a signal that any other audio
+ // operations triggered by this are done before releasing focus.
}
}
@@ -272,6 +276,10 @@
Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n"
+ args.toString());
return HANDLED;
+ case AUDIO_OPERATIONS_COMPLETE:
+ Log.i(LOG_TAG, "Abandoning audio focus: now UNFOCUSED");
+ mAudioManager.abandonAudioFocusForCall();
+ return HANDLED;
default:
// The forced focus switch commands are handled by BaseState.
return NOT_HANDLED;
@@ -283,12 +291,9 @@
@Override
public void enter() {
if (mIsInitialized) {
- Log.i(LOG_TAG, "Abandoning audio focus: now audio processing");
- mAudioManager.setMode(NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
- mAudioManager.abandonAudioFocusForCall();
-
- mMostRecentMode = NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING;
mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
+ mAudioManager.setMode(NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
+ mMostRecentMode = NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING;
}
}
@@ -336,6 +341,10 @@
Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n"
+ args.toString());
return HANDLED;
+ case AUDIO_OPERATIONS_COMPLETE:
+ Log.i(LOG_TAG, "Abandoning audio focus: now AUDIO_PROCESSING");
+ mAudioManager.abandonAudioFocusForCall();
+ return HANDLED;
default:
// The forced focus switch commands are handled by BaseState.
return NOT_HANDLED;
@@ -344,13 +353,28 @@
}
private class RingingFocusState extends BaseState {
+ // Keeps track of whether we're ringing with audio focus or if we've just entered the state
+ // without acquiring focus because of a silent ringtone or something.
+ private boolean mHasFocus = false;
+
private void tryStartRinging() {
+ if (mHasFocus && mCallAudioManager.isRingtonePlaying()) {
+ Log.i(LOG_TAG, "RingingFocusState#tryStartRinging -- audio focus previously"
+ + " acquired and ringtone already playing -- skipping.");
+ return;
+ }
+
if (mCallAudioManager.startRinging()) {
mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ // Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode -- this
+ // trips up the audio system.
+ if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) {
+ mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ }
mCallAudioManager.setCallAudioRouteFocusState(
CallAudioRouteStateMachine.RINGING_FOCUS);
+ mHasFocus = true;
} else {
Log.i(LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus");
}
@@ -367,6 +391,7 @@
public void exit() {
// Audio mode and audio stream will be set by the next state.
mCallAudioManager.stopRinging();
+ mHasFocus = false;
}
@Override
@@ -416,6 +441,10 @@
tryStartRinging();
return HANDLED;
}
+ case AUDIO_OPERATIONS_COMPLETE:
+ Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused"
+ + " state");
+ return HANDLED;
default:
// The forced focus switch commands are handled by BaseState.
return NOT_HANDLED;
@@ -493,6 +522,10 @@
transitionTo(mVoipCallFocusState);
}
return HANDLED;
+ case AUDIO_OPERATIONS_COMPLETE:
+ Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused"
+ + " state");
+ return HANDLED;
default:
// The forced focus switch commands are handled by BaseState.
return NOT_HANDLED;
@@ -563,6 +596,10 @@
transitionTo(mSimCallFocusState);
}
return HANDLED;
+ case AUDIO_OPERATIONS_COMPLETE:
+ Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused"
+ + " state");
+ return HANDLED;
default:
// The forced focus switch commands are handled by BaseState.
return NOT_HANDLED;
@@ -625,6 +662,11 @@
return HANDLED;
case TONE_STOPPED_PLAYING:
transitionTo(calculateProperStateFromArgs(args));
+ return HANDLED;
+ case AUDIO_OPERATIONS_COMPLETE:
+ Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused"
+ + " state");
+ return HANDLED;
default:
return NOT_HANDLED;
}
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 82d245d..69a870f 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -413,12 +413,15 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ setSpeakerphoneOn(true);
+ // fall through
case SPEAKER_ON:
transitionTo(mActiveSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
reinitialize();
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
default:
@@ -458,6 +461,8 @@
switch (msg.what) {
case SWITCH_EARPIECE:
case USER_SWITCH_EARPIECE:
+ case SPEAKER_ON:
+ // Ignore speakerphone state changes outside of calls.
case SPEAKER_OFF:
// Nothing to do here
return HANDLED;
@@ -483,7 +488,6 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
- case SPEAKER_ON:
transitionTo(mQuiescentSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -532,6 +536,7 @@
// This may be sent as a confirmation by the BT stack after switch off BT.
return HANDLED;
case CONNECT_DOCK:
+ setSpeakerphoneOn(true);
sendInternalMessage(SWITCH_SPEAKER);
return HANDLED;
case DISCONNECT_DOCK:
@@ -610,12 +615,15 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ setSpeakerphoneOn(true);
+ // fall through
case SPEAKER_ON:
transitionTo(mActiveSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
reinitialize();
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
default:
@@ -675,12 +683,13 @@
return HANDLED;
case SWITCH_HEADSET:
case USER_SWITCH_HEADSET:
+ case SPEAKER_ON:
+ // Ignore speakerphone state changes outside of calls.
case SPEAKER_OFF:
// Nothing to do
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
- case SPEAKER_ON:
transitionTo(mQuiescentSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -723,6 +732,7 @@
return HANDLED;
case DISCONNECT_WIRED_HEADSET:
if (mWasOnSpeaker) {
+ setSpeakerphoneOn(true);
sendInternalMessage(SWITCH_SPEAKER);
} else {
sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
@@ -794,6 +804,7 @@
transitionTo(mActiveHeadsetRoute);
break;
case SWITCH_SPEAKER:
+ setSpeakerphoneOn(true);
transitionTo(mActiveSpeakerRoute);
break;
default:
@@ -850,6 +861,8 @@
mHasUserExplicitlyLeftBluetooth = true;
// fall through
case SWITCH_SPEAKER:
+ setSpeakerphoneOn(true);
+ // fall through
case SPEAKER_ON:
setBluetoothOff();
transitionTo(mActiveSpeakerRoute);
@@ -861,6 +874,7 @@
// Only disconnect SCO audio here instead of routing away from BT entirely.
mBluetoothRouteManager.disconnectSco();
reinitialize();
+ mCallAudioManager.notifyAudioOperationsComplete();
} else if (msg.arg1 == RINGING_FOCUS
&& !mBluetoothRouteManager.isInbandRingingEnabled()) {
setBluetoothOff();
@@ -944,6 +958,8 @@
mHasUserExplicitlyLeftBluetooth = true;
// fall through
case SWITCH_SPEAKER:
+ setSpeakerphoneOn(true);
+ // fall through
case SPEAKER_ON:
transitionTo(mActiveSpeakerRoute);
return HANDLED;
@@ -952,6 +968,7 @@
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
reinitialize();
+ mCallAudioManager.notifyAudioOperationsComplete();
} else if (msg.arg1 == ACTIVE_FOCUS) {
setBluetoothOn(null);
}
@@ -1008,6 +1025,8 @@
return HANDLED;
case SWITCH_BLUETOOTH:
case USER_SWITCH_BLUETOOTH:
+ case SPEAKER_ON:
+ // Ignore speakerphone state changes outside of calls.
case SPEAKER_OFF:
// Nothing to do
return HANDLED;
@@ -1021,7 +1040,6 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
- case SPEAKER_ON:
transitionTo(mQuiescentSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -1101,8 +1119,9 @@
@Override
public void enter() {
super.enter();
+ // Don't set speakerphone on here -- we might end up in this state by following
+ // the speaker state that some other app commanded.
mWasOnSpeaker = true;
- setSpeakerphoneOn(true);
CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_SPEAKER,
mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices());
setSystemAudioState(newState, true);
@@ -1175,6 +1194,7 @@
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
reinitialize();
+ mCallAudioManager.notifyAudioOperationsComplete();
}
return HANDLED;
default:
@@ -1588,12 +1608,8 @@
}
private void setSpeakerphoneOn(boolean on) {
- if (mAudioManager.isSpeakerphoneOn() != on) {
- Log.i(this, "turning speaker phone %s", on);
- mAudioManager.setSpeakerphoneOn(on);
- } else {
- Log.i(this, "Ignoring speakerphone request -- already %s", on);
- }
+ Log.i(this, "turning speaker phone %s", on);
+ mAudioManager.setSpeakerphoneOn(on);
mStatusBarNotifier.notifySpeakerphone(on);
}
@@ -1602,10 +1618,13 @@
BluetoothDevice connectedDevice =
mBluetoothRouteManager.getBluetoothAudioConnectedDevice();
if (address == null && connectedDevice != null) {
- // null means connect to any device, so don't bother reconnecting. Also, send a
- // message to ourselves telling us that BT audio is already connected.
- Log.i(this, "HFP audio already on. Skipping connecting.");
+ // null means connect to any device, so if we're already connected to some device,
+ // that means we can just tell ourselves that it's connected.
+ // Do still try to connect audio though, so that BluetoothRouteManager knows that
+ // there's an active call.
+ Log.i(this, "Bluetooth audio already on.");
sendInternalMessage(BT_AUDIO_CONNECTED);
+ mBluetoothRouteManager.connectBluetoothAudio(connectedDevice.getAddress());
return;
}
if (connectedDevice == null || !Objects.equals(address, connectedDevice.getAddress())) {
diff --git a/src/com/android/server/telecom/CallIdMapper.java b/src/com/android/server/telecom/CallIdMapper.java
index da2c199..2cd5c79 100644
--- a/src/com/android/server/telecom/CallIdMapper.java
+++ b/src/com/android/server/telecom/CallIdMapper.java
@@ -20,6 +20,7 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Collection;
import java.util.Map;
/** Utility to map {@link Call} objects to unique IDs. IDs are generated when a call is added. */
@@ -71,6 +72,10 @@
return mSecondaryMap.get(value);
}
+ public Collection<V> getValues() {
+ return mPrimaryMap.values();
+ }
+
public void clear() {
mPrimaryMap.clear();
mSecondaryMap.clear();
@@ -132,6 +137,10 @@
return mCalls.getValue(callId);
}
+ Collection<Call> getCalls() {
+ return mCalls.getValues();
+ }
+
void clear() {
mCalls.clear();
}
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index aea60df..7305ab9 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -165,6 +165,17 @@
boolean isPrivilegedDialer = defaultDialerCache.isDefaultOrSystemDialer(callingPackage,
initiatingUser.getIdentifier());
+ NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
+ context, callsManager, intent, callsManager.getPhoneNumberUtilsAdapter(),
+ isPrivilegedDialer, defaultDialerCache);
+
+ // If the broadcaster comes back with an immediate error, disconnect and show a dialog.
+ NewOutgoingCallIntentBroadcaster.CallDisposition disposition = broadcaster.evaluateCall();
+ if (disposition.disconnectCause != DisconnectCause.NOT_DISCONNECTED) {
+ showErrorDialog(context, disposition.disconnectCause);
+ return;
+ }
+
// Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
CompletableFuture<Call> callFuture = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
@@ -175,8 +186,7 @@
if (call != null) {
Log.continueSession(logSubsession, "CIP.sNOCI");
try {
- sendNewOutgoingCallIntent(context, call, callsManager, intent,
- isPrivilegedDialer, defaultDialerCache);
+ broadcaster.processCall(call, disposition);
} finally {
Log.endSession();
}
@@ -184,27 +194,6 @@
});
}
- static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,
- Intent intent, boolean isPrivilegedDialer, DefaultDialerCache defaultDialerCache) {
- // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
- // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
- // killed if memory is scarce. However, this is OK here because the entire Telecom
- // process will be running throughout the duration of the phone call and should never
- // be killed.
- NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
- context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
- isPrivilegedDialer, defaultDialerCache);
-
- // If the broadcaster comes back with an immediate error, disconnect and show a dialog.
- NewOutgoingCallIntentBroadcaster.CallDisposition disposition = broadcaster.evaluateCall();
- if (disposition.disconnectCause != DisconnectCause.NOT_DISCONNECTED) {
- disconnectCallAndShowErrorDialog(context, call, disposition.disconnectCause);
- return;
- }
-
- broadcaster.processCall(disposition);
- }
-
/**
* If the call is initiated from managed profile but there is no work dialer installed, treat
* the call is initiated from its parent user.
@@ -276,9 +265,7 @@
callsManager.addNewUnknownCall(phoneAccountHandle, intent.getExtras());
}
- private static void disconnectCallAndShowErrorDialog(
- Context context, Call call, int errorCode) {
- call.disconnect();
+ private static void showErrorDialog(Context context, int errorCode) {
final Intent errorIntent = new Intent(context, ErrorDialogActivity.class);
int errorMessageId = -1;
switch (errorCode) {
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index a88fec8..cedd41c 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
import static android.telephony.CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL;
import android.annotation.Nullable;
@@ -84,7 +85,8 @@
int features, PhoneAccountHandle accountHandle, long creationDate,
long durationInMillis, Long dataUsage, UserHandle initiatingUser, boolean isRead,
@Nullable LogCallCompletedListener logCallCompletedListener, int callBlockReason,
- CharSequence callScreeningAppName, String callScreeningComponentName) {
+ CharSequence callScreeningAppName, String callScreeningComponentName,
+ long missedReason) {
this.context = context;
this.callerInfo = callerInfo;
this.number = number;
@@ -103,6 +105,7 @@
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.
@@ -127,6 +130,7 @@
public final int callBockReason;
public final CharSequence callScreeningAppName;
public final String callScreeningComponentName;
+ public final long missedReason;
}
private static final String TAG = CallLogManager.class.getSimpleName();
@@ -311,7 +315,18 @@
*/
void logCall(Call call, int callLogType,
@Nullable LogCallCompletedListener logCallCompletedListener, CallFilteringResult result) {
- final long creationTime = call.getCreationTimeMillis();
+ long creationTime;
+
+ 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();
+ } else {
+ creationTime = call.getCreationTimeMillis();
+ }
+
final long age = call.getAgeMillis();
final String logNumber = getLogNumber(call);
@@ -342,20 +357,25 @@
call.wasEverRttCall(),
call.wasVolte());
- if (callLogType == Calls.BLOCKED_TYPE) {
+ if (result == null) {
+ // Call auto missed before filtered
+ result = new CallFilteringResult.Builder().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);
+ result.mCallScreeningComponentName, call.getMissedReason());
} 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*/);
+ null /*callScreeningComponentName*/, call.getMissedReason());
}
}
@@ -379,6 +399,7 @@
* @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,
@@ -398,7 +419,8 @@
@Nullable LogCallCompletedListener logCallCompletedListener,
int callBlockReason,
CharSequence callScreeningAppName,
- String callScreeningComponentName) {
+ String callScreeningComponentName,
+ long missedReason) {
// 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
@@ -432,7 +454,7 @@
AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
viaNumber, presentation, callType, features, accountHandle, start, duration,
dataUsage, initiatingUser, isRead, logCallCompletedListener, callBlockReason,
- callScreeningAppName, callScreeningComponentName);
+ callScreeningAppName, callScreeningComponentName, missedReason);
logCallAsync(args);
} else {
Log.d(TAG, "Not adding emergency call to call log.");
@@ -585,7 +607,7 @@
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.callScreeningComponentName, c.missedReason);
}
@@ -594,7 +616,8 @@
for (int i = 0; i < result.length; i++) {
Uri uri = result[i];
/*
- Performs a simple sanity check to make sure the call was written in the database.
+ Performs a simple correctness check to make sure the call was written in the
+ database.
Typically there is only one result per call so it is easy to identify which one
failed.
*/
diff --git a/src/com/android/server/telecom/CallRecordingTonePlayer.java b/src/com/android/server/telecom/CallRecordingTonePlayer.java
index 999148c..1b522bc 100644
--- a/src/com/android/server/telecom/CallRecordingTonePlayer.java
+++ b/src/com/android/server/telecom/CallRecordingTonePlayer.java
@@ -24,6 +24,7 @@
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.provider.MediaStore;
import android.telecom.Log;
@@ -61,19 +62,71 @@
}
};
+ private class LoopingTonePlayer extends Handler {
+ private Runnable mPlayToneRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mRecordingTonePlayer != null) {
+ mRecordingTonePlayer.start();
+ postDelayed(this, mRepeatInterval);
+ }
+ }
+ };
+ private MediaPlayer mRecordingTonePlayer = null;
+
+ LoopingTonePlayer() {
+ // We're using the main looper here to avoid creating more threads and risking a thread
+ // leak. The actual playing of the tone doesn't take up much time on the calling
+ // thread, so it's okay to use the main thread for this.
+ super(Looper.getMainLooper());
+ }
+
+ private boolean start() {
+ if (mRecordingTonePlayer != null) {
+ Log.w(CallRecordingTonePlayer.this, "Can't start looping tone player more than"
+ + " once");
+ return false;
+ }
+ AudioDeviceInfo telephonyDevice = getTelephonyDevice(mAudioManager);
+ if (telephonyDevice != null) {
+ mRecordingTonePlayer = MediaPlayer.create(mContext, R.raw.record);
+ mRecordingTonePlayer.setPreferredDevice(telephonyDevice);
+ mRecordingTonePlayer.setVolume(0.1f);
+ AudioAttributes audioAttributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();
+ mRecordingTonePlayer.setAudioAttributes(audioAttributes);
+
+ post(mPlayToneRunnable);
+ return true;
+ } else {
+ Log.w(this ,"startCallRecordingTone: can't find telephony audio device.");
+ return false;
+ }
+ }
+
+ private void stop() {
+ mRecordingTonePlayer.release();
+ mRecordingTonePlayer = null;
+ }
+ }
+
private final AudioManager mAudioManager;
private final Context mContext;
private final TelecomSystem.SyncRoot mLock;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+ private final long mRepeatInterval;
private boolean mIsRecording = false;
- private MediaPlayer mRecordingTonePlayer = null;
+ private LoopingTonePlayer mLoopingTonePlayer;
private List<Call> mCalls = new ArrayList<>();
public CallRecordingTonePlayer(Context context, AudioManager audioManager,
+ Timeouts.Adapter timeouts,
TelecomSystem.SyncRoot lock) {
mContext = context;
mAudioManager = audioManager;
mLock = lock;
+ mRepeatInterval = timeouts.getCallRecordingToneRepeatIntervalMillis(
+ context.getContentResolver());
}
@Override
@@ -163,7 +216,7 @@
*/
private void maybeStartCallAudioTone() {
if (mIsRecording && hasActiveCall()) {
- startCallRecordingTone(mContext);
+ startCallRecordingTone();
}
}
@@ -231,26 +284,15 @@
* Begins playing the call recording tone to the remote end of the call.
* The call recording tone is played via the telephony audio output device; this means that it
* will only be audible to the remote end of the call, not the local side.
- *
- * @param context required for obtaining media player.
*/
- private void startCallRecordingTone(Context context) {
- if (mRecordingTonePlayer != null) {
+ private void startCallRecordingTone() {
+ if (mLoopingTonePlayer != null) {
+ Log.w(this, "Tone is already playing");
return;
}
- AudioDeviceInfo telephonyDevice = getTelephonyDevice(mAudioManager);
- if (telephonyDevice != null) {
- Log.i(this ,"startCallRecordingTone: playing call recording tone to remote end.");
- mRecordingTonePlayer = MediaPlayer.create(context, R.raw.record);
- mRecordingTonePlayer.setLooping(true);
- mRecordingTonePlayer.setPreferredDevice(telephonyDevice);
- mRecordingTonePlayer.setVolume(0.1f);
- AudioAttributes audioAttributes = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();
- mRecordingTonePlayer.setAudioAttributes(audioAttributes);
- mRecordingTonePlayer.start();
- } else {
- Log.w(this ,"startCallRecordingTone: can't find telephony audio device.");
+ mLoopingTonePlayer = new LoopingTonePlayer();
+ if (!mLoopingTonePlayer.start()) {
+ mLoopingTonePlayer = null;
}
}
@@ -258,10 +300,10 @@
* Attempts to stop the call recording tone if it is playing.
*/
private void stopCallRecordingTone() {
- if (mRecordingTonePlayer != null) {
- Log.i(this ,"stopCallRecordingTone: stopping call recording tone.");
- mRecordingTonePlayer.stop();
- mRecordingTonePlayer = null;
+ if (mLoopingTonePlayer != null) {
+ Log.i(this, "stopCallRecordingTone: stopping call recording tone.");
+ mLoopingTonePlayer.stop();
+ mLoopingTonePlayer = null;
}
}
diff --git a/src/com/android/server/telecom/CallScreeningServiceHelper.java b/src/com/android/server/telecom/CallScreeningServiceHelper.java
index 29e9bb0..f02b924 100644
--- a/src/com/android/server/telecom/CallScreeningServiceHelper.java
+++ b/src/com/android/server/telecom/CallScreeningServiceHelper.java
@@ -21,7 +21,6 @@
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.Handler;
import android.os.IBinder;
@@ -45,14 +44,6 @@
private static final String TAG = CallScreeningServiceHelper.class.getSimpleName();
/**
- * Abstracts away dependency on the {@link PackageManager} required to fetch the label for an
- * app.
- */
- public interface AppLabelProxy {
- CharSequence getAppLabel(String packageName);
- }
-
- /**
* Implementation of {@link CallScreeningService} adapter AIDL; provides a means for responses
* from the call screening service to be handled.
*/
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 495dcb4..6b99633 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
import static android.telecom.TelecomManager.ACTION_POST_CALL;
import static android.telecom.TelecomManager.DURATION_LONG;
import static android.telecom.TelecomManager.DURATION_MEDIUM;
@@ -27,23 +28,29 @@
import static android.telecom.TelecomManager.MEDIUM_CALL_TIME_MS;
import static android.telecom.TelecomManager.SHORT_CALL_TIME_MS;
import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS;
+import static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING;
import android.Manifest;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
import android.media.AudioSystem;
-import android.media.ToneGenerator;
import android.media.MediaPlayer;
+import android.media.ToneGenerator;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -63,6 +70,7 @@
import android.provider.Settings;
import android.sysprop.TelephonyProperties;
import android.telecom.CallAudioState;
+import android.telecom.CallerInfo;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
@@ -82,9 +90,12 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
-import android.telecom.CallerInfo;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
@@ -93,23 +104,23 @@
import com.android.server.telecom.callfiltering.CallFilterResultCallback;
import com.android.server.telecom.callfiltering.CallFilteringResult;
import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
+import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
import com.android.server.telecom.callfiltering.DirectToVoicemailFilter;
import com.android.server.telecom.callfiltering.IncomingCallFilter;
import com.android.server.telecom.callfiltering.IncomingCallFilterGraph;
-import com.android.server.telecom.callfiltering.NewCallScreeningServiceFilter;
import com.android.server.telecom.callredirection.CallRedirectionProcessor;
import com.android.server.telecom.components.ErrorDialogActivity;
+import com.android.server.telecom.components.TelecomBroadcastReceiver;
import com.android.server.telecom.settings.BlockedNumbersUtil;
import com.android.server.telecom.ui.AudioProcessingNotification;
-import com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity;
import com.android.server.telecom.ui.CallRedirectionTimeoutDialogActivity;
import com.android.server.telecom.ui.ConfirmCallDialogActivity;
import com.android.server.telecom.ui.DisconnectedCallNotifier;
import com.android.server.telecom.ui.IncomingCallNotifier;
import com.android.server.telecom.ui.ToastFactory;
-import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -166,6 +177,7 @@
void onConnectionTimeChanged(Call call);
void onConferenceStateChanged(Call call, boolean isConference);
void onCdmaConferenceSwap(Call call);
+ void onSetCamera(Call call, String cameraId);
}
/** Interface used to define the action which is executed delay under some condition. */
@@ -383,6 +395,8 @@
private LinkedList<HandlerThread> mGraphHandlerThreads;
+ private boolean mHasActiveRttCall = false;
+
/**
* Listener to PhoneAccountRegistrar events.
*/
@@ -534,7 +548,8 @@
mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
ringtoneFactory, systemVibrator,
new Ringer.VibrationEffectProxy(), mInCallController);
- mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager, mLock);
+ mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager,
+ mTimeoutsAdapter, mLock);
mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
this, callAudioModeStateMachineFactory.create(systemStateHelper,
(AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)),
@@ -672,21 +687,8 @@
String carrierPackageName = getCarrierPackageName();
String defaultDialerPackageName = TelecomManager.from(mContext).getDefaultDialerPackage();
String userChosenPackageName = getRoleManagerAdapter().getDefaultCallScreeningApp();
- CallScreeningServiceHelper.AppLabelProxy appLabelProxy =
- new CallScreeningServiceHelper.AppLabelProxy() {
- @Override
- public CharSequence getAppLabel(String packageName) {
- PackageManager pm = mContext.getPackageManager();
- try {
- ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
- return pm.getApplicationLabel(info);
- } catch (PackageManager.NameNotFoundException nnfe) {
- Log.w(this, "Could not determine package name.");
- }
-
- return null;
- }
- };
+ AppLabelProxy appLabelProxy = packageName -> AppLabelProxy.Util.getAppLabel(
+ mContext.getPackageManager(), packageName);
ParcelableCallUtils.Converter converter = new ParcelableCallUtils.Converter();
IncomingCallFilterGraph graph = new IncomingCallFilterGraph(incomingCall,
@@ -695,29 +697,30 @@
mCallerInfoLookupHelper);
BlockCheckerFilter blockCheckerFilter = new BlockCheckerFilter(mContext, incomingCall,
mCallerInfoLookupHelper, new BlockCheckerAdapter());
- NewCallScreeningServiceFilter carrierCallScreeningServiceFilter =
- new NewCallScreeningServiceFilter(incomingCall, carrierPackageName,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, this,
+ CallScreeningServiceFilter carrierCallScreeningServiceFilter =
+ new CallScreeningServiceFilter(incomingCall, carrierPackageName,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, this,
appLabelProxy, converter);
- NewCallScreeningServiceFilter defaultDialerCallScreeningServiceFilter =
- new NewCallScreeningServiceFilter(incomingCall, defaultDialerPackageName,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_DEFAULT_DIALER, mContext, this,
- appLabelProxy, converter);
- NewCallScreeningServiceFilter userChosenCallScreeningServiceFilter =
- new NewCallScreeningServiceFilter(incomingCall, userChosenPackageName,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_USER_CHOSEN, mContext, this,
- appLabelProxy, converter);
+ CallScreeningServiceFilter callScreeningServiceFilter;
+ if ((userChosenPackageName != null)
+ && (!userChosenPackageName.equals(defaultDialerPackageName))) {
+ callScreeningServiceFilter = new CallScreeningServiceFilter(incomingCall,
+ userChosenPackageName, CallScreeningServiceFilter.PACKAGE_TYPE_USER_CHOSEN,
+ mContext, this, appLabelProxy, converter);
+ } else {
+ callScreeningServiceFilter = new CallScreeningServiceFilter(incomingCall,
+ defaultDialerPackageName,
+ CallScreeningServiceFilter.PACKAGE_TYPE_DEFAULT_DIALER,
+ mContext, this, appLabelProxy, converter);
+ }
graph.addFilter(voicemailFilter);
graph.addFilter(blockCheckerFilter);
graph.addFilter(carrierCallScreeningServiceFilter);
- graph.addFilter(defaultDialerCallScreeningServiceFilter);
- graph.addFilter(userChosenCallScreeningServiceFilter);
+ graph.addFilter(callScreeningServiceFilter);
IncomingCallFilterGraph.addEdge(voicemailFilter, carrierCallScreeningServiceFilter);
IncomingCallFilterGraph.addEdge(blockCheckerFilter, carrierCallScreeningServiceFilter);
IncomingCallFilterGraph.addEdge(carrierCallScreeningServiceFilter,
- defaultDialerCallScreeningServiceFilter);
- IncomingCallFilterGraph.addEdge(carrierCallScreeningServiceFilter,
- userChosenCallScreeningServiceFilter);
+ callScreeningServiceFilter);
mGraphHandlerThreads.add(graph.getHandlerThread());
return graph;
}
@@ -740,6 +743,7 @@
// Only set the incoming call as ringing if it isn't already disconnected. It is possible
// that the connection service disconnected the call before it was even added to Telecom, in
// which case it makes no sense to set it back to a ringing state.
+ Log.i(this, "onCallFilteringComplete");
mGraphHandlerThreads.clear();
if (incomingCall.getState() != CallState.DISCONNECTED &&
@@ -761,25 +765,26 @@
} else {
Log.i(this, "onCallFilteringCompleted: Call rejected! " +
"Exceeds maximum number of ringing calls.");
- rejectCallAndLog(incomingCall, result);
+ incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
+ autoMissCallAndLog(incomingCall, result);
}
} else if (hasMaximumManagedDialingCalls(incomingCall)) {
if (shouldSilenceInsteadOfReject(incomingCall)) {
incomingCall.silence();
} else {
-
Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " +
"dialing calls.");
- rejectCallAndLog(incomingCall, result);
+ incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_DIALING);
+ autoMissCallAndLog(incomingCall, result);
}
- } else if (result.shouldSilence) {
- Log.i(this, "onCallFilteringCompleted: setting the call to silent ringing state");
- incomingCall.setSilentRingingRequested(true);
- addCall(incomingCall);
} else if (result.shouldScreenViaAudio) {
Log.i(this, "onCallFilteringCompleted: starting background audio processing");
answerCallForAudioProcessing(incomingCall);
incomingCall.setAudioProcessingRequestingApp(result.mCallScreeningAppName);
+ } else if (result.shouldSilence) {
+ Log.i(this, "onCallFilteringCompleted: setting the call to silent ringing state");
+ incomingCall.setSilentRingingRequested(true);
+ addCall(incomingCall);
} else {
addCall(incomingCall);
}
@@ -902,6 +907,13 @@
}
@Override
+ public void onConnectionPropertiesChanged(Call call, boolean didRttChange) {
+ if (didRttChange) {
+ updateHasActiveRttCall();
+ }
+ }
+
+ @Override
public void onParentChanged(Call call) {
// parent-child relationship affects which call should be foreground, so do an update.
updateCanAddCall();
@@ -1006,6 +1018,18 @@
}
}
+ /**
+ * Handles a change to the currently active camera for a call by notifying listeners.
+ * @param call The call.
+ * @param cameraId The ID of the camera in use, or {@code null} if no camera is in use.
+ */
+ @Override
+ public void onSetCamera(Call call, String cameraId) {
+ for (CallsManagerListener listener : mListeners) {
+ listener.onSetCamera(call, cameraId);
+ }
+ }
+
public Collection<Call> getCalls() {
return Collections.unmodifiableCollection(mCalls);
}
@@ -1225,7 +1249,10 @@
}
}
- if (extras.getBoolean(PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
+ Bundle phoneAccountExtras = phoneAccount.getExtras();
+ if (phoneAccountExtras != null
+ && phoneAccountExtras.getBoolean(
+ PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
Log.d(this, "processIncomingCallIntent: defaulting to voip mode for call %s",
call.getId());
call.setIsVoipAudioMode(true);
@@ -1260,6 +1287,11 @@
// TODO: Move this to be a part of addCall()
call.addListener(this);
+ if (extras.containsKey(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE)) {
+ String disconnectMessage = extras.getString(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE);
+ Log.i(this, "processIncomingCallIntent Disconnect message " + disconnectMessage);
+ }
+
boolean isHandoverAllowed = true;
if (isHandover) {
if (!isHandoverInProgress() &&
@@ -1309,12 +1341,18 @@
if (isConference) {
notifyCreateConferenceFailed(phoneAccountHandle, call);
} else {
+ if (hasMaximumManagedRingingCalls(call)) {
+ call.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
+ mCallLogManager.logCall(call, Calls.MISSED_TYPE,
+ true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
+ }
notifyCreateConnectionFailed(phoneAccountHandle, call);
}
} else if (isInEmergencyCall()) {
// The incoming call is implicitly being rejected so the user does not get any incoming
// call UI during an emergency call. In this case, log the call as missed instead of
// rejected since the user did not explicitly reject.
+ call.setMissedReason(AUTO_MISSED_EMERGENCY_CALL);
mCallLogManager.logCall(call, Calls.MISSED_TYPE,
true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
if (isConference) {
@@ -1552,14 +1590,33 @@
CompletableFuture<Call> makeRoomForCall = setAccountHandle.thenComposeAsync(
potentialPhoneAccounts -> {
Log.i(CallsManager.this, "make room for outgoing call stage");
- boolean isPotentialInCallMMICode =
- isPotentialInCallMMICode(handle) && !isSelfManaged;
- // Do not support any more live calls. Our options are to move a call to hold,
- // disconnect a call, or cancel this call altogether. If a call is being reused,
- // then it has already passed the makeRoomForOutgoingCall check once and will
- // fail the second time due to the call transitioning into the CONNECTING state.
- if (!isPotentialInCallMMICode && (!isReusedCall
- && !makeRoomForOutgoingCall(finalCall, finalCall.isEmergencyCall()))) {
+ if (isPotentialInCallMMICode(handle) && !isSelfManaged) {
+ return CompletableFuture.completedFuture(finalCall);
+ }
+ // If a call is being reused, then it has already passed the
+ // makeRoomForOutgoingCall check once and will fail the second time due to the
+ // call transitioning into the CONNECTING state.
+ if (isReusedCall) {
+ return CompletableFuture.completedFuture(finalCall);
+ } else {
+ Call reusableCall = reuseOutgoingCall(handle);
+ if (reusableCall != null) {
+ Log.i(CallsManager.this,
+ "reusable call %s came in later; disconnect it.",
+ reusableCall.getId());
+ mPendingCallsToDisconnect.remove(reusableCall);
+ reusableCall.disconnect();
+ markCallAsDisconnected(reusableCall,
+ new DisconnectCause(DisconnectCause.CANCELED));
+ }
+ }
+
+ // 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() ?
+ makeRoomForOutgoingEmergencyCall(finalCall) :
+ makeRoomForOutgoingCall(finalCall);
+ if (!isRoomForCall) {
Call foregroundCall = getForegroundCall();
Log.d(CallsManager.this, "No more room for outgoing call %s ", finalCall);
if (foregroundCall.isSelfManaged()) {
@@ -1791,19 +1848,10 @@
new ParcelableCallUtils.Converter(),
mCurrentUserHandle,
theCall,
- new CallScreeningServiceHelper.AppLabelProxy() {
+ new AppLabelProxy() {
@Override
public CharSequence getAppLabel(String packageName) {
- PackageManager pm = mContext.getPackageManager();
- try {
- ApplicationInfo info = pm.getApplicationInfo(
- packageName, 0);
- return pm.getApplicationLabel(info);
- } catch (PackageManager.NameNotFoundException nnfe) {
- Log.w(this, "Could not determine package name.");
- }
-
- return null;
+ return Util.getAppLabel(mContext.getPackageManager(), packageName);
}
}).process();
future.thenApply( v -> {
@@ -1943,13 +1991,22 @@
boolean endEarly = false;
String disconnectReason = "";
-
String callRedirectionApp = mRoleManagerAdapter.getDefaultCallRedirectionApp();
+ boolean isPotentialEmergencyNumber;
+ try {
+ isPotentialEmergencyNumber =
+ handle != null && getTelephonyManager().isPotentialEmergencyNumber(
+ handle.getSchemeSpecificPart());
+ } catch (IllegalStateException ise) {
+ isPotentialEmergencyNumber = false;
+ }
+
if (shouldCancelCall) {
Log.w(this, "onCallRedirectionComplete: call is canceled");
endEarly = true;
disconnectReason = "Canceled from Call Redirection Service";
+
// Show UX when user-defined call redirection service does not response; the UX
// is not needed to show if the call is disconnected (e.g. by the user)
if (uiAction.equals(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT)
@@ -1970,8 +2027,7 @@
Log.w(this, "onCallRedirectionComplete: phoneAccountHandle is null");
endEarly = true;
disconnectReason = "Null phoneAccountHandle from Call Redirection Service";
- } else if (getTelephonyManager().isPotentialEmergencyNumber(
- handle.getSchemeSpecificPart())) {
+ } else if (isPotentialEmergencyNumber) {
Log.w(this, "onCallRedirectionComplete: emergency number %s is redirected from Call"
+ " Redirection Service", handle.getSchemeSpecificPart());
endEarly = true;
@@ -2020,31 +2076,107 @@
+ "callId=%s, callRedirectionAppName=%s",
call.getId(), callRedirectionApp);
- Intent confirmIntent = new Intent(mContext,
- CallRedirectionConfirmDialogActivity.class);
- confirmIntent.putExtra(
- CallRedirectionConfirmDialogActivity.EXTRA_REDIRECTION_OUTGOING_CALL_ID,
- call.getId());
- confirmIntent.putExtra(CallRedirectionConfirmDialogActivity.EXTRA_REDIRECTION_APP_NAME,
+ showRedirectionDialog(call.getId(),
mRoleManagerAdapter.getApplicationLabelForPackageName(callRedirectionApp));
- confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- // A small delay to start the activity after any Dialer's In Call UI starts
- mHandler.postDelayed(new Runnable("CM.oCRC", mLock) {
- @Override
- public void loggedRun() {
- mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT);
- }
- }.prepare(), 500 /* Milliseconds delay */);
-
} else {
call.setTargetPhoneAccount(phoneAccountHandle);
placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState);
}
}
+ /**
+ * Shows the call redirection confirmation dialog. This is explicitly done here instead of in
+ * an activity class such as {@link ConfirmCallDialogActivity}. This was originally done with
+ * an activity class, however due to the fact that the InCall UI is being spun up at the same
+ * time as the dialog activity, there is a potential race condition where the InCall UI will
+ * often be shown instead of the dialog. Activity manager chooses not to show the redirection
+ * dialog in that case since the new top activity from dialer is going to show.
+ * By showing the dialog here we're able to set the dialog's window type to
+ * {@link WindowManager.LayoutParams#TYPE_SYSTEM_ALERT} which guarantees it shows above other
+ * content on the screen.
+ * @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();
+ LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ View dialogView = layoutInflater.inflate(R.layout.call_redirection_confirm_dialog, null);
+
+ Button buttonFirstLine = (Button) dialogView.findViewById(R.id.buttonFirstLine);
+ buttonFirstLine.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent proceedWithoutRedirectedCall = new Intent(
+ TelecomBroadcastIntentProcessor.ACTION_PLACE_UNREDIRECTED_CALL,
+ null, mContext,
+ TelecomBroadcastReceiver.class);
+ proceedWithoutRedirectedCall.putExtra(
+ TelecomBroadcastIntentProcessor.EXTRA_REDIRECTION_OUTGOING_CALL_ID,
+ callId);
+ mContext.sendBroadcast(proceedWithoutRedirectedCall);
+ confirmDialog.dismiss();
+ }
+ });
+
+ Button buttonSecondLine = (Button) dialogView.findViewById(R.id.buttonSecondLine);
+ buttonSecondLine.setText(mContext.getString(
+ R.string.alert_place_outgoing_call_with_redirection, appName));
+ buttonSecondLine.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent proceedWithRedirectedCall = new Intent(
+ TelecomBroadcastIntentProcessor.ACTION_PLACE_REDIRECTED_CALL, null,
+ mContext,
+ TelecomBroadcastReceiver.class);
+ proceedWithRedirectedCall.putExtra(
+ TelecomBroadcastIntentProcessor.EXTRA_REDIRECTION_OUTGOING_CALL_ID,
+ callId);
+ mContext.sendBroadcast(proceedWithRedirectedCall);
+ confirmDialog.dismiss();
+ }
+ });
+
+ Button buttonThirdLine = (Button) dialogView.findViewById(R.id.buttonThirdLine);
+ buttonThirdLine.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ cancelRedirection(callId);
+ confirmDialog.dismiss();
+ }
+ });
+
+ confirmDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ cancelRedirection(callId);
+ confirmDialog.dismiss();
+ }
+ });
+
+ confirmDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ confirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+
+ confirmDialog.setCancelable(false);
+ confirmDialog.setCanceledOnTouchOutside(false);
+ confirmDialog.setView(dialogView);
+
+ confirmDialog.show();
+ }
+
+ /**
+ * Signals to Telecom that redirection of the call is to be cancelled.
+ */
+ private void cancelRedirection(String callId) {
+ Intent cancelRedirectedCall = new Intent(
+ TelecomBroadcastIntentProcessor.ACTION_CANCEL_REDIRECTED_CALL,
+ null, mContext,
+ TelecomBroadcastReceiver.class);
+ cancelRedirectedCall.putExtra(
+ TelecomBroadcastIntentProcessor.EXTRA_REDIRECTION_OUTGOING_CALL_ID, callId);
+ mContext.sendBroadcastAsUser(cancelRedirectedCall, UserHandle.CURRENT);
+ }
+
public void processRedirectedOutgoingCallAfterUserInteraction(String callId, String action) {
- Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for Call ID %s", callId);
+ Log.i(this, "processRedirectedOutgoingCallAfterUserInteraction for Call ID %s, action=%s",
+ callId, action);
if (mPendingRedirectedOutgoingCall != null && mPendingRedirectedOutgoingCall.getId()
.equals(callId)) {
if (action.equals(TelecomBroadcastIntentProcessor.ACTION_PLACE_REDIRECTED_CALL)) {
@@ -2106,7 +2238,10 @@
// is a video call, of if using speaker when docked
PhoneAccount account = mPhoneAccountRegistrar.getPhoneAccount(
call.getTargetPhoneAccount(), call.getInitiatingUser());
- boolean allowVideo = account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING);
+ boolean allowVideo = false;
+ if (account != null) {
+ allowVideo = account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING);
+ }
call.setStartWithSpeakerphoneOn(speakerphoneOn || (useSpeakerForVideoCall && allowVideo)
|| (useSpeakerWhenDocked && useSpeakerForDock));
call.setVideoState(videoState);
@@ -2241,14 +2376,9 @@
return;
}
- CharSequence requestingAppName;
-
- PackageManager pm = mContext.getPackageManager();
- try {
- ApplicationInfo info = pm.getApplicationInfo( requestingPackageName, 0);
- requestingAppName = pm.getApplicationLabel(info);
- } catch (PackageManager.NameNotFoundException nnfe) {
- Log.w(this, "Could not determine package name.");
+ CharSequence requestingAppName = AppLabelProxy.Util.getAppLabel(
+ mContext.getPackageManager(), requestingPackageName);
+ if (requestingAppName == null) {
requestingAppName = requestingPackageName;
}
@@ -2464,7 +2594,11 @@
Log.w(this, "Unknown call (%s) asked to disconnect", call);
} else {
mLocallyDisconnectingCalls.add(call);
+ int previousState = call.getState();
call.disconnect();
+ for (CallsManagerListener listener : mListeners) {
+ listener.onCallStateChanged(call, previousState, call.getState());
+ }
// Cancel any of the outgoing call futures if they're still around.
if (mPendingCallConfirm != null && !mPendingCallConfirm.isDone()) {
mPendingCallConfirm.complete(null);
@@ -2542,10 +2676,10 @@
Log.addEvent(call, LogUtils.Events.SWAP, "From " + activeCall.getId());
} else {
// This call does not support hold. If it is from a different connection
- // service, then disconnect it, otherwise invoke call.hold() and allow the
- // connection service to handle the situation.
- if (!PhoneAccountHandle.areFromSamePackage(activeCall.getTargetPhoneAccount(),
- call.getTargetPhoneAccount())) {
+ // service or connection manager, then disconnect it, otherwise invoke
+ // call.hold() and allow the connection service or connection manager to handle
+ // the situation.
+ if (!areFromSameSource(activeCall, call)) {
if (!activeCall.isEmergencyCall()) {
activeCall.disconnect("Swap to " + call.getId());
} else {
@@ -2791,11 +2925,11 @@
activeCall.hold();
return true;
} else if (supportsHold(activeCall)
- && PhoneAccountHandle.areFromSamePackage(activeCall.getTargetPhoneAccount(),
- call.getTargetPhoneAccount())) {
+ && areFromSameSource(activeCall, call)) {
- // Handle the case where the active call and the new call are from the same CS, and
- // the currently active call supports hold but cannot currently be held.
+ // Handle the case where the active call and the new call are from the same CS or
+ // connection manager, and the currently active call supports hold but cannot
+ // currently be held.
// In this case we'll look for the other held call for this connectionService and
// disconnect it prior to holding the active call.
// E.g.
@@ -2817,10 +2951,9 @@
return true;
} else {
// This call does not support hold. If it is from a different connection
- // service, then disconnect it, otherwise allow the connection service to
- // figure out the right states.
- if (!PhoneAccountHandle.areFromSamePackage(activeCall.getTargetPhoneAccount(),
- call.getTargetPhoneAccount())) {
+ // service or connection manager, then disconnect it, otherwise allow the connection
+ // service or connection manager to figure out the right states.
+ if (!areFromSameSource(activeCall, call)) {
Log.i(this, "holdActiveCallForNewCall: disconnecting %s so that %s can be "
+ "made active.", activeCall.getId(), call.getId());
if (!activeCall.isEmergencyCall()) {
@@ -2862,6 +2995,9 @@
call.setState(CallState.AUDIO_PROCESSING, "active set explicitly and adding");
addCall(call);
}
+ // Clear mPendingAudioProcessingCall so that future attempts to mark the call as
+ // active (e.g. coming off of hold) don't put the call into audio processing instead
+ mPendingAudioProcessingCall = null;
return;
}
setCallState(call, CallState.ACTIVE, "active set explicitly");
@@ -2882,7 +3018,8 @@
* @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
*/
void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
- if (call.getState() == CallState.SIMULATED_RINGING
+ int oldState = call.getState();
+ if (call.getState() == CallState.SIMULATED_RINGING
&& disconnectCause.getCode() == DisconnectCause.REMOTE) {
// If the remote end hangs up while in SIMULATED_RINGING, the call should
// be marked as missed.
@@ -2890,6 +3027,12 @@
}
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);
+ }
+
}
/**
@@ -3225,6 +3368,11 @@
Conference.CONNECT_TIME_NOT_SPECIFIED ? 0 :
parcelableConference.getConnectElapsedTimeMillis();
+ int callDirection = Call.getRemappedCallDirection(parcelableConference.getCallDirection());
+
+ PhoneAccountHandle connectionMgr =
+ mPhoneAccountRegistrar.getSimCallManagerFromHandle(phoneAccount,
+ mCurrentUserHandle);
Call call = new Call(
callId,
mContext,
@@ -3234,9 +3382,9 @@
mPhoneNumberUtilsAdapter,
null /* handle */,
null /* gatewayInfo */,
- null /* connectionManagerPhoneAccount */,
+ connectionMgr,
phoneAccount,
- Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
+ callDirection,
false /* forceAttachToExistingConnection */,
true /* isConference */,
connectTime,
@@ -3312,7 +3460,8 @@
* Reject an incoming call and manually add it to the Call Log.
* @param incomingCall Incoming call that has been rejected
*/
- private void rejectCallAndLog(Call incomingCall, CallFilteringResult result) {
+ private void autoMissCallAndLog(Call incomingCall, CallFilteringResult result) {
+ incomingCall.getAnalytics().setMissedReason(incomingCall.getMissedReason());
if (incomingCall.getConnectionService() != null) {
// Only reject the call if it has not already been destroyed. If a call ends while
// incoming call filtering is taking place, it is possible that the call has already
@@ -3349,6 +3498,8 @@
SystemClock.elapsedRealtime());
updateCanAddCall();
+ updateHasActiveRttCall();
+ updateExternalCallCanPullSupport();
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
if (LogUtils.SYSTRACE_DEBUG) {
@@ -3362,7 +3513,8 @@
Trace.endSection();
}
- private void removeCall(Call call) {
+ @VisibleForTesting
+ public void removeCall(Call call) {
Trace.beginSection("removeCall");
Log.v(this, "removeCall(%s)", call);
@@ -3378,10 +3530,11 @@
}
call.destroy();
-
+ updateExternalCallCanPullSupport();
// Only broadcast changes for calls that are being tracked.
if (shouldNotify) {
updateCanAddCall();
+ updateHasActiveRttCall();
for (CallsManagerListener listener : mListeners) {
if (LogUtils.SYSTRACE_DEBUG) {
Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
@@ -3395,6 +3548,24 @@
Trace.endSection();
}
+ private void updateHasActiveRttCall() {
+ boolean hasActiveRttCall = hasActiveRttCall();
+ if (hasActiveRttCall != mHasActiveRttCall) {
+ Log.i(this, "updateHasActiveRttCall %s -> %s", mHasActiveRttCall, hasActiveRttCall);
+ AudioManager.setRttEnabled(hasActiveRttCall);
+ mHasActiveRttCall = hasActiveRttCall;
+ }
+ }
+
+ private boolean hasActiveRttCall() {
+ for (Call call : mCalls) {
+ if (call.isActive() && call.isRttCall()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Sets the specified state on the specified call.
*
@@ -3406,7 +3577,8 @@
return;
}
int oldState = call.getState();
- Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
+ Log.i(this, "setCallState %s -> %s, call: %s",
+ CallState.toString(call.getParcelableCallState()),
CallState.toString(newState), call);
if (newState != oldState) {
// If the call switches to held state while a DTMF tone is playing, stop the tone to
@@ -3427,6 +3599,10 @@
(newState == CallState.DISCONNECTED)) {
maybeSendPostCallScreenIntent(call);
}
+ if (((newState == CallState.ABORTED) || (newState == CallState.DISCONNECTED))
+ && (call.getDisconnectCause().getCode() != DisconnectCause.MISSED)) {
+ call.setMissedReason(MISSED_REASON_NOT_MISSED);
+ }
maybeShowErrorDialogOnDisconnect(call);
Trace.beginSection("onCallStateChanged");
@@ -3436,6 +3612,7 @@
// 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() +
@@ -3802,142 +3979,26 @@
}
@VisibleForTesting
- public boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) {
- if (hasMaximumLiveCalls(call)) {
- // NOTE: If the amount of live calls changes beyond 1, this logic will probably
- // have to change.
- Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
- Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " +
- liveCall);
-
- if (call == liveCall) {
- // If the call is already the foreground call, then we are golden.
- // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
- // state since the call was already populated into the list.
- return true;
- }
-
- if (hasMaximumOutgoingCalls(call)) {
- Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
- if (isEmergency && !outgoingCall.isEmergencyCall()) {
- // Disconnect the current outgoing call if it's not an emergency call. If the
- // user tries to make two outgoing calls to different emergency call numbers,
- // we will try to connect the first outgoing call.
- call.getAnalytics().setCallIsAdditional(true);
- outgoingCall.getAnalytics().setCallIsInterrupted(true);
- outgoingCall.disconnect("Disconnecting dialing call in favor of new dialing"
- + " emergency call.");
- return true;
- }
- if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
- // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
- // state, just disconnect it since the user has explicitly started a new call.
- call.getAnalytics().setCallIsAdditional(true);
- outgoingCall.getAnalytics().setCallIsInterrupted(true);
- outgoingCall.disconnect("Disconnecting call in SELECT_PHONE_ACCOUNT in favor"
- + " of new outgoing call.");
- return true;
- }
- return false;
- }
-
- if (liveCall.getState() == CallState.AUDIO_PROCESSING && isEmergency) {
- call.getAnalytics().setCallIsAdditional(true);
- liveCall.getAnalytics().setCallIsInterrupted(true);
- liveCall.disconnect(0, "disconnecting audio processing call for emergency");
- return true;
- }
-
- // If we have the max number of held managed calls and we're placing an emergency call,
- // we'll disconnect the ongoing call if it cannot be held.
- if (hasMaximumManagedHoldingCalls(call) && isEmergency && !canHold(liveCall)) {
- call.getAnalytics().setCallIsAdditional(true);
- liveCall.getAnalytics().setCallIsInterrupted(true);
- liveCall.disconnect("disconnecting to make room for emergency call "
- + call.getId());
- return true;
- }
-
- // TODO: Remove once b/23035408 has been corrected.
- // If the live call is a conference, it will not have a target phone account set. This
- // means the check to see if the live call has the same target phone account as the new
- // call will not cause us to bail early. As a result, we'll end up holding the
- // ongoing conference call. However, the ConnectionService is already doing that. This
- // has caused problems with some carriers. As a workaround until b/23035408 is
- // corrected, we will try and get the target phone account for one of the conference's
- // children and use that instead.
- PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
- if (liveCallPhoneAccount == null && liveCall.isConference() &&
- !liveCall.getChildCalls().isEmpty()) {
- liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
- Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
- liveCallPhoneAccount);
- }
-
- // We may not know which PhoneAccount the emergency call will be placed on yet, but if
- // the liveCall PhoneAccount does not support placing emergency calls, then we know it
- // will not be that one and we do not want multiple PhoneAccounts active during an
- // emergency call if possible. Disconnect the active call in favor of the emergency call
- // instead of trying to hold.
- if (isEmergency && liveCall.getTargetPhoneAccount() != null) {
- PhoneAccount pa = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
- liveCall.getTargetPhoneAccount());
- if((pa.getCapabilities() & PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) == 0) {
- liveCall.setOverrideDisconnectCauseCode(new DisconnectCause(
- DisconnectCause.LOCAL, DisconnectCause.REASON_EMERGENCY_CALL_PLACED));
- liveCall.disconnect("outgoing call does not support emergency calls, "
- + "disconnecting.");
- }
- return true;
- }
-
- // First thing, if we are trying to make a call with the same phone account as the live
- // call, then allow it so that the connection service can make its own decision about
- // how to handle the new call relative to the current one.
- if (PhoneAccountHandle.areFromSamePackage(liveCallPhoneAccount,
- call.getTargetPhoneAccount())) {
- Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
- call.getAnalytics().setCallIsAdditional(true);
- liveCall.getAnalytics().setCallIsInterrupted(true);
- return true;
- } else if (call.getTargetPhoneAccount() == null) {
- // Without a phone account, we can't say reliably that the call will fail.
- // If the user chooses the same phone account as the live call, then it's
- // still possible that the call can be made (like with CDMA calls not supporting
- // hold but they still support adding a call by going immediately into conference
- // mode). Return true here and we'll run this code again after user chooses an
- // account.
- return true;
- }
-
- // Try to hold the live call before attempting the new outgoing call.
- if (canHold(liveCall)) {
- Log.i(this, "makeRoomForOutgoingCall: holding live call.");
- call.getAnalytics().setCallIsAdditional(true);
- liveCall.getAnalytics().setCallIsInterrupted(true);
- liveCall.hold("calling " + call.getId());
- return true;
- }
-
- // The live call cannot be held so we're out of luck here. There's no room.
- return false;
- } else if (hasRingingOrSimulatedRingingCall() && isEmergency) {
+ public boolean makeRoomForOutgoingEmergencyCall(Call emergencyCall) {
+ // Always disconnect any ringing/incoming calls when an emergency call is placed to minimize
+ // distraction. This does not affect live call count.
+ if (hasRingingOrSimulatedRingingCall()) {
Call ringingCall = getRingingOrSimulatedRingingCall();
ringingCall.getAnalytics().setCallIsAdditional(true);
ringingCall.getAnalytics().setCallIsInterrupted(true);
if (ringingCall.getState() == CallState.SIMULATED_RINGING) {
- if (!ringingCall.hasGoneActiveBefore()) {
- // If this is an incoming call that is currently in SIMULATED_RINGING only
- // after a call screen, disconnect to make room and mark as missed, since
- // the user didn't get a chance to accept/reject.
- ringingCall.disconnect("emergency call dialed during simulated ringing "
- + "after screen.");
- } else {
- // If this is a simulated ringing call after being active and put in
- // AUDIO_PROCESSING state again, disconnect normally.
- ringingCall.reject(false, null, "emergency call dialed during simulated "
- + "ringing.");
- }
+ if (!ringingCall.hasGoneActiveBefore()) {
+ // If this is an incoming call that is currently in SIMULATED_RINGING only
+ // after a call screen, disconnect to make room and mark as missed, since
+ // the user didn't get a chance to accept/reject.
+ ringingCall.disconnect("emergency call dialed during simulated ringing "
+ + "after screen.");
+ } else {
+ // If this is a simulated ringing call after being active and put in
+ // AUDIO_PROCESSING state again, disconnect normally.
+ ringingCall.reject(false, null, "emergency call dialed during simulated "
+ + "ringing.");
+ }
} else { // normal incoming ringing call.
// Hang up the ringing call to make room for the emergency call and mark as missed,
// since the user did not reject.
@@ -3945,9 +4006,208 @@
new DisconnectCause(DisconnectCause.MISSED));
ringingCall.reject(false, null, "emergency call dialed during ringing.");
}
+ }
+
+ // There is already room!
+ if (!hasMaximumLiveCalls(emergencyCall)) return true;
+
+ Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
+ Log.i(this, "makeRoomForOutgoingEmergencyCall call = " + emergencyCall
+ + " livecall = " + liveCall);
+
+ if (emergencyCall == liveCall) {
+ // Not likely, but a good correctness check.
return true;
}
- return true;
+
+ if (hasMaximumOutgoingCalls(emergencyCall)) {
+ Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
+ if (!outgoingCall.isEmergencyCall()) {
+ emergencyCall.getAnalytics().setCallIsAdditional(true);
+ outgoingCall.getAnalytics().setCallIsInterrupted(true);
+ outgoingCall.disconnect("Disconnecting dialing call in favor of new dialing"
+ + " emergency call.");
+ return true;
+ }
+ if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
+ // Correctness check: if there is an orphaned emergency call in the
+ // {@link CallState#SELECT_PHONE_ACCOUNT} state, just disconnect it since the user
+ // has explicitly started a new call.
+ emergencyCall.getAnalytics().setCallIsAdditional(true);
+ outgoingCall.getAnalytics().setCallIsInterrupted(true);
+ outgoingCall.disconnect("Disconnecting call in SELECT_PHONE_ACCOUNT in favor"
+ + " of new outgoing call.");
+ return true;
+ }
+ // If the user tries to make two outgoing calls to different emergency call numbers,
+ // we will try to connect the first outgoing call and reject the second.
+ return false;
+ }
+
+ if (liveCall.getState() == CallState.AUDIO_PROCESSING) {
+ emergencyCall.getAnalytics().setCallIsAdditional(true);
+ liveCall.getAnalytics().setCallIsInterrupted(true);
+ liveCall.disconnect("disconnecting audio processing call for emergency");
+ return true;
+ }
+
+ // If we have the max number of held managed calls and we're placing an emergency call,
+ // we'll disconnect the ongoing call if it cannot be held.
+ if (hasMaximumManagedHoldingCalls(emergencyCall) && !canHold(liveCall)) {
+ emergencyCall.getAnalytics().setCallIsAdditional(true);
+ liveCall.getAnalytics().setCallIsInterrupted(true);
+ // Disconnect the active call instead of the holding call because it is historically
+ // easier to do, rather than disconnect a held call.
+ liveCall.disconnect("disconnecting to make room for emergency call "
+ + emergencyCall.getId());
+ return true;
+ }
+
+ // TODO: Remove once b/23035408 has been corrected.
+ // If the live call is a conference, it will not have a target phone account set. This
+ // means the check to see if the live call has the same target phone account as the new
+ // call will not cause us to bail early. As a result, we'll end up holding the
+ // ongoing conference call. However, the ConnectionService is already doing that. This
+ // has caused problems with some carriers. As a workaround until b/23035408 is
+ // corrected, we will try and get the target phone account for one of the conference's
+ // children and use that instead.
+ PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
+ if (liveCallPhoneAccount == null && liveCall.isConference() &&
+ !liveCall.getChildCalls().isEmpty()) {
+ liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
+ Log.i(this, "makeRoomForOutgoingEmergencyCall: using child call PhoneAccount = " +
+ liveCallPhoneAccount);
+ }
+
+ // We may not know which PhoneAccount the emergency call will be placed on yet, but if
+ // the liveCall PhoneAccount does not support placing emergency calls, then we know it
+ // will not be that one and we do not want multiple PhoneAccounts active during an
+ // emergency call if possible. Disconnect the active call in favor of the emergency call
+ // instead of trying to hold.
+ if (liveCall.getTargetPhoneAccount() != null) {
+ PhoneAccount pa = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
+ liveCall.getTargetPhoneAccount());
+ if((pa.getCapabilities() & PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) == 0) {
+ liveCall.setOverrideDisconnectCauseCode(new DisconnectCause(
+ DisconnectCause.LOCAL, DisconnectCause.REASON_EMERGENCY_CALL_PLACED));
+ liveCall.disconnect("outgoing call does not support emergency calls, "
+ + "disconnecting.");
+ }
+ return true;
+ }
+
+ // First thing, if we are trying to make an emergency call with the same package name as
+ // the live call, then allow it so that the connection service can make its own decision
+ // about how to handle the new call relative to the current one.
+ // By default, for telephony, it will try to hold the existing call before placing the new
+ // emergency call except for if the carrier does not support holding calls for emergency.
+ // In this case, telephony will disconnect the call.
+ if (PhoneAccountHandle.areFromSamePackage(liveCallPhoneAccount,
+ emergencyCall.getTargetPhoneAccount())) {
+ Log.i(this, "makeRoomForOutgoingEmergencyCall: phoneAccount matches.");
+ emergencyCall.getAnalytics().setCallIsAdditional(true);
+ liveCall.getAnalytics().setCallIsInterrupted(true);
+ return true;
+ } else if (emergencyCall.getTargetPhoneAccount() == null) {
+ // Without a phone account, we can't say reliably that the call will fail.
+ // If the user chooses the same phone account as the live call, then it's
+ // still possible that the call can be made (like with CDMA calls not supporting
+ // hold but they still support adding a call by going immediately into conference
+ // mode). Return true here and we'll run this code again after user chooses an
+ // account.
+ return true;
+ }
+
+ // Hold the live call if possible before attempting the new outgoing emergency call.
+ if (canHold(liveCall)) {
+ Log.i(this, "makeRoomForOutgoingEmergencyCall: holding live call.");
+ emergencyCall.getAnalytics().setCallIsAdditional(true);
+ liveCall.getAnalytics().setCallIsInterrupted(true);
+ liveCall.hold("calling " + emergencyCall.getId());
+ return true;
+ }
+
+ // The live call cannot be held so we're out of luck here. There's no room.
+ return false;
+ }
+
+ private boolean makeRoomForOutgoingCall(Call call) {
+ // Already room!
+ if (!hasMaximumLiveCalls(call)) return true;
+
+ // NOTE: If the amount of live calls changes beyond 1, this logic will probably
+ // have to change.
+ Call liveCall = getFirstCallWithState(LIVE_CALL_STATES);
+ Log.i(this, "makeRoomForOutgoingCall call = " + call + " livecall = " +
+ liveCall);
+
+ if (call == liveCall) {
+ // If the call is already the foreground call, then we are golden.
+ // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
+ // state since the call was already populated into the list.
+ return true;
+ }
+
+ if (hasMaximumOutgoingCalls(call)) {
+ Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
+ if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
+ // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
+ // state, just disconnect it since the user has explicitly started a new call.
+ call.getAnalytics().setCallIsAdditional(true);
+ outgoingCall.getAnalytics().setCallIsInterrupted(true);
+ outgoingCall.disconnect("Disconnecting call in SELECT_PHONE_ACCOUNT in favor"
+ + " of new outgoing call.");
+ return true;
+ }
+ return false;
+ }
+
+ // TODO: Remove once b/23035408 has been corrected.
+ // If the live call is a conference, it will not have a target phone account set. This
+ // means the check to see if the live call has the same target phone account as the new
+ // call will not cause us to bail early. As a result, we'll end up holding the
+ // ongoing conference call. However, the ConnectionService is already doing that. This
+ // has caused problems with some carriers. As a workaround until b/23035408 is
+ // corrected, we will try and get the target phone account for one of the conference's
+ // children and use that instead.
+ PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
+ if (liveCallPhoneAccount == null && liveCall.isConference() &&
+ !liveCall.getChildCalls().isEmpty()) {
+ liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
+ Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
+ liveCallPhoneAccount);
+ }
+
+ // First thing, if we are trying to make a call with the same phone account as the live
+ // call, then allow it so that the connection service can make its own decision about
+ // how to handle the new call relative to the current one.
+ if (PhoneAccountHandle.areFromSamePackage(liveCallPhoneAccount,
+ call.getTargetPhoneAccount())) {
+ Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
+ call.getAnalytics().setCallIsAdditional(true);
+ liveCall.getAnalytics().setCallIsInterrupted(true);
+ return true;
+ } else if (call.getTargetPhoneAccount() == null) {
+ // Without a phone account, we can't say reliably that the call will fail.
+ // If the user chooses the same phone account as the live call, then it's
+ // still possible that the call can be made (like with CDMA calls not supporting
+ // hold but they still support adding a call by going immediately into conference
+ // mode). Return true here and we'll run this code again after user chooses an
+ // account.
+ return true;
+ }
+
+ // Try to hold the live call before attempting the new outgoing call.
+ if (canHold(liveCall)) {
+ Log.i(this, "makeRoomForOutgoingCall: holding live call.");
+ call.getAnalytics().setCallIsAdditional(true);
+ liveCall.getAnalytics().setCallIsInterrupted(true);
+ liveCall.hold("calling " + call.getId());
+ return true;
+ }
+
+ // The live call cannot be held so we're out of luck here. There's no room.
+ return false;
}
/**
@@ -4013,6 +4273,10 @@
Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
boolean isDowngradedConference = (connection.getConnectionProperties()
& Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
+
+ PhoneAccountHandle connectionMgr =
+ mPhoneAccountRegistrar.getSimCallManagerFromHandle(connection.getPhoneAccount(),
+ mCurrentUserHandle);
Call call = new Call(
callId,
mContext,
@@ -4022,7 +4286,7 @@
mPhoneNumberUtilsAdapter,
connection.getHandle() /* handle */,
null /* gatewayInfo */,
- null /* connectionManagerPhoneAccount */,
+ connectionMgr,
connection.getPhoneAccount(), /* targetPhoneAccountHandle */
Call.getRemappedCallDirection(connection.getCallDirection()) /* callDirection */,
false /* forceAttachToExistingConnection */,
@@ -4044,13 +4308,8 @@
call.setCallerDisplayName(connection.getCallerDisplayName(),
connection.getCallerDisplayNamePresentation());
call.addListener(this);
+ call.putExtras(Call.SOURCE_CONNECTION_SERVICE, connection.getExtras());
- // In case this connection was added via a ConnectionManager, keep track of the original
- // Connection ID as created by the originating ConnectionService.
- Bundle extras = connection.getExtras();
- if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
- call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
- }
Log.i(this, "createCallForExistingConnection: %s", connection);
Call parentCall = null;
if (!TextUtils.isEmpty(connection.getParentCallId())) {
@@ -4376,6 +4635,18 @@
pw.println(mPendingCall.getId());
}
+ if (mPendingRedirectedOutgoingCallInfo.size() > 0) {
+ pw.print("mPendingRedirectedOutgoingCallInfo:");
+ pw.println(mPendingRedirectedOutgoingCallInfo.keySet().stream().collect(
+ Collectors.joining(", ")));
+ }
+
+ if (mPendingUnredirectedOutgoingCallInfo.size() > 0) {
+ pw.print("mPendingUnredirectedOutgoingCallInfo:");
+ pw.println(mPendingUnredirectedOutgoingCallInfo.keySet().stream().collect(
+ Collectors.joining(", ")));
+ }
+
if (mCallAudioManager != null) {
pw.println("mCallAudioManager:");
pw.increaseIndent();
@@ -4488,6 +4759,7 @@
* @param call The {@link Call} which could not be added.
*/
private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) {
+ call.getAnalytics().setMissedReason(call.getMissedReason());
if (phoneAccountHandle == null) {
return;
}
@@ -4946,6 +5218,12 @@
// we can just declare it active.
setCallState(mCall, CallState.ACTIVE, "answering simulated ringing");
Log.addEvent(mCall, LogUtils.Events.REQUEST_SIMULATED_ACCEPT);
+ } else if (mCall.getState() == CallState.ANSWERED) {
+ // In certain circumstances, the connection service can lose track of a request
+ // to answer a call. Therefore, if the user presses answer again, still send it
+ // on down, but log a warning in the process and don't change the call state.
+ mCall.answer(mVideoState);
+ Log.w(this, "Duplicate answer request for call %s", mCall.getId());
}
if (isSpeakerphoneAutoEnabledForVideoCalls(mVideoState)) {
mCall.setStartWithSpeakerphoneOn(true);
@@ -4996,6 +5274,18 @@
}
/**
+ * Trigger a recalculation of support for CAPABILITY_CAN_PULL_CALL for external calls due to
+ * a possible emergency call being added/removed.
+ */
+ private void updateExternalCallCanPullSupport() {
+ boolean isInEmergencyCall = isInEmergencyCall();
+ // Remove the capability to pull an external call in the case that we are in an emergency
+ // call.
+ mCalls.stream().filter(Call::isExternalCall).forEach(
+ c->c.setIsPullExternalCallSupported(!isInEmergencyCall));
+ }
+
+ /**
* Trigger display of an error message to the user; we do this outside of dialer for calls which
* fail to be created and added to Dialer.
* @param messageId The string resource id.
@@ -5026,6 +5316,32 @@
.forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported));
}
+ /**
+ * Determines if two {@link Call} instances originated from either the same target
+ * {@link PhoneAccountHandle} or connection manager {@link PhoneAccountHandle}.
+ * @param call1 The first call
+ * @param call2 The second call
+ * @return {@code true} if both calls are from the same target or connection manager
+ * {@link PhoneAccountHandle}.
+ */
+ public static boolean areFromSameSource(@NonNull Call call1, @NonNull Call call2) {
+ PhoneAccountHandle call1ConnectionMgr = call1.getConnectionManagerPhoneAccount();
+ PhoneAccountHandle call2ConnectionMgr = call2.getConnectionManagerPhoneAccount();
+
+ if (call1ConnectionMgr != null && call2ConnectionMgr != null
+ && PhoneAccountHandle.areFromSamePackage(call1ConnectionMgr, call2ConnectionMgr)) {
+ // Both calls share the same connection manager package, so they are from the same
+ // source.
+ return true;
+ }
+
+ PhoneAccountHandle call1TargetAcct = call1.getTargetPhoneAccount();
+ PhoneAccountHandle call2TargetAcct = call2.getTargetPhoneAccount();
+ // Otherwise if the target phone account for both is the same package, they're the same
+ // source.
+ return PhoneAccountHandle.areFromSamePackage(call1TargetAcct, call2TargetAcct);
+ }
+
public LinkedList<HandlerThread> getGraphHandlerThreads() {
return mGraphHandlerThreads;
}
@@ -5053,4 +5369,9 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, mCurrentUserHandle);
}
+
+ @VisibleForTesting
+ public void addToPendingCallsToDisconnect(Call call) {
+ mPendingCallsToDisconnect.add(call);
+ }
}
diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java
index e0d2831..55c7b53 100644
--- a/src/com/android/server/telecom/CallsManagerListenerBase.java
+++ b/src/com/android/server/telecom/CallsManagerListenerBase.java
@@ -104,4 +104,8 @@
@Override
public void onCdmaConferenceSwap(Call call) {
}
+
+ @Override
+ public void onSetCamera(Call call, String cameraId) {
+ }
}
diff --git a/src/com/android/server/telecom/CarModeTracker.java b/src/com/android/server/telecom/CarModeTracker.java
index 0ec4917..e64ef5d 100644
--- a/src/com/android/server/telecom/CarModeTracker.java
+++ b/src/com/android/server/telecom/CarModeTracker.java
@@ -28,6 +28,7 @@
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.PriorityQueue;
import java.util.stream.Collectors;
@@ -144,6 +145,28 @@
}
/**
+ * Force-removes a package from the car mode tracking list, no matter at which priority.
+ *
+ * This handles the case where packages are disabled or uninstalled. In those case, remove them
+ * 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()
+ .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());
+ 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);
+ }
+ }
+
+ /**
* Retrieves a list of the apps which are currently in car mode, ordered by priority such that
* the highest priority app is first.
* @return List of apps in car mode.
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 3ae00aa..72c3f24 100755
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -43,7 +43,6 @@
import android.telecom.StatusHints;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
-import android.telephony.TelephonyManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.IConnectionService;
@@ -70,12 +69,15 @@
public class ConnectionServiceWrapper extends ServiceBinder implements
ConnectionServiceFocusManager.ConnectionServiceFocus {
+ private static final String TELECOM_ABBREVIATION = "cast";
+
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
ParcelableConnection connection, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE,
+ mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -89,6 +91,7 @@
mServiceInterface.createConnectionComplete(callId,
Log.getExternalSession());
} catch (RemoteException e) {
+ logOutgoing("createConnectionComplete remote exception=%s", e);
}
}
}
@@ -104,7 +107,8 @@
@Override
public void handleCreateConferenceComplete(String callId, ConnectionRequest request,
ParcelableConference conference, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE,
+ mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -133,7 +137,8 @@
@Override
public void setActive(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE,
+ mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -156,7 +161,7 @@
@Override
public void setRinging(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING, mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -179,7 +184,7 @@
@Override
public void resetConnectionTime(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.rCCT");
+ Log.startSession(sessionInfo, "CSW.rCCT", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -200,7 +205,7 @@
@Override
public void setVideoProvider(String callId, IVideoProvider videoProvider,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sVP");
+ Log.startSession(sessionInfo, "CSW.sVP", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -221,7 +226,7 @@
@Override
public void setDialing(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING, mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -244,7 +249,7 @@
@Override
public void setPulling(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING, mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -266,7 +271,8 @@
@Override
public void setDisconnected(String callId, DisconnectCause disconnectCause,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED,
+ mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -290,7 +296,7 @@
@Override
public void setOnHold(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD, mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -314,7 +320,7 @@
@Override
public void setRingbackRequested(String callId, boolean ringback,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.SRR");
+ Log.startSession(sessionInfo, "CSW.SRR", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -337,7 +343,7 @@
@Override
public void removeCall(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL, mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -364,7 +370,7 @@
@Override
public void setConnectionCapabilities(String callId, int connectionCapabilities,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sCC");
+ Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -389,7 +395,7 @@
@Override
public void setConnectionProperties(String callId, int connectionProperties,
Session.Info sessionInfo) {
- Log.startSession("CSW.sCP");
+ Log.startSession("CSW.sCP", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -411,7 +417,8 @@
@Override
public void setIsConferenced(String callId, String conferenceCallId,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED,
+ mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -440,7 +447,7 @@
@Override
public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sCMF");
+ Log.startSession(sessionInfo, "CSW.sCMF", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -467,31 +474,29 @@
@Override
public void addConferenceCall(String callId, ParcelableConference parcelableConference,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL);
+ Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL,
+ mPackageAbbreviation);
if (parcelableConference.getConnectElapsedTimeMillis() != 0
&& mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(this, "addConferenceCall from caller without permission!");
- parcelableConference = new ParcelableConference(
+ parcelableConference = new ParcelableConference.Builder(
parcelableConference.getPhoneAccount(),
- parcelableConference.getState(),
- parcelableConference.getConnectionCapabilities(),
- parcelableConference.getConnectionProperties(),
- parcelableConference.getConnectionIds(),
- parcelableConference.getVideoProvider(),
- parcelableConference.getVideoState(),
- 0 /* connectTimeMillis */,
- 0 /* connectElapsedRealTime */,
- parcelableConference.getStatusHints(),
- parcelableConference.getExtras(),
- parcelableConference.getHandle(),
- parcelableConference.getHandlePresentation(),
- "" /* callerDisplayName */,
- TelecomManager.PRESENTATION_UNKNOWN /* callerDisplayNamePresentation */,
- parcelableConference.getDisconnectCause(),
- parcelableConference.isRingbackRequested()
- );
+ parcelableConference.getState())
+ .setConnectionCapabilities(parcelableConference.getConnectionCapabilities())
+ .setConnectionProperties(parcelableConference.getConnectionProperties())
+ .setConnectionIds(parcelableConference.getConnectionIds())
+ .setVideoAttributes(parcelableConference.getVideoProvider(),
+ parcelableConference.getVideoState())
+ .setStatusHints(parcelableConference.getStatusHints())
+ .setExtras(parcelableConference.getExtras())
+ .setAddress(parcelableConference.getHandle(),
+ parcelableConference.getHandlePresentation())
+ // no caller display name set.
+ .setDisconnectCause(parcelableConference.getDisconnectCause())
+ .setRingbackRequested(parcelableConference.isRingbackRequested())
+ .build();
}
long token = Binder.clearCallingIdentity();
@@ -584,7 +589,7 @@
@Override
public void onPostDialWait(String callId, String remaining,
Session.Info sessionInfo) throws RemoteException {
- Log.startSession(sessionInfo, "CSW.oPDW");
+ Log.startSession(sessionInfo, "CSW.oPDW", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -608,7 +613,7 @@
@Override
public void onPostDialChar(String callId, char nextChar,
Session.Info sessionInfo) throws RemoteException {
- Log.startSession(sessionInfo, "CSW.oPDC");
+ Log.startSession(sessionInfo, "CSW.oPDC", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -633,7 +638,7 @@
public void queryRemoteConnectionServices(RemoteServiceCallback callback,
String callingPackage, Session.Info sessionInfo) {
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
- Log.startSession(sessionInfo, "CSW.qRCS");
+ Log.startSession(sessionInfo, "CSW.qRCS", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -653,7 +658,7 @@
@Override
public void setVideoState(String callId, int videoState, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sVS");
+ Log.startSession(sessionInfo, "CSW.sVS", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -674,7 +679,7 @@
@Override
public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sIVAM");
+ Log.startSession(sessionInfo, "CSW.sIVAM", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -696,7 +701,7 @@
@Override
public void setAudioRoute(String callId, int audioRoute,
String bluetoothAddress, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sAR");
+ Log.startSession(sessionInfo, "CSW.sAR", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -716,7 +721,7 @@
@Override
public void setStatusHints(String callId, StatusHints statusHints,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sSH");
+ Log.startSession(sessionInfo, "CSW.sSH", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -737,7 +742,7 @@
@Override
public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.pE");
+ Log.startSession(sessionInfo, "CSW.pE", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -758,7 +763,7 @@
@Override
public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.rE");
+ Log.startSession(sessionInfo, "CSW.rE", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -780,13 +785,7 @@
@Override
public void setAddress(String callId, Uri address, int presentation,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sA");
-
- if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- Log.w(this, "setAddress from caller without permission.");
- return;
- }
+ Log.startSession(sessionInfo, "CSW.sA", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
@@ -809,7 +808,7 @@
@Override
public void setCallerDisplayName(String callId, String callerDisplayName, int presentation,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sCDN");
+ Log.startSession(sessionInfo, "CSW.sCDN", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -832,7 +831,7 @@
@Override
public void setConferenceableConnections(String callId, List<String> conferenceableCallIds,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.sCC");
+ Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -864,7 +863,7 @@
@Override
public void addExistingConnection(String callId, ParcelableConnection connection,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.aEC");
+ Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation);
UserHandle userHandle = Binder.getCallingUserHandle();
// Check that the Calling Package matches PhoneAccountHandle's Component Package
PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount();
@@ -873,12 +872,6 @@
callingPhoneAccountHandle.getComponentName().getPackageName());
}
- if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- Log.w(this, "addExistingConnection from caller without permission!");
- return;
- }
-
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -959,7 +952,7 @@
@Override
public void onConnectionEvent(String callId, String event, Bundle extras,
Session.Info sessionInfo) {
- Log.startSession(sessionInfo, "CSW.oCE");
+ Log.startSession(sessionInfo, "CSW.oCE", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -987,7 +980,7 @@
@Override
public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
throws RemoteException {
- Log.startSession(sessionInfo, "CSW.oRIF");
+ Log.startSession(sessionInfo, "CSW.oRIF", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1014,7 +1007,7 @@
@Override
public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
throws RemoteException {
- Log.startSession(sessionInfo, "CSW.oRRR");
+ Log.startSession(sessionInfo, "CSW.oRRR", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1040,7 +1033,7 @@
mAppOpsManager.checkPackage(Binder.getCallingUid(),
pHandle.getComponentName().getPackageName());
}
- Log.startSession(sessionInfo, "CSW.oPAC");
+ Log.startSession(sessionInfo, "CSW.oPAC", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1061,7 +1054,7 @@
@Override
public void onConnectionServiceFocusReleased(Session.Info sessionInfo)
throws RemoteException {
- Log.startSession(sessionInfo, "CSW.oCSFR");
+ Log.startSession(sessionInfo, "CSW.oCSFR", mPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1080,11 +1073,12 @@
@Override
public void setConferenceState(String callId, boolean isConference,
Session.Info sessionInfo) throws RemoteException {
- Log.startSession(sessionInfo, "CSW.sCS");
+ Log.startSession(sessionInfo, "CSW.sCS", mPackageAbbreviation);
if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(this, "setConferenceState from caller without permission.");
+ Log.endSession();
return;
}
@@ -1104,6 +1098,35 @@
Log.endSession();
}
}
+
+ @Override
+ public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, "CSW.sCD", mPackageAbbreviation);
+
+ if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.w(this, "setCallDirection from caller without permission.");
+ Log.endSession();
+ return;
+ }
+
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ logIncoming("setCallDirection %s %d", callId, direction);
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.setCallDirection(Call.getRemappedCallDirection(direction));
+ }
+ }
+ } catch (Throwable t) {
+ Log.e(ConnectionServiceWrapper.this, t, "");
+ throw t;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
}
private final Adapter mAdapter = new Adapter();
@@ -1184,6 +1207,10 @@
mPendingResponses.put(callId, response);
Bundle extras = call.getIntentExtras();
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
Log.addEvent(call, LogUtils.Events.START_CONFERENCE,
Log.piiHandle(call.getHandle()));
@@ -1212,7 +1239,7 @@
connectionRequest,
call.shouldAttachToExistingConnection(),
call.isUnknown(),
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConference -- %s", getComponentName());
@@ -1237,7 +1264,7 @@
*/
@VisibleForTesting
public void createConnection(final Call call, final CreateConnectionResponse response) {
- Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
+ Log.i(this, "createConnection(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
@@ -1276,7 +1303,8 @@
}
Log.addEvent(call, LogUtils.Events.START_CONNECTION,
- Log.piiHandle(call.getHandle()));
+ Log.piiHandle(call.getHandle()) + " via:" +
+ getComponentName().getPackageName());
ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
.setAccountHandle(call.getTargetPhoneAccount())
@@ -1300,7 +1328,7 @@
connectionRequest,
call.shouldAttachToExistingConnection(),
call.isUnknown(),
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
@@ -1347,7 +1375,7 @@
callId,
false),
call.isIncoming(),
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
call.disconnect();
} catch (RemoteException e) {
@@ -1393,7 +1421,7 @@
callId,
false),
call.isIncoming(),
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
call.disconnect();
} catch (RemoteException e) {
@@ -1431,7 +1459,9 @@
call.getIntentExtras(),
call.getVideoState(),
callId,
- false), reason, Log.getExternalSession());
+ false),
+ reason,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1459,7 +1489,7 @@
try {
mServiceInterface.handoverComplete(
callId,
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1485,7 +1515,7 @@
if (callId != null && isServiceValid("abort")) {
try {
logOutgoing("abort %s", callId);
- mServiceInterface.abort(callId, Log.getExternalSession());
+ mServiceInterface.abort(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1499,7 +1529,7 @@
if (callId != null && isServiceValid("silence")) {
try {
logOutgoing("silence %s", callId);
- mServiceInterface.silence(callId, Log.getExternalSession());
+ mServiceInterface.silence(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1511,7 +1541,7 @@
if (callId != null && isServiceValid("hold")) {
try {
logOutgoing("hold %s", callId);
- mServiceInterface.hold(callId, Log.getExternalSession());
+ mServiceInterface.hold(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1523,7 +1553,7 @@
if (callId != null && isServiceValid("unhold")) {
try {
logOutgoing("unhold %s", callId);
- mServiceInterface.unhold(callId, Log.getExternalSession());
+ mServiceInterface.unhold(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1537,7 +1567,7 @@
try {
logOutgoing("onCallAudioStateChanged %s %s", callId, audioState);
mServiceInterface.onCallAudioStateChanged(callId, audioState,
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1549,7 +1579,7 @@
if (callId != null && isServiceValid("disconnect")) {
try {
logOutgoing("disconnect %s", callId);
- mServiceInterface.disconnect(callId, Log.getExternalSession());
+ mServiceInterface.disconnect(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1562,9 +1592,10 @@
try {
logOutgoing("answer %s %d", callId, videoState);
if (VideoProfile.isAudioOnly(videoState)) {
- mServiceInterface.answer(callId, Log.getExternalSession());
+ mServiceInterface.answer(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} else {
- mServiceInterface.answerVideo(callId, videoState, Log.getExternalSession());
+ mServiceInterface.answerVideo(callId, videoState,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
}
} catch (RemoteException e) {
}
@@ -1577,7 +1608,8 @@
if (callId != null && isServiceValid("deflect")) {
try {
logOutgoing("deflect %s", callId);
- mServiceInterface.deflect(callId, address, Log.getExternalSession());
+ mServiceInterface.deflect(callId, address,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1592,9 +1624,10 @@
if (rejectWithMessage && call.can(
Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
- mServiceInterface.rejectWithMessage(callId, message, Log.getExternalSession());
+ mServiceInterface.rejectWithMessage(callId, message,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} else {
- mServiceInterface.reject(callId, Log.getExternalSession());
+ mServiceInterface.reject(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
}
} catch (RemoteException e) {
}
@@ -1608,7 +1641,8 @@
try {
logOutgoing("rejectReason %s, %d", callId, rejectReason);
- mServiceInterface.rejectWithReason(callId, rejectReason, Log.getExternalSession());
+ mServiceInterface.rejectWithReason(callId, rejectReason,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1621,7 +1655,7 @@
try {
logOutgoing("transfer %s", callId);
mServiceInterface.transfer(callId, number, isConfirmationRequired,
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1635,7 +1669,7 @@
try {
logOutgoing("consultativeTransfer %s", callId);
mServiceInterface.consultativeTransfer(callId, otherCallId,
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1647,7 +1681,8 @@
if (callId != null && isServiceValid("playDtmfTone")) {
try {
logOutgoing("playDtmfTone %s %c", callId, digit);
- mServiceInterface.playDtmfTone(callId, digit, Log.getExternalSession());
+ mServiceInterface.playDtmfTone(callId, digit,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1659,7 +1694,8 @@
if (callId != null && isServiceValid("stopDtmfTone")) {
try {
logOutgoing("stopDtmfTone %s", callId);
- mServiceInterface.stopDtmfTone(callId, Log.getExternalSession());
+ mServiceInterface.stopDtmfTone(callId,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
}
}
@@ -1706,7 +1742,8 @@
if (callId != null && isServiceValid("onPostDialContinue")) {
try {
logOutgoing("onPostDialContinue %s %b", callId, proceed);
- mServiceInterface.onPostDialContinue(callId, proceed, Log.getExternalSession());
+ mServiceInterface.onPostDialContinue(callId, proceed,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1718,7 +1755,8 @@
if (callId != null && otherCallId != null && isServiceValid("conference")) {
try {
logOutgoing("conference %s %s", callId, otherCallId);
- mServiceInterface.conference(callId, otherCallId, Log.getExternalSession());
+ mServiceInterface.conference(callId, otherCallId,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1729,7 +1767,8 @@
if (callId != null && isServiceValid("splitFromConference")) {
try {
logOutgoing("splitFromConference %s", callId);
- mServiceInterface.splitFromConference(callId, Log.getExternalSession());
+ mServiceInterface.splitFromConference(callId,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1740,7 +1779,8 @@
if (callId != null && isServiceValid("mergeConference")) {
try {
logOutgoing("mergeConference %s", callId);
- mServiceInterface.mergeConference(callId, Log.getExternalSession());
+ mServiceInterface.mergeConference(callId,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1751,7 +1791,8 @@
if (callId != null && isServiceValid("swapConference")) {
try {
logOutgoing("swapConference %s", callId);
- mServiceInterface.swapConference(callId, Log.getExternalSession());
+ mServiceInterface.swapConference(callId,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1763,7 +1804,7 @@
try {
logOutgoing("addConferenceParticipants %s", callId);
mServiceInterface.addConferenceParticipants(callId, participants,
- Log.getExternalSession());
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1775,7 +1816,8 @@
if (callId != null && isServiceValid("pullExternalCall")) {
try {
logOutgoing("pullExternalCall %s", callId);
- mServiceInterface.pullExternalCall(callId, Log.getExternalSession());
+ mServiceInterface.pullExternalCall(callId,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1786,7 +1828,8 @@
if (callId != null && isServiceValid("sendCallEvent")) {
try {
logOutgoing("sendCallEvent %s %s", callId, event);
- mServiceInterface.sendCallEvent(callId, event, extras, Log.getExternalSession());
+ mServiceInterface.sendCallEvent(callId, event, extras,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1797,7 +1840,8 @@
if (callId != null && isServiceValid("onExtrasChanged")) {
try {
logOutgoing("onExtrasChanged %s %s", callId, extras);
- mServiceInterface.onExtrasChanged(callId, extras, Log.getExternalSession());
+ mServiceInterface.onExtrasChanged(callId, extras,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1808,7 +1852,8 @@
if (callId != null && isServiceValid("startRtt")) {
try {
logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall);
- mServiceInterface.startRtt(callId, fromInCall, toInCall, Log.getExternalSession());
+ mServiceInterface.startRtt(callId, fromInCall, toInCall,
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1819,7 +1864,7 @@
if (callId != null && isServiceValid("stopRtt")) {
try {
logOutgoing("stopRtt: %s", callId);
- mServiceInterface.stopRtt(callId, Log.getExternalSession());
+ mServiceInterface.stopRtt(callId, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1832,7 +1877,7 @@
try {
logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall);
mServiceInterface.respondToRttUpgradeRequest(
- callId, fromInCall, toInCall, Log.getExternalSession());
+ callId, fromInCall, toInCall, Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
}
}
@@ -1871,7 +1916,8 @@
@Override
public void onSuccess() {
try {
- mServiceInterface.connectionServiceFocusLost(Log.getExternalSession());
+ mServiceInterface.connectionServiceFocusLost(
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
Log.d(this, "failed to inform the focus lost event");
}
@@ -1889,7 +1935,8 @@
@Override
public void onSuccess() {
try {
- mServiceInterface.connectionServiceFocusGained(Log.getExternalSession());
+ mServiceInterface.connectionServiceFocusGained(
+ Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException ignored) {
Log.d(this, "failed to inform the focus gained event");
}
@@ -1918,6 +1965,11 @@
// A connection that begins in the DISCONNECTED state is an indication of
// failure to connect; we handle all failures uniformly
Call foundCall = mCallIdMapper.getCall(callId);
+
+ if (connection.getConnectTimeMillis() != 0) {
+ foundCall.setConnectTimeMillis(connection.getConnectTimeMillis());
+ }
+
if (foundCall != null) {
// The post-dial digits are created when the call is first created. Normally
// the ConnectionService is responsible for stripping them from the address, but
@@ -1976,12 +2028,14 @@
}
private void logIncoming(String msg, Object... params) {
- Log.d(this, "ConnectionService -> Telecom[" + mComponentName.flattenToShortString() + "]: "
+ // Keep these as debug; the incoming logging is traced on a package level through the
+ // session logging.
+ Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: "
+ msg, params);
}
private void logOutgoing(String msg, Object... params) {
- Log.d(this, "Telecom -> ConnectionService[" + mComponentName.flattenToShortString() + "]: "
+ Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: "
+ msg, params);
}
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index bfd625f..2e67b08 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -17,6 +17,7 @@
package com.android.server.telecom;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.telecom.DisconnectCause;
import android.telecom.Log;
import android.telecom.ParcelableConference;
@@ -388,7 +389,8 @@
List<PhoneAccount> allAccounts = mPhoneAccountRegistrar
.getAllPhoneAccountsOfCurrentUser();
- if (allAccounts.isEmpty()) {
+ if (allAccounts.isEmpty() && mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY)) {
// If the list of phone accounts is empty at this point, it means Telephony hasn't
// registered any phone accounts yet. Add a fallback emergency phone account so
// that emergency calls can still go through. We create a new ArrayLists here just
@@ -401,6 +403,7 @@
// When testing emergency calls, we want the calls to go through to the test connection
// service, not the telephony ConnectionService.
if (mCall.isTestEmergencyCall()) {
+ Log.i(this, "Processing test emergency call -- special rules");
allAccounts = mPhoneAccountRegistrar.filterRestrictedPhoneAccounts(allAccounts);
}
@@ -409,7 +412,7 @@
preferredPAH);
// Next, add all SIM phone accounts which can place emergency calls.
sortSimPhoneAccountsForEmergency(allAccounts, preferredPA);
- // and pick the fist one that can place emergency calls.
+ // and pick the first one that can place emergency calls.
for (PhoneAccount phoneAccount : allAccounts) {
if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
&& phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
@@ -436,7 +439,10 @@
mPhoneAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
mCall.getHandle() == null
? null : mCall.getHandle().getScheme()));
- if (!mAttemptRecords.contains(callAttemptRecord)) {
+ // If the target phone account is null, we'll run into a NPE during the retry
+ // process, so skip it now if it's null.
+ if (callAttemptRecord.targetPhoneAccount != null
+ && !mAttemptRecords.contains(callAttemptRecord)) {
Log.i(this, "Will try Connection Manager account %s for emergency",
callManager);
mAttemptRecords.add(callAttemptRecord);
diff --git a/src/com/android/server/telecom/CreateConnectionTimeout.java b/src/com/android/server/telecom/CreateConnectionTimeout.java
index 399c28a..14e5bf0 100644
--- a/src/com/android/server/telecom/CreateConnectionTimeout.java
+++ b/src/com/android/server/telecom/CreateConnectionTimeout.java
@@ -69,7 +69,7 @@
}
// Timeout is only supported for SIM call managers that are set by the carrier.
- if (!Objects.equals(connectionManager.getComponentName(),
+ if (connectionManager != null && !Objects.equals(connectionManager.getComponentName(),
mPhoneAccountRegistrar.getSystemSimCallManagerComponent())) {
Log.d(this, "isTimeoutNeededForCall, not a system sim call manager");
return false;
diff --git a/src/com/android/server/telecom/DefaultDialerCache.java b/src/com/android/server/telecom/DefaultDialerCache.java
index c2b78ee..a4a0242 100644
--- a/src/com/android/server/telecom/DefaultDialerCache.java
+++ b/src/com/android/server/telecom/DefaultDialerCache.java
@@ -217,6 +217,12 @@
return mSystemDialerComponentName;
}
+ public ComponentName getDialtactsSystemDialerComponent() {
+ final Resources resources = mContext.getResources();
+ return new ComponentName(getSystemDialerApplication(),
+ resources.getString(R.string.dialer_default_class));
+ }
+
public void observeDefaultDialerApplication(Executor executor, IntConsumer observer) {
mRoleManagerAdapter.observeDefaultDialerApp(executor, observer);
}
@@ -289,4 +295,8 @@
public ContentObserver getContentObserver() {
return mDefaultDialerObserver;
}
+
+ public RoleManagerAdapter getRoleManagerAdapter() {
+ return mRoleManagerAdapter;
+ }
}
\ No newline at end of file
diff --git a/src/com/android/server/telecom/DeviceIdleControllerAdapter.java b/src/com/android/server/telecom/DeviceIdleControllerAdapter.java
new file mode 100644
index 0000000..d3a798a
--- /dev/null
+++ b/src/com/android/server/telecom/DeviceIdleControllerAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.PowerWhitelistManager;
+import android.os.RemoteException;
+import android.telecom.Log;
+
+import com.android.internal.telecom.IDeviceIdleControllerAdapter;
+
+/**
+ * Telecom is in the same process as the {@link PowerWhitelistManager}, so we can not make direct
+ * calls to the manager interface, since they will fail in the DeviceIdleController
+ * (see {@link Context#enforceCallingPermission(String, String)}). Instead, we must access it
+ * through SystemService#getLocalService, which is only accessible to the Telecom
+ * core loader service (TelecomLoaderService). Unfortunately, due to the architecture, this means
+ * we must use a Binder to allow services such as this to be accessible.
+ */
+public class DeviceIdleControllerAdapter {
+
+ private static final String TAG = "DeviceIdleControllerAdapter";
+
+ private final IDeviceIdleControllerAdapter mAdapter;
+
+ public DeviceIdleControllerAdapter(IDeviceIdleControllerAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Exempts an application from power restrictions for the duration specified. See
+ * DeviceIdleController for more information on how this works.
+ */
+ public void exemptAppTemporarilyForEvent(@NonNull String packageName, long duration,
+ int userHandle, @NonNull String reason) {
+ try {
+ mAdapter.exemptAppTemporarilyForEvent(packageName, duration, userHandle, reason);
+ } catch (RemoteException e) {
+ Log.w(TAG, "exemptAppTemporarilyForEvent e=" + e.getMessage());
+ }
+ }
+}
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index d25665f..0fda5f8 100755
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -36,6 +36,7 @@
private final CallIdMapper mCallIdMapper;
private final TelecomSystem.SyncRoot mLock;
private final String mOwnerPackageName;
+ private final String mOwnerPackageAbbreviation;
/** Persists the specified parameters. */
public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper,
@@ -44,12 +45,13 @@
mCallIdMapper = callIdMapper;
mLock = lock;
mOwnerPackageName = ownerPackageName;
+ mOwnerPackageAbbreviation = Log.getPackageAbbreviation(ownerPackageName);
}
@Override
public void answerCall(String callId, int videoState) {
try {
- Log.startSession(LogUtils.Sessions.ICA_ANSWER_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_ANSWER_CALL, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -72,7 +74,7 @@
@Override
public void deflectCall(String callId, Uri address) {
try {
- Log.startSession(LogUtils.Sessions.ICA_DEFLECT_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_DEFLECT_CALL, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -95,7 +97,7 @@
@Override
public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
try {
- Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageAbbreviation);
int callingUid = Binder.getCallingUid();
long token = Binder.clearCallingIdentity();
@@ -129,7 +131,7 @@
public void rejectCallWithReason(String callId,
@android.telecom.Call.RejectReason int rejectReason) {
try {
- Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageAbbreviation);
int callingUid = Binder.getCallingUid();
long token = Binder.clearCallingIdentity();
@@ -153,7 +155,7 @@
public void transferCall(String callId, Uri targetNumber, boolean isConfirmationRequired) {
try {
- Log.startSession(LogUtils.Sessions.ICA_TRANSFER_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_TRANSFER_CALL, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -177,7 +179,8 @@
@Override
public void consultativeTransfer(String callId, String otherCallId) {
try {
- Log.startSession(LogUtils.Sessions.ICA_CONSULTATIVE_TRANSFER, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_CONSULTATIVE_TRANSFER,
+ mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -202,7 +205,7 @@
@Override
public void playDtmfTone(String callId, char digit) {
try {
- Log.startSession("ICA.pDT", mOwnerPackageName);
+ Log.startSession("ICA.pDT", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -225,7 +228,7 @@
@Override
public void stopDtmfTone(String callId) {
try {
- Log.startSession("ICA.sDT", mOwnerPackageName);
+ Log.startSession("ICA.sDT", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -248,7 +251,7 @@
@Override
public void postDialContinue(String callId, boolean proceed) {
try {
- Log.startSession("ICA.pDC", mOwnerPackageName);
+ Log.startSession("ICA.pDC", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -271,7 +274,7 @@
@Override
public void disconnectCall(String callId) {
try {
- Log.startSession(LogUtils.Sessions.ICA_DISCONNECT_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_DISCONNECT_CALL, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -294,7 +297,7 @@
@Override
public void holdCall(String callId) {
try {
- Log.startSession(LogUtils.Sessions.ICA_HOLD_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_HOLD_CALL, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -316,7 +319,7 @@
@Override
public void unholdCall(String callId) {
try {
- Log.startSession(LogUtils.Sessions.ICA_UNHOLD_CALL, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_UNHOLD_CALL, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -339,7 +342,7 @@
public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
boolean setDefault) {
try {
- Log.startSession("ICA.pAS", mOwnerPackageName);
+ Log.startSession("ICA.pAS", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -361,7 +364,7 @@
@Override
public void mute(boolean shouldMute) {
try {
- Log.startSession(LogUtils.Sessions.ICA_MUTE, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_MUTE, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -378,7 +381,7 @@
@Override
public void setAudioRoute(int route, String bluetoothAddress) {
try {
- Log.startSession(LogUtils.Sessions.ICA_SET_AUDIO_ROUTE, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_SET_AUDIO_ROUTE, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -395,7 +398,8 @@
@Override
public void enterBackgroundAudioProcessing(String callId) {
try {
- Log.startSession(LogUtils.Sessions.ICA_ENTER_AUDIO_PROCESSING, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_ENTER_AUDIO_PROCESSING,
+ mOwnerPackageAbbreviation);
// TODO: enforce the extra permission.
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
@@ -415,7 +419,8 @@
@Override
public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) {
try {
- Log.startSession(LogUtils.Sessions.ICA_EXIT_AUDIO_PROCESSING, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_EXIT_AUDIO_PROCESSING,
+ mOwnerPackageAbbreviation);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
Call call = mCallIdMapper.getCall(callId);
@@ -435,7 +440,7 @@
@Override
public void conference(String callId, String otherCallId) {
try {
- Log.startSession(LogUtils.Sessions.ICA_CONFERENCE, mOwnerPackageName);
+ Log.startSession(LogUtils.Sessions.ICA_CONFERENCE, mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -458,7 +463,7 @@
@Override
public void splitFromConference(String callId) {
try {
- Log.startSession("ICA.sFC", mOwnerPackageName);
+ Log.startSession("ICA.sFC", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -480,7 +485,7 @@
@Override
public void mergeConference(String callId) {
try {
- Log.startSession("ICA.mC", mOwnerPackageName);
+ Log.startSession("ICA.mC", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -502,7 +507,7 @@
@Override
public void swapConference(String callId) {
try {
- Log.startSession("ICA.sC", mOwnerPackageName);
+ Log.startSession("ICA.sC", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -524,7 +529,7 @@
@Override
public void addConferenceParticipants(String callId, List<Uri> participants) {
try {
- Log.startSession("ICA.aCP", mOwnerPackageName);
+ Log.startSession("ICA.aCP", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -547,7 +552,7 @@
@Override
public void pullExternalCall(String callId) {
try {
- Log.startSession("ICA.pEC", mOwnerPackageName);
+ Log.startSession("ICA.pEC", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -569,7 +574,7 @@
@Override
public void sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras) {
try {
- Log.startSession("ICA.sCE", mOwnerPackageName);
+ Log.startSession("ICA.sCE", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -591,7 +596,7 @@
@Override
public void putExtras(String callId, Bundle extras) {
try {
- Log.startSession("ICA.pE", mOwnerPackageName);
+ Log.startSession("ICA.pE", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -613,7 +618,7 @@
@Override
public void removeExtras(String callId, List<String> keys) {
try {
- Log.startSession("ICA.rE", mOwnerPackageName);
+ Log.startSession("ICA.rE", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -635,7 +640,7 @@
@Override
public void turnOnProximitySensor() {
try {
- Log.startSession("ICA.tOnPS", mOwnerPackageName);
+ Log.startSession("ICA.tOnPS", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -652,7 +657,7 @@
@Override
public void turnOffProximitySensor(boolean screenOnImmediately) {
try {
- Log.startSession("ICA.tOffPS", mOwnerPackageName);
+ Log.startSession("ICA.tOffPS", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -753,7 +758,7 @@
public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
Bundle extras) {
try {
- Log.startSession("ICA.hT", mOwnerPackageName);
+ Log.startSession("ICA.hT", mOwnerPackageAbbreviation);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 171bdf3..954aa44 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -16,15 +16,20 @@
package com.android.server.telecom;
+import static android.os.Process.myUid;
+
import android.Manifest;
import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.PermissionChecker;
import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -44,6 +49,7 @@
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
// TODO: Needed for move to system service: import com.android.internal.R;
@@ -59,6 +65,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -195,7 +202,7 @@
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- Log.startSession("ICSBC.oSC");
+ Log.startSession("ICSBC.oSC", Log.getPackageAbbreviation(name));
synchronized (mLock) {
try {
Log.d(this, "onServiceConnected: %s %b %b", name, mIsBound, mIsConnected);
@@ -212,10 +219,10 @@
@Override
public void onServiceDisconnected(ComponentName name) {
- Log.startSession("ICSBC.oSD");
+ Log.startSession("ICSBC.oSD", Log.getPackageAbbreviation(name));
synchronized (mLock) {
try {
- Log.d(this, "onDisconnected: %s", name);
+ Log.d(this, "onServiceDisconnected: %s", name);
mIsBound = false;
onDisconnected();
} finally {
@@ -226,7 +233,7 @@
@Override
public void onNullBinding(ComponentName name) {
- Log.startSession("ICSBC.oNB");
+ Log.startSession("ICSBC.oNB", Log.getPackageAbbreviation(name));
synchronized (mLock) {
try {
Log.d(this, "onNullBinding: %s", name);
@@ -241,7 +248,7 @@
@Override
public void onBindingDied(ComponentName name) {
- Log.startSession("ICSBC.oBD");
+ Log.startSession("ICSBC.oBD", Log.getPackageAbbreviation(name));
synchronized (mLock) {
try {
Log.d(this, "onBindingDied: %s", name);
@@ -323,7 +330,10 @@
String packageName = mInCallServiceInfo.getComponentName().getPackageName();
mContext.unbindService(mServiceConnection);
mIsConnected = false;
- if (mIsNullBinding) {
+ if (mIsNullBinding && mInCallServiceInfo.getType() != IN_CALL_SERVICE_TYPE_NON_UI) {
+ // Non-UI InCallServices are allowed to return null from onBind if they don't
+ // want to handle calls at the moment, so don't report them to the user as
+ // crashed.
sendCrashedInCallServiceNotification(packageName);
}
if (mCall != null) {
@@ -333,6 +343,8 @@
mInCallServiceInfo.getDisconnectTime()
- mInCallServiceInfo.getBindingStartTime(), mIsNullBinding);
}
+
+ InCallController.this.onDisconnected(mInCallServiceInfo);
} else {
Log.i(InCallController.this, "ICSBC#disconnect: already disconnected; %s",
mInCallServiceInfo);
@@ -445,7 +457,7 @@
@Override
public void disconnect() {
- Log.i(this, "Disconnect forced!");
+ Log.i(this, "Disconnecting from InCallService");
if (mIsProxying) {
mSubConnection.disconnect();
} else {
@@ -478,7 +490,7 @@
super.onDisconnected();
// We just disconnected. Check if we are expected to be connected, and reconnect.
if (shouldReconnect && !mIsProxying) {
- connect(null); // reconnect
+ connect(mCall); // reconnect
}
}
@@ -543,9 +555,9 @@
if (newConnection != mCurrentConnection) {
if (mIsConnected) {
mCurrentConnection.disconnect();
- int result = newConnection.connect(null);
- mIsConnected = result == CONNECTION_SUCCEEDED;
}
+ int result = newConnection.connect(null);
+ mIsConnected = result == CONNECTION_SUCCEEDED;
mCurrentConnection = newConnection;
}
}
@@ -722,6 +734,20 @@
}
pw.decreaseIndent();
}
+
+ public void addConnections(List<InCallServiceBindingConnection> newConnections) {
+ // connect() needs to be called with a Call object. Since we're in the middle of any
+ // possible number of calls right now, choose an arbitrary one from the ones that
+ // InCallController is tracking.
+ if (mCallIdMapper.getCalls().isEmpty()) {
+ Log.w(InCallController.this, "No calls tracked while adding new NonUi incall");
+ return;
+ }
+ Call callToConnectWith = mCallIdMapper.getCalls().iterator().next();
+ for (InCallServiceBindingConnection newConnection : newConnections) {
+ newConnection.connect(callToConnectWith);
+ }
+ }
}
private final Call.Listener mCallListener = new Call.ListenerBase() {
@@ -802,6 +828,11 @@
}
@Override
+ public void onCallDirectionChanged(Call call) {
+ updateCall(call);
+ }
+
+ @Override
public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
updateCall(call);
}
@@ -843,9 +874,50 @@
}
};
- private final SystemStateListener mSystemStateListener =
- (priority, packageName, isCarMode) -> InCallController.this.handleCarModeChange(
- priority, packageName, isCarMode);
+ private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.startSession("ICC.pCR");
+ try {
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
+ synchronized (mLock) {
+ String changedPackage = intent.getData().getSchemeSpecificPart();
+ List<InCallServiceBindingConnection> componentsToBind =
+ Arrays.stream(intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST))
+ .map((className) ->
+ ComponentName.createRelative(changedPackage,
+ className))
+ .filter(mKnownNonUiInCallServices::contains)
+ .flatMap(componentName -> getInCallServiceComponents(
+ componentName,
+ IN_CALL_SERVICE_TYPE_NON_UI).stream())
+ .map(InCallServiceBindingConnection::new)
+ .collect(Collectors.toList());
+
+ if (mNonUIInCallServiceConnections != null) {
+ mNonUIInCallServiceConnections.addConnections(componentsToBind);
+ }
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+ };
+
+ private final SystemStateListener mSystemStateListener = new SystemStateListener() {
+ @Override
+ public void onCarModeChanged(int priority, String packageName, boolean isCarMode) {
+ InCallController.this.handleCarModeChange(priority, packageName, isCarMode);
+ }
+
+ @Override
+ public void onPackageUninstalled(String packageName) {
+ mCarModeTracker.forceExitCarMode(packageName);
+ updateCarModeForSwitchingConnection();
+ }
+ };
private static final int IN_CALL_SERVICE_TYPE_INVALID = 0;
private static final int IN_CALL_SERVICE_TYPE_DIALER_UI = 1;
@@ -860,6 +932,7 @@
private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getId);
private final Context mContext;
+ private final AppOpsManager mAppOpsManager;
private final TelecomSystem.SyncRoot mLock;
private final CallsManager mCallsManager;
private final SystemStateHelper mSystemStateHelper;
@@ -871,18 +944,35 @@
private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
private final ClockProxy mClockProxy;
+ // 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
+ // component has been enabled.
+ private Set<ComponentName> mKnownNonUiInCallServices = new ArraySet<>();
+
// Future that's in a completed state unless we're in the middle of binding to a service.
// The future will complete with true if binding succeeds, false if it timed out.
private CompletableFuture<Boolean> mBindingFuture = CompletableFuture.completedFuture(true);
private final CarModeTracker mCarModeTracker;
+ /**
+ * The package name of the app which is showing the calling UX.
+ */
+ private String mCurrentUserInterfacePackageName = null;
+
+ /**
+ * {@code true} if InCallController is tracking a managed, not external call which is using the
+ * microphone, {@code false} otherwise.
+ */
+ private boolean mIsCallUsingMicrophone = false;
+
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);
mLock = lock;
mCallsManager = callsManager;
mSystemStateHelper = systemStateHelper;
@@ -936,7 +1026,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_SYSTEM_UI ||
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
try {
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
@@ -968,6 +1059,7 @@
}
call.removeListener(mCallListener);
mCallIdMapper.removeCall(call);
+ maybeTrackMicrophoneUse(isMuted());
}
@Override
@@ -1000,7 +1092,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_SYSTEM_UI ||
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
try {
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
@@ -1011,7 +1104,7 @@
// The call was regular but it is now external. We must now remove it from any
// InCallServices which do not support external calls.
// Remove the call by sending a call update indicating the call was disconnected.
- Log.i(this, "Removing external call %", call);
+ Log.i(this, "Removing external call %s", call);
for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
InCallServiceInfo info = entry.getKey();
if (info.isExternalCallsSupported()) {
@@ -1030,7 +1123,8 @@
false /* supportsExternalCalls */,
android.telecom.Call.STATE_DISCONNECTED /* overrideState */,
false /* includeRttCall */,
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI
);
try {
@@ -1041,10 +1135,12 @@
}
Log.i(this, "External call removed from components: %s", componentsUpdated);
}
+ maybeTrackMicrophoneUse(isMuted());
}
@Override
public void onCallStateChanged(Call call, int oldState, int newState) {
+ maybeTrackMicrophoneUse(isMuted());
updateCall(call);
}
@@ -1062,6 +1158,7 @@
if (!mInCallServices.isEmpty()) {
Log.i(this, "Calling onAudioStateChanged, audioState: %s -> %s", oldCallAudioState,
newCallAudioState);
+ maybeTrackMicrophoneUse(newCallAudioState.isMuted());
for (IInCallService inCallService : mInCallServices.values()) {
try {
inCallService.onCallAudioStateChanged(newCallAudioState);
@@ -1126,6 +1223,23 @@
updateCall(call);
}
+ /**
+ * Track changes to camera usage for a 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) {
+ 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);
+ } else {
+ mAppOpsManager.finishOp(AppOpsManager.OP_PHONE_CALL_CAMERA, myUid(),
+ mContext.getOpPackageName(), null);
+ }
+ }
+
void bringToForeground(boolean showDialpad) {
if (!mInCallServices.isEmpty()) {
for (IInCallService inCallService : mInCallServices.values()) {
@@ -1223,6 +1337,12 @@
* Unbinds an existing bound connection to the in-call app.
*/
private void unbindFromServices() {
+ try {
+ mContext.unregisterReceiver(mPackageChangedReceiver);
+ } catch (IllegalArgumentException e) {
+ // Ignore this -- we may or may not have registered it, but when we bind, we want to
+ // unregister no matter what.
+ }
if (mInCallServiceConnection != null) {
mInCallServiceConnection.disconnect();
mInCallServiceConnection = null;
@@ -1308,6 +1428,10 @@
}
mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls);
mNonUIInCallServiceConnections.connect(call);
+
+ IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
+ packageChangedFilter.addDataScheme("package");
+ mContext.registerReceiver(mPackageChangedReceiver, packageChangedFilter);
}
private InCallServiceInfo getDefaultDialerComponent() {
@@ -1320,10 +1444,12 @@
(systemPackageName != null && systemPackageName.equals(packageName))
? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI)
: getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI);
- if (packageName != null && defaultDialerComponent == null) {
- // The in call service of default phone app is disabled, send notification.
- sendCrashedInCallServiceNotification(packageName);
- }
+ /* 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.
+ sendCrashedInCallServiceNotification(packageName);
+ }
+ */
return defaultDialerComponent;
}
@@ -1381,7 +1507,7 @@
PackageManager packageManager = mContext.getPackageManager();
for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
serviceIntent,
- PackageManager.GET_META_DATA,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
mCallsManager.getCurrentUserHandle().getIdentifier())) {
ServiceInfo serviceInfo = entry.serviceInfo;
if (serviceInfo != null) {
@@ -1394,14 +1520,13 @@
int currentType = getInCallServiceType(entry.serviceInfo, packageManager,
packageName);
- if (requestedType == 0 || requestedType == currentType) {
- if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
- // We enforce the rule that self-managed calls are not supported by non-ui
- // InCallServices.
- isSelfManageCallsSupported = false;
- }
- retval.add(new InCallServiceInfo(
- new ComponentName(serviceInfo.packageName, serviceInfo.name),
+ ComponentName foundComponentName =
+ new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
+ mKnownNonUiInCallServices.add(foundComponentName);
+ }
+ if (serviceInfo.enabled && (requestedType == 0 || requestedType == currentType)) {
+ retval.add(new InCallServiceInfo(foundComponentName,
isExternalCallsSupported, isSelfManageCallsSupported, requestedType));
}
}
@@ -1452,9 +1577,17 @@
p -> packageManager.checkPermission(
Manifest.permission.CONTROL_INCALL_EXPERIENCE,
p) == PackageManager.PERMISSION_GRANTED);
+
+ boolean hasAppOpsPermittedManageOngoingCalls = false;
+ if (isAppOpsPermittedManageOngoingCalls(serviceInfo.applicationInfo.uid,
+ serviceInfo.packageName)) {
+ hasAppOpsPermittedManageOngoingCalls = true;
+ }
+
boolean isCarModeUIService = serviceInfo.metaData != null &&
serviceInfo.metaData.getBoolean(
TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI, false);
+
if (isCarModeUIService && hasControlInCallPermission) {
return IN_CALL_SERVICE_TYPE_CAR_MODE_UI;
}
@@ -1469,7 +1602,8 @@
// Also allow any in-call service that has the control-experience permission (to ensure
// that it is a system app) and doesn't claim to show any UI.
- if (!isUIService && !isCarModeUIService && hasControlInCallPermission) {
+ if (!isUIService && !isCarModeUIService && (hasControlInCallPermission ||
+ hasAppOpsPermittedManageOngoingCalls)) {
return IN_CALL_SERVICE_TYPE_NON_UI;
}
@@ -1498,9 +1632,13 @@
* @return True if we successfully connected.
*/
private boolean onConnected(InCallServiceInfo info, IBinder service) {
- Trace.beginSection("onConnected: " + info.getComponentName());
Log.i(this, "onConnected to %s", info.getComponentName());
+ if (info.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
+ || info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
+ || info.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) {
+ trackCallingUserInterfaceStarted(info);
+ }
IInCallService inCallService = IInCallService.Stub.asInterface(service);
mInCallServices.put(info, inCallService);
@@ -1541,7 +1679,8 @@
mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported(),
includeRttCall,
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
}
@@ -1551,9 +1690,12 @@
inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
} catch (RemoteException ignored) {
}
- mBindingFuture.complete(true);
+ // Don't complete the binding future for non-ui incalls
+ if (info.getType() != IN_CALL_SERVICE_TYPE_NON_UI) {
+ mBindingFuture.complete(true);
+ }
+
Log.i(this, "%s calls sent to InCallService.", numCallsSent);
- Trace.endSection();
return true;
}
@@ -1564,7 +1706,11 @@
*/
private void onDisconnected(InCallServiceInfo disconnectedInfo) {
Log.i(this, "onDisconnected from %s", disconnectedInfo.getComponentName());
-
+ if (disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
+ || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
+ || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) {
+ trackCallingUserInterfaceStopped(disconnectedInfo);
+ }
mInCallServices.remove(disconnectedInfo);
}
@@ -1606,7 +1752,8 @@
mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported(),
rttInfoChanged && info.equals(mInCallServiceConnection.getInfo()),
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+ info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
ComponentName componentName = info.getComponentName();
IInCallService inCallService = entry.getValue();
componentsUpdated.add(componentName);
@@ -1630,6 +1777,7 @@
mCallIdMapper.addCall(call);
call.addListener(mCallListener);
}
+ maybeTrackMicrophoneUse(isMuted());
}
/**
@@ -1697,7 +1845,7 @@
if (TextUtils.isEmpty(ringingPackage)) {
// The current in-call UI returned nothing, so lets use the default dialer.
- ringingPackage = mDefaultDialerCache.getDefaultDialerApplication(
+ ringingPackage = mDefaultDialerCache.getRoleManagerAdapter().getDefaultDialerApp(
mCallsManager.getCurrentUserHandle().getIdentifier());
if (ringingPackage != null) {
Log.d(this, "doesConnectedDialerSupportRinging: notCurentlyConnectedPackage=%s",
@@ -1780,7 +1928,8 @@
public void handleCarModeChange(int priority, String packageName, boolean isCarMode) {
Log.i(this, "handleCarModeChange: packageName=%s, priority=%d, isCarMode=%b",
packageName, priority, isCarMode);
- if (!isCarModeInCallService(packageName)) {
+ // Don't ignore the signal if we are disabling car mode; package may be uninstalled.
+ if (isCarMode && !isCarModeInCallService(packageName)) {
Log.i(this, "handleCarModeChange: not a valid InCallService; packageName=%s",
packageName);
return;
@@ -1792,8 +1941,12 @@
mCarModeTracker.handleExitCarMode(priority, packageName);
}
+ updateCarModeForSwitchingConnection();
+ }
+
+ public void updateCarModeForSwitchingConnection() {
if (mInCallServiceConnection != null) {
- Log.i(this, "handleCarModeChange: car mode apps: %s",
+ Log.i(this, "updateCarModeForSwitchingConnection: car mode apps: %s",
mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
if (shouldUseCarModeUI()) {
mInCallServiceConnection.changeCarModeApp(
@@ -1804,9 +1957,82 @@
}
}
+ /**
+ * Tracks start of microphone use on binding to the current calling UX.
+ * @param info
+ */
+ private void trackCallingUserInterfaceStarted(InCallServiceInfo info) {
+ String packageName = info.getComponentName().getPackageName();
+ if (!Objects.equals(mCurrentUserInterfacePackageName, packageName)) {
+ Log.i(this, "trackCallingUserInterfaceStarted: %s is now calling UX.", packageName);
+ mCurrentUserInterfacePackageName = packageName;
+ }
+ maybeTrackMicrophoneUse(isMuted());
+ }
+
+ /**
+ * Tracks stop of microphone use on unbind from the current calling UX.
+ * @param info
+ */
+ private void trackCallingUserInterfaceStopped(InCallServiceInfo info) {
+ maybeTrackMicrophoneUse(isMuted());
+ mCurrentUserInterfacePackageName = null;
+ String packageName = info.getComponentName().getPackageName();
+ Log.i(this, "trackCallingUserInterfaceStopped: %s is no longer calling UX", packageName);
+ }
+
+ /**
+ * 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) {
+ if (mIsCallUsingMicrophone) {
+ mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(),
+ mContext.getOpPackageName(), false, null, null);
+ } else {
+ mAppOpsManager.finishOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(),
+ mContext.getOpPackageName(), null);
+ }
+ }
+ }
+
+ /**
+ * @return {@code true} if InCallController is tracking a managed call (i.e. not self managed
+ * and not external) that is active.
+ */
+ 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);
+ }
+
+ /**
+ * @return {@code true} if the audio is currently muted, {@code false} otherwise.
+ */
+ private boolean isMuted() {
+ if (mCallsManager.getAudioState() == null) {
+ return false;
+ }
+ return mCallsManager.getAudioState().isMuted();
+ }
+
+ private boolean isAppOpsPermittedManageOngoingCalls(int uid, String callingPackage) {
+ return PermissionChecker.checkPermissionForPreflight(mContext,
+ Manifest.permission.MANAGE_ONGOING_CALLS, PermissionChecker.PID_UNKNOWN, uid,
+ callingPackage) == PermissionChecker.PERMISSION_GRANTED;
+ }
+
private void sendCrashedInCallServiceNotification(String packageName) {
PackageManager packageManager = mContext.getPackageManager();
CharSequence appName;
+ String systemDialer = mDefaultDialerCache.getSystemDialerApplication();
+ if ((systemDialer != null) && systemDialer.equals(packageName)) {
+ return;
+ }
try {
appName = packageManager.getApplicationLabel(
packageManager.getApplicationInfo(packageName, 0));
@@ -1823,12 +2049,11 @@
builder.setSmallIcon(R.drawable.ic_phone)
.setColor(mContext.getResources().getColor(R.color.theme_color))
.setContentTitle(
- mContext.getText(
- R.string.notification_crashedInCallService_title))
+ mContext.getString(
+ R.string.notification_incallservice_not_responding_title, appName))
.setStyle(new Notification.BigTextStyle()
- .bigText(mContext.getString(
- R.string.notification_crashedInCallService_body,
- appName)));
+ .bigText(mContext.getText(
+ R.string.notification_incallservice_not_responding_body)));
notificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID,
builder.build());
}
diff --git a/src/com/android/server/telecom/InternalServiceRetrieverAdapter.java b/src/com/android/server/telecom/InternalServiceRetrieverAdapter.java
new file mode 100644
index 0000000..4a2c3d1
--- /dev/null
+++ b/src/com/android/server/telecom/InternalServiceRetrieverAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecom.IInternalServiceRetriever;
+
+/**
+ * Contains all services that Telecom must access that are only accessible as a local service as
+ * part of the SYSTEM process.
+ */
+public class InternalServiceRetrieverAdapter {
+
+ private final IInternalServiceRetriever mRetriever;
+
+ public InternalServiceRetrieverAdapter(IInternalServiceRetriever retriever) {
+ mRetriever = retriever;
+ }
+
+ public DeviceIdleControllerAdapter getDeviceIdleController() {
+ try {
+ return new DeviceIdleControllerAdapter(mRetriever.getDeviceIdleController());
+ } catch (RemoteException e) {
+ // This should not happen - if it does, there is a bad configuration as this should
+ // all be local.
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index 280b2a8..e4a414b 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -101,6 +101,8 @@
public static final String SET_DISCONNECTED = "SET_DISCONNECTED";
public static final String SET_DISCONNECTING = "SET_DISCONNECTING";
public static final String SET_SELECT_PHONE_ACCOUNT = "SET_SELECT_PHONE_ACCOUNT";
+ public static final String SET_AUDIO_PROCESSING = "SET_AUDIO_PROCESSING";
+ public static final String SET_SIMULATED_RINGING = "SET_SIMULATED_RINGING";
public static final String REQUEST_HOLD = "REQUEST_HOLD";
public static final String REQUEST_UNHOLD = "REQUEST_UNHOLD";
public static final String REQUEST_DISCONNECT = "REQUEST_DISCONNECT";
@@ -136,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 CALL_DIRECTION_CHANGED = "CALL_DIRECTION_CHANGED";
public static final String MUTE = "MUTE";
public static final String UNMUTE = "UNMUTE";
public static final String AUDIO_ROUTE = "AUDIO_ROUTE";
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index 7f71ad2..86fedd5 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -72,7 +72,7 @@
public static final String EXTRA_GATEWAY_URI = "com.android.phone.extra.GATEWAY_URI";
private final CallsManager mCallsManager;
- private final Call mCall;
+ private Call mCall;
private final Intent mIntent;
private final Context mContext;
private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
@@ -99,12 +99,11 @@
}
@VisibleForTesting
- public NewOutgoingCallIntentBroadcaster(Context context, CallsManager callsManager, Call call,
+ public NewOutgoingCallIntentBroadcaster(Context context, CallsManager callsManager,
Intent intent, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
boolean isDefaultPhoneApp, DefaultDialerCache defaultDialerCache) {
mContext = context;
mCallsManager = callsManager;
- mCall = call;
mIntent = intent;
mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
mIsDefaultOrSystemPhoneApp = isDefaultPhoneApp;
@@ -330,7 +329,8 @@
return number;
}
- public void processCall(CallDisposition disposition) {
+ public void processCall(Call call, CallDisposition disposition) {
+ mCall = call;
if (disposition.callImmediately) {
boolean speakerphoneOn = mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
@@ -494,7 +494,7 @@
private void launchSystemDialer(Uri handle) {
Intent systemDialerIntent = new Intent();
- systemDialerIntent.setComponent(mDefaultDialerCache.getSystemDialerComponent());
+ systemDialerIntent.setComponent(mDefaultDialerCache.getDialtactsSystemDialerComponent());
systemDialerIntent.setAction(Intent.ACTION_DIAL);
systemDialerIntent.setData(handle);
systemDialerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index aae3e36..a5291e7 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -42,9 +42,9 @@
/**
* A list of extra keys which should be removed from a {@link ParcelableCall} when it is being
- * generated for the purpose of sending to a dialer other than the system dialer.
+ * generated for the purpose of sending to a incallservice other than the system incallservice.
* By convention we only pass keys namespaced with android.*, however there are some keys which
- * should not be passed to non-system dialer apps either.
+ * should not be passed to non-system incallservice apps either.
*/
private static List<String> EXTRA_KEYS_TO_SANITIZE;
static {
@@ -90,9 +90,9 @@
* {@link InCallService} which supports external calls or not.
* @param includeRttCall {@code true} if the RTT call should be included, {@code false}
* otherwise.
- * @param isForSystemDialer {@code true} if this call is being parcelled for the system dialer,
- * {@code false} otherwise. When parceling for the system dialer, the entire call extras
- * is included. When parceling for anything other than the system dialer, some extra key
+ * @param isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice,
+ * {@code false} otherwise. When parceling for the system incallservice, the entire call extras
+ * is included. When parceling for anything other than the system incallservice, some extra key
* values will be stripped for privacy sake.
*/
public static ParcelableCall toParcelableCall(
@@ -101,10 +101,10 @@
PhoneAccountRegistrar phoneAccountRegistrar,
boolean supportsExternalCalls,
boolean includeRttCall,
- boolean isForSystemDialer) {
+ boolean isForSystemInCallService) {
return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */,
- includeRttCall, isForSystemDialer);
+ includeRttCall, isForSystemInCallService);
}
/**
@@ -120,9 +120,9 @@
* {@link InCallService} which supports external calls or not.
* @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
* override to whatever is defined in the call.
- * @param isForSystemDialer {@code true} if this call is being parcelled for the system dialer,
- * {@code false} otherwise. When parceling for the system dialer, the entire call extras
- * is included. When parceling for anything other than the system dialer, some extra key
+ * @param isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice,
+ * {@code false} otherwise. When parceling for the system incallservice, the entire call extras
+ * is included. When parceling for anything other than the system incallservice, some extra key
* values will be stripped for privacy sake.
* @return The {@link ParcelableCall} containing all call information from the {@link Call}.
*/
@@ -133,7 +133,7 @@
boolean supportsExternalCalls,
int overrideState,
boolean includeRttCall,
- boolean isForSystemDialer) {
+ boolean isForSystemInCallService) {
int state;
if (overrideState == CALL_STATE_OVERRIDE_NONE) {
state = getParcelableState(call, supportsExternalCalls);
@@ -181,22 +181,12 @@
parentCallId = parentCall.getId();
}
- long connectTimeMillis = call.getConnectTimeMillis();
List<Call> childCalls = call.getChildCalls();
List<String> childCallIds = new ArrayList<>();
if (!childCalls.isEmpty()) {
- long childConnectTimeMillis = Long.MAX_VALUE;
for (Call child : childCalls) {
- if (child.getConnectTimeMillis() > 0) {
- childConnectTimeMillis = Math.min(child.getConnectTimeMillis(),
- childConnectTimeMillis);
- }
childCallIds.add(child.getId());
}
-
- if (childConnectTimeMillis != Long.MAX_VALUE) {
- connectTimeMillis = childConnectTimeMillis;
- }
}
Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
@@ -226,7 +216,7 @@
}
Bundle extras;
- if (isForSystemDialer) {
+ if (isForSystemInCallService) {
extras = call.getExtras();
} else {
extras = sanitizeExtras(call.getExtras());
@@ -240,7 +230,7 @@
.setCapabilities(capabilities)
.setProperties(properties)
.setSupportedAudioRoutes(supportedAudioRoutes)
- .setConnectTimeMillis(connectTimeMillis)
+ .setConnectTimeMillis(call.getConnectTimeMillis())
.setHandle(handle)
.setHandlePresentation(call.getHandlePresentation())
.setCallerDisplayName(callerDisplayName)
@@ -279,9 +269,9 @@
* <li>Caller number verification status (verstat)</li>
* </ul>
* All other fields are nulled or set to 0 values.
- * Where the call screening service is part of the system dialer, the
+ * Where the call screening service is part of the system incallservice, the
* {@link Connection#EXTRA_SIP_INVITE} header information is also sent to the call screening
- * service (since the system dialer has access to this anyways).
+ * service (since the system incallservice has access to this anyways).
* @param call The telecom call to send to a call screening service.
* @param areRestrictedExtrasIncluded {@code true} if the set of restricted extras defined in
* {@link #RESTRICTED_CALL_SCREENING_EXTRA_KEYS} are to
@@ -343,7 +333,7 @@
/**
* Sanitize the extras bundle passed in, removing keys which should not be sent to non-system
- * dialer apps.
+ * incallservice apps.
* @param oldExtras Extras bundle to sanitize.
* @return The sanitized extras bundle.
*/
@@ -391,7 +381,7 @@
private static int getParcelableState(Call call, boolean supportsExternalCalls) {
int state = CallState.NEW;
- switch (call.getState()) {
+ switch (call.getParcelableCallState()) {
case CallState.ABORTED:
case CallState.DISCONNECTED:
state = android.telecom.Call.STATE_DISCONNECTED;
@@ -443,12 +433,6 @@
break;
}
- // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
- // Unless we're disconnect*ED*, in which case leave it at that.
- if (call.isLocallyDisconnecting() &&
- (state != android.telecom.Call.STATE_DISCONNECTED)) {
- state = android.telecom.Call.STATE_DISCONNECTING;
- }
return state;
}
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 22568f1..9a4f7df 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -130,14 +131,6 @@
PhoneAccount phoneAccount) {}
}
- /**
- * Abstracts away dependency on the {@link PackageManager} required to fetch the label for an
- * app.
- */
- public interface AppLabelProxy {
- CharSequence getAppLabel(String packageName);
- }
-
public static final String FILE_NAME = "phone-account-registrar-state.xml";
@VisibleForTesting
public static final int EXPECTED_STATE_VERSION = 9;
@@ -493,6 +486,7 @@
* target phone account.
* @return phone account handle of sim call manager based on the ongoing call.
*/
+ @Nullable
public PhoneAccountHandle getSimCallManagerFromCall(Call call) {
if (call == null) {
return null;
@@ -516,6 +510,14 @@
*/
public PhoneAccountHandle getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount,
UserHandle userHandle) {
+ // First, check if the specified target phone account handle is a connection manager; if
+ // it is, then just return it.
+ PhoneAccount phoneAccount = getPhoneAccountUnchecked(targetPhoneAccount);
+ if (phoneAccount != null
+ && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
+ return targetPhoneAccount;
+ }
+
int subId = getSubscriptionIdForPhoneAccount(targetPhoneAccount);
if (SubscriptionManager.isValidSubscriptionId(subId)
&& subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
@@ -1264,11 +1266,11 @@
// Comparator which places PhoneAccounts with a specified sort order first, followed by
// those with no sort order.
Comparator<PhoneAccount> bySortOrder = (p1, p2) -> {
- String sort1 = p1.getExtras() == null ? null :
- p1.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null);
- String sort2 = p2.getExtras() == null ? null :
- p2.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null);
- return nullSafeStringComparator.compare(sort1, sort2);
+ int sort1 = p1.getExtras() == null ? Integer.MAX_VALUE:
+ p1.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
+ int sort2 = p2.getExtras() == null ? Integer.MAX_VALUE:
+ p2.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
+ return Integer.compare(sort1, sort2);
};
// Comparator which sorts PhoneAccounts by label.
@@ -1597,10 +1599,16 @@
return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
}
+ @Nullable
protected Icon readIcon(XmlPullParser parser) throws IOException {
- byte[] iconByteArray = Base64.decode(parser.getText(), 0);
- ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
- return Icon.createFromStream(stream);
+ try {
+ byte[] iconByteArray = Base64.decode(parser.getText(), 0);
+ ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
+ return Icon.createFromStream(stream);
+ } catch (IllegalArgumentException e) {
+ Log.e(this, e, "Bitmap must not be null.");
+ return null;
+ }
}
}
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index f2531ed..f02f7e8 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -17,8 +17,16 @@
package com.android.server.telecom;
import android.telecom.Log;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyRegistryManager;
+import android.telephony.emergency.EmergencyNumber;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
/**
* Send a {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} broadcast when the call state
@@ -52,6 +60,10 @@
return;
}
updateStates(call);
+
+ if (call.isEmergencyCall() && !call.isIncoming()) {
+ sendOutgoingEmergencyCallEvent(call);
+ }
}
@Override
@@ -113,4 +125,31 @@
Log.i(this, "Broadcasted state change: %s", mCurrentState);
}
}
+
+ private void sendOutgoingEmergencyCallEvent(Call call) {
+ 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();
+
+ int subscriptionId = tm.getSubscriptionId(call.getTargetPhoneAccount());
+ SubscriptionManager subscriptionManager =
+ mCallsManager.getContext().getSystemService(SubscriptionManager.class);
+ int simSlotIndex = SubscriptionManager.DEFAULT_PHONE_INDEX;
+ if (subscriptionManager != null) {
+ SubscriptionInfo subInfo =
+ subscriptionManager.getActiveSubscriptionInfo(subscriptionId);
+ if (subInfo != null) {
+ simSlotIndex = subInfo.getSimSlotIndex();
+ }
+ }
+
+ if (emergencyNumber.isPresent()) {
+ mRegistry.notifyOutgoingEmergencyCall(
+ simSlotIndex, subscriptionId, emergencyNumber.get());
+ }
+ }
}
diff --git a/src/com/android/server/telecom/RespondViaSmsManager.java b/src/com/android/server/telecom/RespondViaSmsManager.java
index a709ae5..00d94f0 100644
--- a/src/com/android/server/telecom/RespondViaSmsManager.java
+++ b/src/com/android/server/telecom/RespondViaSmsManager.java
@@ -212,7 +212,8 @@
messageParts.size());
context.registerReceiver(receiver, new IntentFilter(ACTION_MESSAGE_SENT));
smsManager.sendMultipartTextMessage(phoneNumber, null, messageParts,
- sentIntents/*sentIntent*/, null /*deliveryIntent*/, context.getOpPackageName());
+ sentIntents/*sentIntent*/, null /*deliveryIntent*/, context.getOpPackageName(),
+ context.getAttributionTag());
} catch (IllegalArgumentException e) {
Log.w(RespondViaSmsManager.this, "Couldn't send SMS message: " +
e.getMessage());
diff --git a/src/com/android/server/telecom/RespondViaSmsSettings.java b/src/com/android/server/telecom/RespondViaSmsSettings.java
index 3bee5f7..6d7c5c6 100644
--- a/src/com/android/server/telecom/RespondViaSmsSettings.java
+++ b/src/com/android/server/telecom/RespondViaSmsSettings.java
@@ -18,16 +18,18 @@
import android.app.ActionBar;
import android.app.Activity;
-import android.content.Context;
+import android.app.AlertDialog;
import android.content.SharedPreferences;
-import android.telecom.Log;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
-import android.view.Menu;
+import android.telecom.Log;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.view.MenuItem;
+import android.widget.Button;
// TODO: This class is newly copied into Telecom (com.android.server.telecom) from it previous
// location in Telephony (com.android.phone). User's preferences stored in the old location
@@ -103,11 +105,15 @@
// (Watch out: onPreferenceChange() is called *before* the
// Preference itself gets updated, so we need to use newValue here
// rather than pref.getText().)
- pref.setTitle((String) newValue);
+ // If the newValue is an empty string, skip this to avoid setting an empty response.
+ // TODO: Show a popup to inform user that response didn't set because it's empty.
+ if (((String) newValue).length() != 0) {
+ pref.setTitle((String) newValue);
- // Save the new preference value.
- SharedPreferences.Editor editor = mPrefs.edit();
- editor.putString(pref.getKey(), (String) newValue).commit();
+ // Save the new preference value.
+ SharedPreferences.Editor editor = mPrefs.edit();
+ editor.putString(pref.getKey(), (String) newValue).commit();
+ }
// If the user just reset the quick response to its original text, clear the pref.
QuickResponseUtils.maybeResetQuickResponses(this, mPrefs);
@@ -141,6 +147,33 @@
EditTextPreference pref = (EditTextPreference) preference;
pref.setText(mPrefs.getString(pref.getKey(), pref.getText()));
pref.setTitle(pref.getText());
+ pref.getEditText().addTextChangedListener(new TextWatcher() {
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ try {
+ Button button = ((AlertDialog) pref.getDialog())
+ .getButton(AlertDialog.BUTTON_POSITIVE);
+ if (s.toString().length() == 0) {
+ button.setEnabled(false);
+ } else {
+ button.setEnabled(true);
+ }
+ } catch (NullPointerException e) {
+ Log.d(this, e.toString());
+ }
+ }
+ });
pref.setOnPreferenceChangeListener(this);
}
}
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 55f2b0d..a769a94 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -74,6 +74,9 @@
private static final int[] PULSE_AMPLITUDE;
+ private static final int RAMPING_RINGER_VIBRATION_DURATION = 5000;
+ private static final int RAMPING_RINGER_DURATION = 10000;
+
static {
// construct complete pulse pattern
PULSE_PATTERN = new long[PULSE_PRIMING_PATTERN.length + PULSE_RAMPING_PATTERN.length];
@@ -111,13 +114,6 @@
private static final int REPEAT_SIMPLE_VIBRATION_AT = 1;
- private static final int DEFAULT_RAMPING_RINGER_DURATION = 10000; // 10 seconds
-
- private int mRampingRingerDuration = -1; // ramping ringer duration in millisecond
-
- // vibration duration before ramping ringer in second
- private int mRampingRingerVibrationDuration = 0;
-
private static final float EPSILON = 1e-6f;
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
@@ -287,36 +283,18 @@
// call (for the purposes of direct-to-voicemail), the information about custom
// ringtones should be available by the time this code executes. We can safely
// request the custom ringtone from the call and expect it to be current.
- if (mSystemSettingsUtil.applyRampingRinger(mContext)
- && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()) {
+ if (mSystemSettingsUtil.applyRampingRinger(mContext)) {
Log.i(this, "start ramping ringer.");
- // configure vibration effect for ramping ringer.
- int previousRampingRingerVibrationDuration = mRampingRingerVibrationDuration;
- // get vibration duration in millisecond and round down to second.
- mRampingRingerVibrationDuration =
- mSystemSettingsUtil.getRampingRingerVibrationDuration() >= 0
- ? mSystemSettingsUtil.getRampingRingerVibrationDuration() / 1000
- : 0;
if (mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) {
effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
} else {
effect = mDefaultVibrationEffect;
}
-
- // configure volume shaper for ramping ringer
- int previousRampingRingerDuration = mRampingRingerDuration;
- mRampingRingerDuration =
- mSystemSettingsUtil.getRampingRingerDuration() > 0
- ? mSystemSettingsUtil.getRampingRingerDuration()
- : DEFAULT_RAMPING_RINGER_DURATION;
- if (mRampingRingerDuration != previousRampingRingerDuration
- || mRampingRingerVibrationDuration != previousRampingRingerVibrationDuration
- || mVolumeShaperConfig == null) {
- float silencePoint = (float) (mRampingRingerVibrationDuration * 1000)
- / (float) (mRampingRingerVibrationDuration * 1000 + mRampingRingerDuration);
+ if (mVolumeShaperConfig == null) {
+ float silencePoint = (float) (RAMPING_RINGER_VIBRATION_DURATION)
+ / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION);
mVolumeShaperConfig = new VolumeShaper.Configuration.Builder()
- .setDuration(mRampingRingerVibrationDuration * 1000
- + mRampingRingerDuration)
+ .setDuration(RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION)
.setCurve(new float[] {0.f, silencePoint + EPSILON /*keep monotonicity*/,
1.f}, new float[] {0.f, 0.f, 1.f})
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
@@ -346,6 +324,11 @@
isUsingAudioCoupledHaptics, mIsHapticPlaybackSupportedByDevice);
maybeStartVibration(foregroundCall, shouldRingForContact, effect,
isVibratorEnabled, isRingerAudible);
+ } else if (mSystemSettingsUtil.applyRampingRinger(mContext)
+ && !mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) {
+ Log.i(this, "startRinging: apply ramping ringer vibration");
+ maybeStartVibration(foregroundCall, shouldRingForContact, effect,
+ isVibratorEnabled, isRingerAudible);
} else {
Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION,
"using audio-coupled haptics");
@@ -368,11 +351,9 @@
private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact,
VibrationEffect effect, boolean isVibrationEnabled, boolean isRingerAudible) {
-
if (isVibrationEnabled
&& !mIsVibrating && shouldRingForContact) {
if (mSystemSettingsUtil.applyRampingRinger(mContext)
- && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()
&& isRingerAudible) {
Log.i(this, "start vibration for ramping ringer.");
mIsVibrating = true;
@@ -477,6 +458,10 @@
}
}
+ public boolean isRinging() {
+ return mRingtonePlayer.isPlaying();
+ }
+
private boolean shouldRingForContact(Uri contactUri) {
final NotificationManager manager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -530,7 +515,6 @@
return false;
}
return mSystemSettingsUtil.canVibrateWhenRinging(context)
- || (mSystemSettingsUtil.applyRampingRinger(context)
- && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig());
+ || mSystemSettingsUtil.applyRampingRinger(context);
}
}
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index c64fc73..aa2e2a2 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -120,7 +120,8 @@
public void binderDied() {
try {
synchronized (mLock) {
- Log.startSession("SDR.bD");
+ Log.startSession("SDR.bD",
+ Log.getPackageAbbreviation(mComponentName));
Log.i(this, "binderDied: ConnectionService %s died.", mComponentName);
logServiceDisconnected("binderDied");
handleDisconnect();
@@ -144,7 +145,7 @@
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
- Log.startSession("SBC.oSC");
+ Log.startSession("SBC.oSC", Log.getPackageAbbreviation(componentName));
synchronized (mLock) {
Log.i(this, "Service bound %s", componentName);
@@ -182,7 +183,7 @@
@Override
public void onServiceDisconnected(ComponentName componentName) {
try {
- Log.startSession("SBC.oSD");
+ Log.startSession("SBC.oSD", Log.getPackageAbbreviation(componentName));
synchronized (mLock) {
logServiceDisconnected("onServiceDisconnected");
handleDisconnect();
@@ -212,6 +213,11 @@
/** The component name of the service to bind to. */
protected final ComponentName mComponentName;
+ /**
+ * Abbreviated form of the package name from {@link #mComponentName}; used for session logging.
+ */
+ protected final String mPackageAbbreviation;
+
/** The set of callbacks waiting for notification of the binding's success or failure. */
private final Set<BindCallback> mCallbacks = new ArraySet<>();
@@ -261,6 +267,7 @@
mLock = lock;
mServiceAction = serviceAction;
mComponentName = componentName;
+ mPackageAbbreviation = Log.getPackageAbbreviation(componentName);
mUserHandle = userHandle;
}
diff --git a/src/com/android/server/telecom/SystemSettingsUtil.java b/src/com/android/server/telecom/SystemSettingsUtil.java
index 62e1a68..f104f27 100644
--- a/src/com/android/server/telecom/SystemSettingsUtil.java
+++ b/src/com/android/server/telecom/SystemSettingsUtil.java
@@ -30,16 +30,6 @@
@VisibleForTesting
public class SystemSettingsUtil {
- /** Flag for ringer ramping time in milliseconds. */
- private static final String RAMPING_RINGER_DURATION_MILLIS = "ramping_ringer_duration";
-
- /** Flag for vibration time in milliseconds before ramping ringer starts. */
- private static final String RAMPING_RINGER_VIBRATION_DURATION =
- "ramping_ringer_vibration_duration";
-
- /** Flag for whether or not to apply ramping ringer on incoming phone calls. */
- private static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
-
/** Flag for whether or not to support audio coupled haptics in ramping ringer. */
private static final String RAMPING_RINGER_AUDIO_COUPLED_VIBRATION_ENABLED =
"ramping_ringer_audio_coupled_vibration_enabled";
@@ -69,26 +59,11 @@
Settings.Global.APPLY_RAMPING_RINGER, 0) == 1;
}
- public boolean enableRampingRingerFromDeviceConfig() {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, RAMPING_RINGER_ENABLED,
- false);
- }
-
public boolean enableAudioCoupledVibrationForRampingRinger() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY,
RAMPING_RINGER_AUDIO_COUPLED_VIBRATION_ENABLED, false);
}
- public int getRampingRingerDuration() {
- return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TELEPHONY,
- RAMPING_RINGER_DURATION_MILLIS, -1);
- }
-
- public int getRampingRingerVibrationDuration() {
- return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TELEPHONY,
- RAMPING_RINGER_VIBRATION_DURATION, 0);
- }
-
public boolean isHapticPlaybackSupported(Context context) {
return context.getSystemService(AudioManager.class).isHapticPlaybackSupported();
}
diff --git a/src/com/android/server/telecom/SystemStateHelper.java b/src/com/android/server/telecom/SystemStateHelper.java
index 073b081..3be3d5e 100644
--- a/src/com/android/server/telecom/SystemStateHelper.java
+++ b/src/com/android/server/telecom/SystemStateHelper.java
@@ -26,6 +26,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.net.Uri;
import android.telecom.Log;
import java.util.Set;
@@ -38,7 +39,7 @@
* Provides various system states to the rest of the telecom codebase.
*/
public class SystemStateHelper {
- public static interface SystemStateListener {
+ public interface SystemStateListener {
/**
* Listener method to inform interested parties when a package name requests to enter or
* exit car mode.
@@ -48,6 +49,12 @@
* otherwise.
*/
void onCarModeChanged(int priority, String packageName, boolean isCarMode);
+
+ /**
+ * Notifies when a package has been uninstalled.
+ * @param packageName the package name of the uninstalled package
+ */
+ void onPackageUninstalled(String packageName);
}
private final Context mContext;
@@ -62,7 +69,7 @@
UiModeManager.DEFAULT_PRIORITY);
String callingPackage = intent.getStringExtra(
UiModeManager.EXTRA_CALLING_PACKAGE);
- Log.i(SystemStateHelper.this, "ENTER_CAR_MODE_PRIVILEGED; priority=%d, pkg=%s",
+ 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)) {
@@ -70,11 +77,21 @@
UiModeManager.DEFAULT_PRIORITY);
String callingPackage = intent.getStringExtra(
UiModeManager.EXTRA_CALLING_PACKAGE);
- Log.i(SystemStateHelper.this, "EXIT_CAR_MODE_PRIVILEGED; priority=%d, pkg=%s",
+ 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(this, "Unexpected intent received: %s", intent.getAction());
+ Log.w(SystemStateHelper.this,
+ "Unexpected intent received: %s", intent.getAction());
}
} finally {
Log.endSession();
@@ -88,11 +105,16 @@
public SystemStateHelper(Context context) {
mContext = context;
- IntentFilter intentFilter = new IntentFilter(
+ IntentFilter intentFilter1 = new IntentFilter(
UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
- intentFilter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
- mContext.registerReceiver(mBroadcastReceiver, intentFilter);
- Log.i(this, "Registering car mode receiver: %s", intentFilter);
+ intentFilter1.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+
+ IntentFilter intentFilter2 = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter2.addDataScheme("package");
+ mContext.registerReceiver(mBroadcastReceiver, intentFilter1);
+ mContext.registerReceiver(mBroadcastReceiver, intentFilter2);
+ Log.i(this, "Registering broadcast receiver: %s", intentFilter1);
+ Log.i(this, "Registering broadcast receiver: %s", intentFilter2);
mIsCarMode = getSystemCarMode();
}
diff --git a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index 06aa174..e1f2d08 100644
--- a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -24,7 +24,6 @@
import android.telecom.Log;
import android.widget.Toast;
-import com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity;
import com.android.server.telecom.ui.ConfirmCallDialogActivity;
import com.android.server.telecom.ui.DisconnectedCallNotifier;
@@ -80,27 +79,31 @@
"com.android.server.telecom.CANCEL_CALL";
/**
- * The action used to proceed with a redirected call being confirmed via
- * {@link com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity}.
+ * The action used to proceed with a redirected call being confirmed via the call redirection
+ * confirmation dialog.
*/
public static final String ACTION_PLACE_REDIRECTED_CALL =
"com.android.server.telecom.PROCEED_WITH_REDIRECTED_CALL";
/**
- * The action used to confirm to proceed the call without redirection via
- * {@link com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity}.
+ * The action used to confirm to proceed the call without redirection via the call redirection
+ * confirmation dialog.
*/
public static final String ACTION_PLACE_UNREDIRECTED_CALL =
"com.android.server.telecom.PROCEED_WITH_UNREDIRECTED_CALL";
/**
- * The action used to cancel a redirected call being confirmed via
- * {@link com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity}.
+ * The action used to cancel a redirected call being confirmed via the call redirection
+ * confirmation dialog.
*/
public static final String ACTION_CANCEL_REDIRECTED_CALL =
"com.android.server.telecom.CANCEL_REDIRECTED_CALL";
public static final String EXTRA_USERHANDLE = "userhandle";
+ public static final String EXTRA_REDIRECTION_OUTGOING_CALL_ID =
+ "android.telecom.extra.REDIRECTION_OUTGOING_CALL_ID";
+ public static final String EXTRA_REDIRECTION_APP_NAME =
+ "android.telecom.extra.REDIRECTION_APP_NAME";
private final Context mContext;
private final CallsManager mCallsManager;
@@ -214,8 +217,7 @@
Log.startSession("TBIP.aPRC");
try {
mCallsManager.processRedirectedOutgoingCallAfterUserInteraction(
- intent.getStringExtra(CallRedirectionConfirmDialogActivity
- .EXTRA_REDIRECTION_OUTGOING_CALL_ID),
+ intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID),
ACTION_PLACE_REDIRECTED_CALL);
} finally {
Log.endSession();
@@ -224,8 +226,7 @@
Log.startSession("TBIP.aPUC");
try {
mCallsManager.processRedirectedOutgoingCallAfterUserInteraction(
- intent.getStringExtra(CallRedirectionConfirmDialogActivity
- .EXTRA_REDIRECTION_OUTGOING_CALL_ID),
+ intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID),
ACTION_PLACE_UNREDIRECTED_CALL);
} finally {
Log.endSession();
@@ -234,8 +235,7 @@
Log.startSession("TBIP.aCRC");
try {
mCallsManager.processRedirectedOutgoingCallAfterUserInteraction(
- intent.getStringExtra(CallRedirectionConfirmDialogActivity
- .EXTRA_REDIRECTION_OUTGOING_CALL_ID),
+ intent.getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID),
ACTION_CANCEL_REDIRECTED_CALL);
} finally {
Log.endSession();
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 08d77a0..3481558 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -20,8 +20,10 @@
import static android.Manifest.permission.CALL_PRIVILEGED;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_NUMBERS;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.Manifest.permission.READ_SMS;
import static android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
@@ -32,6 +34,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -41,6 +44,7 @@
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
+import android.provider.BlockedNumberContract;
import android.provider.Settings;
import android.telecom.Log;
import android.telecom.PhoneAccount;
@@ -54,6 +58,7 @@
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;
@@ -108,18 +113,15 @@
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
@Override
public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme,
- String callingPackage) {
+ String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.gDOPA");
synchronized (mLock) {
- if (!canReadPhoneState(callingPackage, "getDefaultOutgoingPhoneAccount")) {
- return null;
- }
-
+ PhoneAccountHandle phoneAccountHandle = null;
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
try {
- return mPhoneAccountRegistrar
+ phoneAccountHandle = mPhoneAccountRegistrar
.getOutgoingPhoneAccountForScheme(uriScheme, callingUserHandle);
} catch (Exception e) {
Log.e(this, e, "getDefaultOutgoingPhoneAccount");
@@ -127,6 +129,14 @@
} finally {
Binder.restoreCallingIdentity(token);
}
+ if (isCallerSimCallManager(phoneAccountHandle)
+ || canReadPhoneState(
+ callingPackage,
+ callingFeatureId,
+ "getDefaultOutgoingPhoneAccount")) {
+ return phoneAccountHandle;
+ }
+ return null;
}
} finally {
Log.endSession();
@@ -179,7 +189,7 @@
@Override
public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
- boolean includeDisabledAccounts, String callingPackage) {
+ boolean includeDisabledAccounts, String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.gCCPA");
if (includeDisabledAccounts &&
@@ -187,7 +197,8 @@
callingPackage, "getCallCapablePhoneAccounts")) {
return Collections.emptyList();
}
- if (!canReadPhoneState(callingPackage, "getCallCapablePhoneAccounts")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId,
+ "getCallCapablePhoneAccounts")) {
return Collections.emptyList();
}
synchronized (mLock) {
@@ -209,10 +220,12 @@
}
@Override
- public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage) {
+ public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage,
+ String callingFeatureId) {
try {
Log.startSession("TSI.gSMPA");
- if (!canReadPhoneState(callingPackage, "Requires READ_PHONE_STATE permission.")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId,
+ "Requires READ_PHONE_STATE permission.")) {
throw new SecurityException("Requires READ_PHONE_STATE permission.");
}
synchronized (mLock) {
@@ -267,6 +280,23 @@
@Override
public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
+ //TODO: Deprecate this in S
+ try {
+ enforceCallingPackage(packageName);
+ } catch (SecurityException se1) {
+ EventLog.writeEvent(0x534e4554, "153995334", Binder.getCallingUid(),
+ "getPhoneAccountsForPackage: invalid calling package");
+ throw se1;
+ }
+
+ try {
+ enforcePermission(READ_PRIVILEGED_PHONE_STATE);
+ } catch (SecurityException se2) {
+ EventLog.writeEvent(0x534e4554, "153995334", Binder.getCallingUid(),
+ "getPhoneAccountsForPackage: no permission");
+ throw se2;
+ }
+
synchronized (mLock) {
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
@@ -563,11 +593,11 @@
*/
@Override
public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number,
- String callingPackage) {
+ String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.iVMN");
synchronized (mLock) {
- if (!canReadPhoneState(callingPackage, "isVoiceMailNumber")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId, "isVoiceMailNumber")) {
return false;
}
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
@@ -595,10 +625,11 @@
* @see android.telecom.TelecomManager#getVoiceMailNumber
*/
@Override
- public String getVoiceMailNumber(PhoneAccountHandle accountHandle, String callingPackage) {
+ public String getVoiceMailNumber(PhoneAccountHandle accountHandle, String callingPackage,
+ String callingFeatureId) {
try {
Log.startSession("TSI.gVMN");
- if (!canReadPhoneState(callingPackage, "getVoiceMailNumber")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId, "getVoiceMailNumber")) {
return null;
}
try {
@@ -630,10 +661,11 @@
* @see android.telecom.TelecomManager#getLine1Number
*/
@Override
- public String getLine1Number(PhoneAccountHandle accountHandle, String callingPackage) {
+ public String getLine1Number(PhoneAccountHandle accountHandle, String callingPackage,
+ String callingFeatureId) {
try {
Log.startSession("getL1N");
- if (!canReadPhoneState(callingPackage, "getLine1Number")) {
+ if (!canReadPhoneNumbers(callingPackage, callingFeatureId, "getLine1Number")) {
return null;
}
@@ -696,7 +728,7 @@
public ComponentName getDefaultPhoneApp() {
try {
Log.startSession("TSI.gDPA");
- return mDefaultDialerCache.getSystemDialerComponent();
+ return mDefaultDialerCache.getDialtactsSystemDialerComponent();
} finally {
Log.endSession();
}
@@ -784,10 +816,10 @@
* @see android.telecom.TelecomManager#isInCall
*/
@Override
- public boolean isInCall(String callingPackage) {
+ public boolean isInCall(String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.iIC");
- if (!canReadPhoneState(callingPackage, "isInCall")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId, "isInCall")) {
return false;
}
@@ -800,13 +832,29 @@
}
/**
+ * @see android.telecom.TelecomManager#hasCompanionInCallServiceAccess
+ */
+ @Override
+ public boolean hasCompanionInCallServiceAccess(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;
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ /**
* @see android.telecom.TelecomManager#isInManagedCall
*/
@Override
- public boolean isInManagedCall(String callingPackage) {
+ public boolean isInManagedCall(String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.iIMC");
- if (!canReadPhoneState(callingPackage, "isInManagedCall")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId, "isInManagedCall")) {
throw new SecurityException("Only the default dialer or caller with " +
"READ_PHONE_STATE permission can use this method.");
}
@@ -842,7 +890,7 @@
// current state as tracked by PhoneStateBroadcaster, any failure to properly
// track the current call state there could result in the wrong ringing state
// being reported by this API.
- return mCallsManager.hasRingingCall();
+ return mCallsManager.hasRingingOrSimulatedRingingCall();
}
} finally {
Log.endSession();
@@ -937,10 +985,11 @@
* @see android.telecom.TelecomManager#showInCallScreen
*/
@Override
- public void showInCallScreen(boolean showDialpad, String callingPackage) {
+ public void showInCallScreen(boolean showDialpad, String callingPackage,
+ String callingFeatureId) {
try {
Log.startSession("TSI.sICS");
- if (!canReadPhoneState(callingPackage, "showInCallScreen")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId, "showInCallScreen")) {
return;
}
@@ -1086,10 +1135,10 @@
* @see android.telecom.TelecomManager#isTtySupported
*/
@Override
- public boolean isTtySupported(String callingPackage) {
+ public boolean isTtySupported(String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.iTS");
- if (!canReadPhoneState(callingPackage, "isTtySupported")) {
+ 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");
}
@@ -1106,10 +1155,10 @@
* @see android.telecom.TelecomManager#getCurrentTtyMode
*/
@Override
- public int getCurrentTtyMode(String callingPackage) {
+ public int getCurrentTtyMode(String callingPackage, String callingFeatureId) {
try {
Log.startSession("TSI.gCTM");
- if (!canReadPhoneState(callingPackage, "getCurrentTtyMode")) {
+ if (!canReadPhoneState(callingPackage, callingFeatureId, "getCurrentTtyMode")) {
return TelecomManager.TTY_MODE_OFF;
}
@@ -1356,7 +1405,8 @@
* @see android.telecom.TelecomManager#placeCall
*/
@Override
- public void placeCall(Uri handle, Bundle extras, String callingPackage) {
+ public void placeCall(Uri handle, Bundle extras, String callingPackage,
+ String callingFeatureId) {
try {
Log.startSession("TSI.pC");
enforceCallingPackage(callingPackage);
@@ -1378,14 +1428,14 @@
if (!callingPackage.equals(
phoneAccountHandle.getComponentName().getPackageName())
- && !canCallPhone(callingPackage,
+ && !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.");
}
- } else if (!canCallPhone(callingPackage, "placeCall")) {
+ } else if (!canCallPhone(callingPackage, callingFeatureId, "placeCall")) {
throw new SecurityException("Package " + callingPackage
+ " is not allowed to place phone calls");
}
@@ -1398,7 +1448,8 @@
// by {@link UserCallIntentProcessor}.
final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
- Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+ Binder.getCallingUid(), callingPackage, callingFeatureId, null)
+ == AppOpsManager.MODE_ALLOWED;
final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
PackageManager.PERMISSION_GRANTED;
@@ -1477,6 +1528,28 @@
}
@Override
+ public void stopBlockSuppression() {
+ try {
+ Log.startSession("TSI.sBS");
+ enforceModifyPermission();
+ if (Binder.getCallingUid() != Process.SHELL_UID
+ && Binder.getCallingUid() != Process.ROOT_UID) {
+ throw new SecurityException("Shell-only API.");
+ }
+ synchronized (mLock) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public TelecomAnalytics dumpCallAnalytics() {
try {
Log.startSession("TSI.dCA");
@@ -1698,6 +1771,32 @@
}
}
+ /**
+ * A method intended for use in testing to clean up any calls that get stuck in the
+ * {@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.
+ */
+ @Override
+ public void cleanupStuckCalls() {
+ Log.startSession("TCI.cSC");
+ try {
+ synchronized (mLock) {
+ enforceShellOnly(Binder.getCallingUid(), "cleanupStuckCalls");
+ Binder.withCleanCallingIdentity(() -> {
+ for (Call call : mCallsManager.getCalls()) {
+ if (call.getState() == CallState.DISCONNECTED
+ || call.getState() == CallState.DISCONNECTING) {
+ mCallsManager.markCallAsRemoved(call);
+ }
+ }
+ });
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
@Override
public void setTestDefaultCallRedirectionApp(String packageName) {
try {
@@ -1930,12 +2029,12 @@
}
private void acceptRingingCallInternal(int videoState) {
- Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
+ Call call = mCallsManager.getFirstCallWithState(CallState.RINGING, CallState.SIMULATED_RINGING);
if (call != null) {
if (videoState == DEFAULT_VIDEO_STATE || !isValidAcceptVideoState(videoState)) {
videoState = call.getVideoState();
}
- call.answer(videoState);
+ mCallsManager.answerCall(call, videoState);
}
}
@@ -1949,6 +2048,7 @@
CallState.DIALING,
CallState.PULLING,
CallState.RINGING,
+ CallState.SIMULATED_RINGING,
CallState.ON_HOLD);
}
@@ -1958,10 +2058,11 @@
return false;
}
- if (call.getState() == CallState.RINGING) {
- call.reject(false /* rejectWithMessage */, null, callingPackage);
+ if (call.getState() == CallState.RINGING
+ || call.getState() == CallState.SIMULATED_RINGING) {
+ mCallsManager.rejectCall(call, false /* rejectWithMessage */, null);
} else {
- call.disconnect(0 /* disconnectionTimeout */, callingPackage);
+ mCallsManager.disconnectCall(call);
}
return true;
}
@@ -2087,7 +2188,8 @@
throw new SecurityException(message + ": Only shell user can call it");
}
- private boolean canReadPhoneState(String callingPackage, String message) {
+ private boolean canReadPhoneState(String callingPackage, String callingFeatureId,
+ String message) {
// The system/default dialer can always read phone state - so that emergency calls will
// still work.
if (isPrivilegedDialerCalling(callingPackage)) {
@@ -2104,11 +2206,64 @@
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, message);
// Some apps that have the permission can be restricted via app ops.
- return mAppOpsManager.noteOp(AppOpsManager.OP_READ_PHONE_STATE,
- Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+ return mAppOpsManager.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+ callingPackage, callingFeatureId, message) == AppOpsManager.MODE_ALLOWED;
}
}
+ private boolean canReadPhoneNumbers(String callingPackage, String callingFeatureId,
+ String message) {
+ boolean targetSdkPreR = false;
+ int uid = Binder.getCallingUid();
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfoAsUser(
+ callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid()));
+ targetSdkPreR = applicationInfo != null
+ && applicationInfo.targetSdkVersion < Build.VERSION_CODES.R;
+ } catch (PackageManager.NameNotFoundException e) {
+ // In the case that the PackageManager cannot find the specified calling package apply
+ // the more restrictive target R+ requirements.
+ }
+ // Apps targeting pre-R can access phone numbers via READ_PHONE_STATE
+ if (targetSdkPreR) {
+ try {
+ return canReadPhoneState(callingPackage, callingFeatureId, message);
+ } catch (SecurityException e) {
+ // Apps targeting pre-R can still access phone numbers via the additional checks
+ // below.
+ }
+ } else {
+ // The system/default dialer can always read phone state - so that emergency calls will
+ // still work.
+ if (isPrivilegedDialerCalling(callingPackage)) {
+ return true;
+ }
+ if (mContext.checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ if (mContext.checkCallingOrSelfPermission(READ_PHONE_NUMBERS)
+ == PackageManager.PERMISSION_GRANTED && mAppOpsManager.noteOpNoThrow(
+ AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage, callingFeatureId,
+ message) == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+ if (mContext.checkCallingOrSelfPermission(READ_SMS) == PackageManager.PERMISSION_GRANTED
+ && mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage,
+ callingFeatureId, message) == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+ // The default SMS app with the WRITE_SMS appop granted can access phone numbers.
+ if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage,
+ callingFeatureId, message) == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+ throw new SecurityException("Package " + callingPackage
+ + " does not meet the requirements to access the phone number");
+ }
+
+
private boolean canReadPrivilegedPhoneState(String callingPackage, String message) {
// The system/default dialer can always read phone state - so that emergency calls will
// still work.
@@ -2143,6 +2298,10 @@
}
private boolean canCallPhone(String callingPackage, String message) {
+ return canCallPhone(callingPackage, null /* featureId */, message);
+ }
+
+ private boolean canCallPhone(String callingPackage, String callingFeatureId, String message) {
// The system/default dialer can always read phone state - so that emergency calls will
// still work.
if (isPrivilegedDialerCalling(callingPackage)) {
@@ -2154,7 +2313,8 @@
// Some apps that have the permission can be restricted via app ops.
return mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
- Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+ Binder.getCallingUid(), callingPackage, callingFeatureId, message)
+ == AppOpsManager.MODE_ALLOWED;
}
private boolean isCallerSimCallManager(PhoneAccountHandle targetPhoneAccount) {
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 4bc61e0..08389b9 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -32,6 +32,7 @@
import com.android.server.telecom.DefaultDialerCache.DefaultDialerManagerAdapter;
import com.android.server.telecom.ui.ToastFactory;
+import android.app.ActivityManager;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -206,7 +207,8 @@
ClockProxy clockProxy,
RoleManagerAdapter roleManagerAdapter,
IncomingCallFilter.Factory incomingCallFilterFactory,
- ContactsAsyncHelper.Factory contactsAsyncHelperFactory) {
+ ContactsAsyncHelper.Factory contactsAsyncHelperFactory,
+ DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
mContext = context.getApplicationContext();
LogUtils.initLogging(mContext);
DefaultDialerManagerAdapter defaultDialerAdapter =
@@ -217,20 +219,9 @@
Log.startSession("TS.init");
mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext, defaultDialerCache,
- new PhoneAccountRegistrar.AppLabelProxy() {
- @Override
- public CharSequence getAppLabel(String packageName) {
- PackageManager pm = mContext.getPackageManager();
- try {
- ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
- return pm.getApplicationLabel(info);
- } catch (PackageManager.NameNotFoundException nnfe) {
- Log.w(this, "Could not determine package name.");
- }
+ packageName -> AppLabelProxy.Util.getAppLabel(
+ mContext.getPackageManager(), packageName));
- return null;
- }
- });
mContactsAsyncHelper = contactsAsyncHelperFactory.create(
new ContactsAsyncHelper.ContentResolverAdapter() {
@Override
@@ -251,7 +242,8 @@
SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
mMissedCallNotifier = missedCallNotifierImplFactory
- .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache);
+ .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache,
+ deviceIdleControllerAdapter);
DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory =
new DisconnectedCallNotifier.Default();
@@ -347,9 +339,19 @@
mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
- mContext.registerReceiver(mUserSwitchedReceiver, USER_SWITCHED_FILTER);
- mContext.registerReceiver(mUserStartingReceiver, USER_STARTING_FILTER);
- mContext.registerReceiver(mBootCompletedReceiver, BOOT_COMPLETE_FILTER);
+ 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);
+ }
mBluetoothPhoneServiceImpl = bluetoothPhoneServiceImplFactory.makeBluetoothPhoneServiceImpl(
mContext, mLock, mCallsManager, mPhoneAccountRegistrar);
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index 70f774f..7eb08d7 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -70,8 +70,12 @@
}
public static boolean shouldProcessAsEmergency(Context context, Uri handle) {
- TelephonyManager tm = (TelephonyManager) context.getSystemService(
- Context.TELEPHONY_SERVICE);
- return handle != null && tm.isEmergencyNumber(handle.getSchemeSpecificPart());
+ try {
+ TelephonyManager tm = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return handle != null && tm.isEmergencyNumber(handle.getSchemeSpecificPart());
+ } catch (IllegalStateException ise) {
+ return false;
+ }
}
}
diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java
index 37f9363..2309596 100644
--- a/src/com/android/server/telecom/Timeouts.java
+++ b/src/com/android/server/telecom/Timeouts.java
@@ -29,7 +29,8 @@
*/
public final class Timeouts {
public static class Adapter {
- public Adapter() { }
+ public Adapter() {
+ }
public long getCallScreeningTimeoutMillis(ContentResolver cr) {
return Timeouts.getCallScreeningTimeoutMillis(cr);
@@ -62,20 +63,25 @@
public long getPhoneAccountSuggestionServiceTimeout(ContentResolver cr) {
return Timeouts.getPhoneAccountSuggestionServiceTimeout(cr);
}
+
+ public long getCallRecordingToneRepeatIntervalMillis(ContentResolver cr) {
+ return Timeouts.getCallRecordingToneRepeatIntervalMillis(cr);
+ }
}
/** A prefix to use for all keys so to not clobber the global namespace. */
private static final String PREFIX = "telecom.";
- private Timeouts() {}
+ private Timeouts() {
+ }
/**
* Returns the timeout value from Settings or the default value if it hasn't been changed. This
* method is safe to call from any thread, including the UI thread.
*
* @param contentResolver The content resolved.
- * @param key Settings key to retrieve.
- * @param defaultValue Default value, in milliseconds.
+ * @param key Settings key to retrieve.
+ * @param defaultValue Default value, in milliseconds.
* @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) {
@@ -176,8 +182,8 @@
* as potential emergency callbacks.
*/
public static long getEmergencyCallbackWindowMillis(ContentResolver contentResolver) {
- return get(contentResolver, "emergency_callback_window_millis",
- TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));
+ return get(contentResolver, "emergency_callback_window_millis",
+ TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));
}
/**
@@ -187,7 +193,7 @@
*/
public static long getUserDefinedCallRedirectionTimeoutMillis(ContentResolver contentResolver) {
return get(contentResolver, "user_defined_call_redirection_timeout",
- 5000L /* 5 seconds */);
+ 5000L /* 5 seconds */);
}
/**
@@ -198,4 +204,22 @@
public static long getCarrierCallRedirectionTimeoutMillis(ContentResolver contentResolver) {
return get(contentResolver, "carrier_call_redirection_timeout", 5000L /* 5 seconds */);
}
+
+ /**
+ * Returns the number of milliseconds between two plays of the call recording tone.
+ */
+ public static long getCallRecordingToneRepeatIntervalMillis(ContentResolver contentResolver) {
+ return get(contentResolver, "call_recording_tone_repeat_interval", 15000L /* 15 seconds */);
+ }
+
+ /**
+ * 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...).
+ */
+ public static long getDialerMissedCallPowerSaveExemptionTimeMillis(
+ ContentResolver contentResolver) {
+ return get(contentResolver, "dialer_missed_call_power_save_exemption_time_millis",
+ 30000L /*30 seconds*/);
+ }
}
diff --git a/src/com/android/server/telecom/TtyManager.java b/src/com/android/server/telecom/TtyManager.java
index 2d04234..dfddb8f 100644
--- a/src/com/android/server/telecom/TtyManager.java
+++ b/src/com/android/server/telecom/TtyManager.java
@@ -49,7 +49,9 @@
IntentFilter intentFilter = new IntentFilter(
TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
- mContext.registerReceiver(mReceiver, intentFilter);
+ mContext.registerReceiver(mReceiver, intentFilter,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ null);
updateCurrentTtyMode();
}
diff --git a/src/com/android/server/telecom/VideoProviderProxy.java b/src/com/android/server/telecom/VideoProviderProxy.java
index 364e0f4..df11403 100644
--- a/src/com/android/server/telecom/VideoProviderProxy.java
+++ b/src/com/android/server/telecom/VideoProviderProxy.java
@@ -55,6 +55,7 @@
*/
public interface Listener {
void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
+ void onSetCamera(Call call, String cameraId);
}
/**
@@ -346,6 +347,12 @@
return;
}
}
+
+ // Inform other Telecom components of the change in camera status.
+ for (Listener listener : mListeners) {
+ listener.onSetCamera(mCall, cameraId);
+ }
+
try {
mConectionServiceVideoProvider.setCamera(cameraId, callingPackage,
targetSdkVersion);
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index fe34be3..7211990 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -645,6 +645,16 @@
Log.i(this, "No device with address %s available. Using %s instead.",
address, actualAddress);
}
+
+ BluetoothDevice alreadyConnectedDevice = getBluetoothAudioConnectedDevice();
+ if (alreadyConnectedDevice != null && alreadyConnectedDevice.getAddress().equals(
+ actualAddress)) {
+ Log.i(this, "trying to connect to already connected device -- skipping connection"
+ + " and going into the actual connected state.");
+ transitionToActualState();
+ return null;
+ }
+
if (!mDeviceManager.connectAudio(actualAddress)) {
boolean shouldRetry = retryCount < MAX_CONNECTION_RETRIES;
Log.w(LOG_TAG, "Could not connect to %s. Will %s", actualAddress,
diff --git a/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java b/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
deleted file mode 100644
index be127a2..0000000
--- a/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
+++ /dev/null
@@ -1,180 +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.callfiltering;
-
-import android.content.Context;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.BlockedNumberContract;
-import android.provider.CallLog;
-import android.telecom.Log;
-import android.telecom.Logging.Session;
-import android.telecom.TelecomManager;
-
-import android.telecom.CallerInfo;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.LogUtils;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-import com.android.server.telecom.settings.BlockedNumbersUtil;
-
-/**
- * An {@link AsyncTask} that checks if a call needs to be blocked.
- * <p> An {@link AsyncTask} is used to perform the block check to avoid blocking the main thread.
- * The block check itself is performed in the {@link AsyncTask#doInBackground(Object[])}.
- */
-public class AsyncBlockCheckFilter extends AsyncTask<String, Void, Boolean>
- implements IncomingCallFilter.CallFilter {
- private final Context mContext;
- private final BlockCheckerAdapter mBlockCheckerAdapter;
- private final CallBlockListener mCallBlockListener;
- private Call mIncomingCall;
- private Session mBackgroundTaskSubsession;
- private Session mPostExecuteSubsession;
- private CallFilterResultCallback mCallback;
- private CallerInfoLookupHelper mCallerInfoLookupHelper;
- private int mBlockStatus = BlockedNumberContract.STATUS_NOT_BLOCKED;
-
- public AsyncBlockCheckFilter(Context context, BlockCheckerAdapter blockCheckerAdapter,
- CallerInfoLookupHelper callerInfoLookupHelper, CallBlockListener callBlockListener) {
- mContext = context;
- mBlockCheckerAdapter = blockCheckerAdapter;
- mCallerInfoLookupHelper = callerInfoLookupHelper;
- mCallBlockListener = callBlockListener;
- }
-
- @Override
- public void startFilterLookup(Call call, CallFilterResultCallback callback) {
- mCallback = callback;
- mIncomingCall = call;
- String number = call.getHandle() == null ?
- null : call.getHandle().getSchemeSpecificPart();
- if (BlockedNumbersUtil.isEnhancedCallBlockingEnabledByPlatform(mContext)) {
- int presentation = mIncomingCall.getHandlePresentation();
- if (presentation == TelecomManager.PRESENTATION_ALLOWED) {
- mCallerInfoLookupHelper.startLookup(call.getHandle(),
- new CallerInfoLookupHelper.OnQueryCompleteListener() {
- @Override
- public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) {
- boolean contactExists = info == null ? false : info.contactExists;
- execute(number, String.valueOf(presentation),
- String.valueOf(contactExists));
- }
-
- @Override
- public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) {
- // ignore
- }
- });
- } else {
- this.execute(number, String.valueOf(presentation));
- }
- } else {
- this.execute(number);
- }
- }
-
- @Override
- protected void onPreExecute() {
- mBackgroundTaskSubsession = Log.createSubsession();
- mPostExecuteSubsession = Log.createSubsession();
- }
-
- @Override
- protected Boolean doInBackground(String... params) {
- try {
- Log.continueSession(mBackgroundTaskSubsession, "ABCF.dIB");
- Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_INITIATED);
- Bundle extras = new Bundle();
- if (params.length > 1) {
- extras.putInt(BlockedNumberContract.EXTRA_CALL_PRESENTATION,
- Integer.valueOf(params[1]));
- }
- if (params.length > 2) {
- extras.putBoolean(BlockedNumberContract.EXTRA_CONTACT_EXIST,
- Boolean.valueOf(params[2]));
- }
- mBlockStatus = mBlockCheckerAdapter.getBlockStatus(mContext, params[0], extras);
- return mBlockStatus != BlockedNumberContract.STATUS_NOT_BLOCKED;
- } finally {
- Log.endSession();
- }
- }
-
- @Override
- protected void onPostExecute(Boolean isBlocked) {
- Log.continueSession(mPostExecuteSubsession, "ABCF.oPE");
- try {
- CallFilteringResult result;
- if (isBlocked) {
- result = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(false)
- .setCallBlockReason(convertBlockStatusToReason())
- .setCallScreeningAppName(null)
- .setCallScreeningComponentName(null)
- .build();
- if (mCallBlockListener != null) {
- String number = mIncomingCall.getHandle() == null ? null
- : mIncomingCall.getHandle().getSchemeSpecificPart();
- mCallBlockListener.onCallBlocked(mBlockStatus, number,
- mIncomingCall.getInitiatingUser());
- }
- } else {
- result = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- }
- Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_FINISHED,
- BlockedNumberContract.SystemContract.blockStatusToString(mBlockStatus) + " "
- + result);
- mCallback.onCallFilteringComplete(mIncomingCall, result);
- } finally {
- Log.endSession();
- }
- }
-
- private int convertBlockStatusToReason() {
- switch (mBlockStatus) {
- case BlockedNumberContract.STATUS_BLOCKED_IN_LIST:
- return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER;
-
- case BlockedNumberContract.STATUS_BLOCKED_UNKNOWN_NUMBER:
- return CallLog.Calls.BLOCK_REASON_UNKNOWN_NUMBER;
-
- case BlockedNumberContract.STATUS_BLOCKED_RESTRICTED:
- return CallLog.Calls.BLOCK_REASON_RESTRICTED_NUMBER;
-
- case BlockedNumberContract.STATUS_BLOCKED_PAYPHONE:
- return CallLog.Calls.BLOCK_REASON_PAY_PHONE;
-
- case BlockedNumberContract.STATUS_BLOCKED_NOT_IN_CONTACTS:
- return CallLog.Calls.BLOCK_REASON_NOT_IN_CONTACTS;
-
- default:
- Log.w(AsyncBlockCheckFilter.class.getSimpleName(),
- "There's no call log block reason can be converted");
- return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER;
- }
- }
-}
diff --git a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
index 44d5708..d95d578 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
@@ -20,6 +20,8 @@
import android.provider.CallLog.Calls;
import android.text.TextUtils;
+import java.util.Objects;
+
public class CallFilteringResult {
public static class Builder {
private boolean mShouldAllowCall;
@@ -135,8 +137,8 @@
/**
* Combine this CallFilteringResult with another, returning a CallFilteringResult with the more
* restrictive properties of the two. Where there are multiple call filtering components which
- * block a call, the first filter from {@link AsyncBlockCheckFilter},
- * {@link DirectToVoicemailCallFilter}, {@link CallScreeningServiceFilter} which blocked a call
+ * block a call, the first filter from {@link BlockCheckerFilter},
+ * {@link DirectToVoicemailFilter}, {@link CallScreeningServiceFilter} which blocked a call
* shall be used to populate the call block reason, component name, etc.
*/
public CallFilteringResult combine(CallFilteringResult other) {
@@ -230,21 +232,11 @@
if (mCallBlockReason != that.mCallBlockReason) return false;
if (contactExists != that.contactExists) return false;
- if ((TextUtils.isEmpty(mCallScreeningAppName) &&
- TextUtils.isEmpty(that.mCallScreeningAppName)) &&
- (TextUtils.isEmpty(mCallScreeningComponentName) &&
- TextUtils.isEmpty(that.mCallScreeningComponentName))) {
- return true;
- } else if (!TextUtils.isEmpty(mCallScreeningAppName) &&
- !TextUtils.isEmpty(that.mCallScreeningAppName) &&
- mCallScreeningAppName.equals(that.mCallScreeningAppName) &&
- !TextUtils.isEmpty(mCallScreeningComponentName) &&
- !TextUtils.isEmpty(that.mCallScreeningComponentName) &&
- mCallScreeningComponentName.equals(that.mCallScreeningComponentName)) {
- return true;
+ if (!Objects.equals(mCallScreeningAppName, that.mCallScreeningAppName)) return false;
+ if (!Objects.equals(mCallScreeningComponentName, that.mCallScreeningComponentName)) {
+ return false;
}
-
- return false;
+ return true;
}
@Override
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java
deleted file mode 100644
index 181ff5c..0000000
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.telecom.callfiltering;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.PersistableBundle;
-import android.provider.CallLog;
-import android.telecom.Log;
-import android.telecom.Logging.Runnable;
-import android.telecom.TelecomManager;
-import android.telephony.CarrierConfigManager;
-import android.text.TextUtils;
-
-import android.telecom.CallerInfo;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallScreeningServiceHelper;
-import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.CallsManager;
-import com.android.server.telecom.LogUtils;
-import com.android.server.telecom.ParcelableCallUtils;
-import com.android.server.telecom.PhoneAccountRegistrar;
-import com.android.server.telecom.TelecomServiceImpl;
-import com.android.server.telecom.TelecomSystem;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-
-/**
- * This class supports binding to the various {@link android.telecom.CallScreeningService}:
- * carrier, default dialer and user chosen. Carrier's CallScreeningService implementation will be
- * bound first, and then default dialer's and user chosen's. If Carrier's CallScreeningService
- * blocks a call, no further CallScreeningService after it will be bound.
- */
-public class CallScreeningServiceController implements IncomingCallFilter.CallFilter,
- CallScreeningServiceFilter.CallScreeningFilterResultCallback {
-
- private final Context mContext;
- private final CallsManager mCallsManager;
- private final PhoneAccountRegistrar mPhoneAccountRegistrar;
- private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
- private final TelecomSystem.SyncRoot mTelecomLock;
- private final TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter;
- private final CallerInfoLookupHelper mCallerInfoLookupHelper;
- private final CallScreeningServiceHelper.AppLabelProxy mAppLabelProxy;
-
- private final int CARRIER_CALL_FILTERING_TIMED_OUT = 2000; // 2 seconds
- private final int CALL_FILTERING_TIMED_OUT = 4500; // 4.5 seconds
-
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- private Call mCall;
- private CallFilterResultCallback mCallback;
-
- private CallFilteringResult mResult = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
-
- private boolean mIsFinished;
- private boolean mIsCarrierFinished;
- private boolean mIsDefaultDialerFinished;
- private boolean mIsUserChosenFinished;
-
- public CallScreeningServiceController(
- Context context,
- CallsManager callsManager,
- PhoneAccountRegistrar phoneAccountRegistrar,
- ParcelableCallUtils.Converter parcelableCallUtilsConverter,
- TelecomSystem.SyncRoot lock,
- TelecomServiceImpl.SettingsSecureAdapter settingsSecureAdapter,
- CallerInfoLookupHelper callerInfoLookupHelper,
- CallScreeningServiceHelper.AppLabelProxy appLabelProxy) {
- mContext = context;
- mCallsManager = callsManager;
- mPhoneAccountRegistrar = phoneAccountRegistrar;
- mParcelableCallUtilsConverter = parcelableCallUtilsConverter;
- mTelecomLock = lock;
- mSettingsSecureAdapter = settingsSecureAdapter;
- mCallerInfoLookupHelper = callerInfoLookupHelper;
- mAppLabelProxy = appLabelProxy;
- }
-
- @Override
- public void startFilterLookup(Call call, CallFilterResultCallback callBack) {
- mCall = call;
- mCallback = callBack;
- mIsFinished = false;
- mIsCarrierFinished = false;
- mIsDefaultDialerFinished = false;
- mIsUserChosenFinished = false;
-
- bindCarrierService();
-
- // Call screening filtering timed out
- mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) {
- @Override
- public void loggedRun() {
- if (!mIsFinished) {
- Log.i(CallScreeningServiceController.this, "Call screening has timed out.");
- finishCallScreening();
- }
- }
- }.prepare(), CALL_FILTERING_TIMED_OUT);
- }
-
- @Override
- public void onCallScreeningFilterComplete(Call call, CallFilteringResult result,
- String packageName) {
- synchronized (mTelecomLock) {
- mResult = result.combine(mResult);
- if (!TextUtils.isEmpty(packageName) && packageName.equals(getCarrierPackageName())) {
- mIsCarrierFinished = true;
- if (result.mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE) {
- finishCallScreening();
- } else {
- checkContactExistsAndBindService();
- }
- } else if (!TextUtils.isEmpty(packageName) &&
- packageName.equals(getDefaultDialerPackageName())) {
- // Default dialer defined CallScreeningService cannot skip the call log.
- mResult.shouldAddToCallLog = true;
- mIsDefaultDialerFinished = true;
- if (result.mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE ||
- mIsUserChosenFinished) {
- finishCallScreening();
- }
- } else if (!TextUtils.isEmpty(packageName) &&
- packageName.equals(getUserChosenPackageName())) {
- // User defined CallScreeningService cannot skip the call log.
- mResult.shouldAddToCallLog = true;
- mIsUserChosenFinished = true;
- if (mIsDefaultDialerFinished) {
- finishCallScreening();
- }
- }
- }
- }
-
- private void bindCarrierService() {
- String carrierPackageName = getCarrierPackageName();
- if (TextUtils.isEmpty(carrierPackageName)) {
- mIsCarrierFinished = true;
- bindDefaultDialerAndUserChosenService();
- } else {
- createCallScreeningServiceFilter().startCallScreeningFilter(mCall, this,
- carrierPackageName, mAppLabelProxy.getAppLabel(carrierPackageName),
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_CARRIER);
- }
-
- // Carrier filtering timed out
- mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) {
- @Override
- public void loggedRun() {
- if (!mIsCarrierFinished) {
- mIsCarrierFinished = true;
- checkContactExistsAndBindService();
- }
- }
- }.prepare(), CARRIER_CALL_FILTERING_TIMED_OUT);
- }
-
- private void bindDefaultDialerAndUserChosenService() {
- if (mIsCarrierFinished) {
- String dialerPackageName = getDefaultDialerPackageName();
- String systemDialerPackageName = getSystemDialerPackageName();
- if (TextUtils.isEmpty(dialerPackageName)) {
- mIsDefaultDialerFinished = true;
- } else {
- int dialerType = dialerPackageName.equals(systemDialerPackageName) ?
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_SYSTEM_DIALER :
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_DEFAULT_DIALER;
- createCallScreeningServiceFilter().startCallScreeningFilter(mCall,
- CallScreeningServiceController.this, dialerPackageName,
- mAppLabelProxy.getAppLabel(dialerPackageName), dialerType);
- }
-
- String userChosenPackageName = getUserChosenPackageName();
- if (TextUtils.isEmpty(userChosenPackageName)) {
- mIsUserChosenFinished = true;
- } else {
- // If the user chosen call screening service is the same as the default dialer, then
- // we have already bound to it above and don't need to do so again here.
- if (userChosenPackageName.equals(dialerPackageName)) {
- Log.addEvent(mCall, LogUtils.Events.SCREENING_SKIPPED,
- "user pkg same as dialer: " + userChosenPackageName);
- mIsUserChosenFinished = true;
- } else {
- createCallScreeningServiceFilter().startCallScreeningFilter(mCall,
- CallScreeningServiceController.this, userChosenPackageName,
- mAppLabelProxy.getAppLabel(userChosenPackageName),
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- }
- }
-
- if (mIsDefaultDialerFinished && mIsUserChosenFinished) {
- finishCallScreening();
- }
- }
- }
-
- private CallScreeningServiceFilter createCallScreeningServiceFilter() {
- return new CallScreeningServiceFilter(
- mContext,
- mCallsManager,
- mPhoneAccountRegistrar,
- mParcelableCallUtilsConverter,
- mTelecomLock,
- mSettingsSecureAdapter);
- }
-
- private void checkContactExistsAndBindService() {
- mCallerInfoLookupHelper.startLookup(mCall.getHandle(),
- new CallerInfoLookupHelper.OnQueryCompleteListener() {
- @Override
- public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) {
- boolean contactExists = info != null && info.contactExists;
- Log.i(CallScreeningServiceController.this, "Contact exists: " +
- contactExists);
- if (!contactExists) {
- bindDefaultDialerAndUserChosenService();
- } else {
- finishCallScreening();
- }
- }
-
- @Override
- public void onContactPhotoQueryComplete(Uri handle, CallerInfo
- info) {
- // ignore
- }
- });
- }
-
- private void finishCallScreening() {
- Log.addEvent(mCall, LogUtils.Events.CONTROLLER_SCREENING_COMPLETED, mResult);
- mCallback.onCallFilteringComplete(mCall, mResult);
- mIsFinished = true;
- }
-
- private String getCarrierPackageName() {
- ComponentName componentName = null;
- CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService
- (Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle configBundle = configManager.getConfig();
- if (configBundle != null) {
- componentName = ComponentName.unflattenFromString(configBundle.getString
- (CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, ""));
- }
-
- return componentName != null ? componentName.getPackageName() : null;
- }
-
- private String getDefaultDialerPackageName() {
- return TelecomManager.from(mContext).getDefaultDialerPackage();
- }
-
- private String getSystemDialerPackageName() {
- return TelecomManager.from(mContext).getSystemDialerPackage();
- }
-
- private String getUserChosenPackageName() {
- return mCallsManager.getRoleManagerAdapter().getDefaultCallScreeningApp();
- }
-}
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index a795f73..486cd8d 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -11,357 +11,304 @@
* 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
+ * limitations under the License.
*/
package com.android.server.telecom.callfiltering;
+import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
-import android.os.PersistableBundle;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.CallLog.Calls;
-import android.provider.Settings;
+import android.provider.CallLog;
import android.telecom.Log;
import android.telecom.TelecomManager;
-import android.telephony.CarrierConfigManager;
-import android.text.TextUtils;
import com.android.internal.telecom.ICallScreeningAdapter;
import com.android.internal.telecom.ICallScreeningService;
+import com.android.server.telecom.AppLabelProxy;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallScreeningServiceHelper;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.LogUtils;
import com.android.server.telecom.ParcelableCallUtils;
-import com.android.server.telecom.PhoneAccountRegistrar;
-import com.android.server.telecom.TelecomServiceImpl.SettingsSecureAdapter;
-import com.android.server.telecom.TelecomSystem;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-/**
- * Binds to {@link ICallScreeningService} to allow call blocking. A single instance of this class
- * handles a single call.
- */
-public class CallScreeningServiceFilter {
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
- public static final int CALL_SCREENING_FILTER_TYPE_USER_SELECTED = 1;
- public static final int CALL_SCREENING_FILTER_TYPE_DEFAULT_DIALER = 2;
- public static final int CALL_SCREENING_FILTER_TYPE_SYSTEM_DIALER = 3;
- public static final int CALL_SCREENING_FILTER_TYPE_CARRIER = 4;
+public class CallScreeningServiceFilter extends CallFilter {
+ public static final int PACKAGE_TYPE_CARRIER = 0;
+ public static final int PACKAGE_TYPE_DEFAULT_DIALER = 1;
+ public static final int PACKAGE_TYPE_USER_CHOSEN = 2;
+ public static final long CALL_SCREENING_FILTER_TIMEOUT = 5000;
- public interface CallScreeningFilterResultCallback {
- void onCallScreeningFilterComplete(Call call, CallFilteringResult result, String
- packageName);
- }
-
- private class CallScreeningServiceConnection implements ServiceConnection {
- @Override
- public void onServiceConnected(ComponentName componentName, IBinder service) {
- Log.startSession("CSCR.oSC");
- try {
- synchronized (mTelecomLock) {
- Log.addEvent(mCall, LogUtils.Events.SCREENING_BOUND, componentName);
- if (!mHasFinished) {
- onServiceBound(ICallScreeningService.Stub.asInterface(service));
- }
- }
- } finally {
- Log.endSession();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) {
- Log.startSession("CSCR.oSD");
- try {
- synchronized (mTelecomLock) {
- finishCallScreening();
- }
- } finally {
- Log.endSession();
- }
- }
- }
+ private final Call mCall;
+ private final String mPackageName;
+ private final int mPackagetype;
+ private PackageManager mPackageManager;
+ private Context mContext;
+ private CallScreeningServiceConnection mConnection;
+ private final CallsManager mCallsManager;
+ private CharSequence mAppName;
+ private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
private class CallScreeningAdapter extends ICallScreeningAdapter.Stub {
+ private CompletableFuture<CallFilteringResult> mResultFuture;
+
+ public CallScreeningAdapter(CompletableFuture<CallFilteringResult> resultFuture) {
+ mResultFuture = resultFuture;
+ }
+
@Override
public void allowCall(String callId) {
- Log.startSession("CSCR.aC");
- long token = Binder.clearCallingIdentity();
+ Long token = Binder.clearCallingIdentity();
+ Log.startSession("NCSSF.aC");
try {
- synchronized (mTelecomLock) {
- Log.d(this, "allowCall(%s)", callId);
- if (mCall != null && mCall.getId().equals(callId)) {
- mResult = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- } else {
- Log.w(this, "allowCall, unknown call id: %s", callId);
- }
- finishCallScreening();
+ 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);
} finally {
+ unbindCallScreeningService();
Binder.restoreCallingIdentity(token);
Log.endSession();
}
}
@Override
- public void disallowCall(
- String callId,
- boolean shouldReject,
- boolean shouldAddToCallLog,
- boolean shouldShowNotification,
+ public void disallowCall(String callId, boolean shouldReject,
+ boolean shouldAddToCallLog, boolean shouldShowNotification,
ComponentName componentName) {
- Log.startSession("CSCR.dC");
long token = Binder.clearCallingIdentity();
+ Log.startSession("NCSSF.dC");
try {
- synchronized (mTelecomLock) {
- boolean isServiceRequestingLogging = isLoggable(componentName,
- shouldAddToCallLog);
- Log.i(this, "disallowCall(%s), shouldReject: %b, shouldAddToCallLog: %b, "
- + "shouldShowNotification: %b", callId, shouldReject,
- isServiceRequestingLogging, shouldShowNotification);
- if (mCall != null && mCall.getId().equals(callId)) {
- mResult = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(shouldReject)
- .setShouldSilence(false)
- .setShouldAddToCallLog(isServiceRequestingLogging)
- .setShouldShowNotification(shouldShowNotification)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(mAppName)
- .setCallScreeningComponentName(componentName.flattenToString())
- .build();
- } else {
- Log.w(this, "disallowCall, unknown call id: %s", callId);
- }
- finishCallScreening();
+ if (mCall != null && mCall.getId().equals(callId)) {
+ CallFilteringResult result = new CallFilteringResult.Builder()
+ .setShouldAllowCall(false)
+ .setShouldReject(shouldReject)
+ .setShouldSilence(false)
+ .setShouldAddToCallLog(shouldAddToCallLog
+ || packageTypeShouldAdd(mPackagetype))
+ .setShouldShowNotification(shouldShowNotification)
+ .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+ .setCallScreeningAppName(mAppName)
+ .setCallScreeningComponentName(componentName.flattenToString())
+ .setContactExists(mPriorStageResult.contactExists)
+ .build();
+ Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
+ mResultFuture.complete(result);
+ } else {
+ Log.w(this, "disallowCall, unknown call id: %s", callId);
+ mResultFuture.complete(mPriorStageResult);
}
} finally {
- Binder.restoreCallingIdentity(token);
+ unbindCallScreeningService();
Log.endSession();
+ Binder.restoreCallingIdentity(token);
}
}
@Override
public void silenceCall(String callId) {
- Log.startSession("CSCR.sC");
long token = Binder.clearCallingIdentity();
+ Log.startSession("NCSSF.sC");
try {
- synchronized (mTelecomLock) {
- Log.d(this, "silenceCall(%s)", callId);
- if (mCall != null && mCall.getId().equals(callId)) {
- mResult = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- } else {
- Log.w(this, "silenceCall, unknown call id: %s", callId);
- }
- finishCallScreening();
+ if (mCall != null && mCall.getId().equals(callId)) {
+ CallFilteringResult result = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(true)
+ .setShouldAddToCallLog(true)
+ .setShouldShowNotification(true)
+ .setContactExists(mPriorStageResult.contactExists)
+ .build();
+ Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
+ mResultFuture.complete(result);
+ } else {
+ Log.w(this, "silenceCall, unknown call id: %s", callId);
+ mResultFuture.complete(mPriorStageResult);
}
} finally {
- Binder.restoreCallingIdentity(token);
+ unbindCallScreeningService();
Log.endSession();
+ Binder.restoreCallingIdentity(token);
}
}
@Override
public void screenCallFurther(String callId) {
- Log.startSession("CSCR.sCF");
+ if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
+ throw new SecurityException("Only the default/system dialer may request screen via"
+ + "background call audio");
+ }
+ // TODO: add permission check for the additional role-based permission
long token = Binder.clearCallingIdentity();
- try {
- synchronized (mTelecomLock) {
- // This is only allowed if the caller is also the default dialer.
- if (!mCallsManager.getDefaultDialerCache().isDefaultOrSystemDialer(
- mPackageName, UserHandle.USER_CURRENT)) {
- throw new SecurityException("Only the default/system dialer may request"
- + " screening via background call audio");
- }
- // TODO: add permissions check for the additional role-based permission
+ Log.startSession("NCSSF.sCF");
- Log.d(this, "screenCallFurther: %s", callId);
- if (mCall != null && mCall.getId().equals(callId)) {
- mResult = new CallFilteringResult.Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(false)
- .setShouldScreenViaAudio(true)
- .setCallScreeningAppName(mAppName)
- .build();
- } else {
- Log.w(this, "screenCallFurther, unknown call id: %s", callId);
- }
- finishCallScreening();
+ try {
+ if (mCall != null && mCall.getId().equals(callId)) {
+ CallFilteringResult result = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(false)
+ .setShouldScreenViaAudio(true)
+ .setCallScreeningAppName(mAppName)
+ .setContactExists(mPriorStageResult.contactExists)
+ .build();
+ Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, result);
+ mResultFuture.complete(result);
+ } else {
+ Log.w(this, "screenCallFurther, unknown call id: %s", callId);
+ mResultFuture.complete(mPriorStageResult);
}
} finally {
- Binder.restoreCallingIdentity(token);
+ unbindCallScreeningService();
Log.endSession();
+ Binder.restoreCallingIdentity(token);
}
}
}
- private final Context mContext;
- private final CallsManager mCallsManager;
- private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
- private final TelecomSystem.SyncRoot mTelecomLock;
- private final SettingsSecureAdapter mSettingsSecureAdapter;
+ private class CallScreeningServiceConnection implements ServiceConnection {
+ private CompletableFuture<CallFilteringResult> mResultFuture;
- private Call mCall;
- private CallScreeningFilterResultCallback mCallback;
- private ICallScreeningService mService;
- private ServiceConnection mConnection;
- private String mPackageName;
- private CharSequence mAppName;
- private boolean mHasFinished = false;
- private int mCallScreeningServiceType;
+ public CallScreeningServiceConnection(CompletableFuture<CallFilteringResult> resultFuture) {
+ mResultFuture = resultFuture;
+ }
- private CallFilteringResult mResult = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder service) {
+ ICallScreeningService callScreeningService =
+ ICallScreeningService.Stub.asInterface(service);
+ try {
+ callScreeningService.screenCall(new CallScreeningAdapter(mResultFuture),
+ mParcelableCallUtilsConverter.
+ toParcelableCallForScreening(mCall, isSystemDialer()));
+ } catch (RemoteException e) {
+ Log.e(this, e, "Failed to set the call screening adapter");
+ mResultFuture.complete(mPriorStageResult);
+ }
+ Log.addEvent(mCall, LogUtils.Events.SCREENING_BOUND, componentName);
+ Log.i(this, "Binding completed.");
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ mResultFuture.complete(mPriorStageResult);
+ Log.i(this, "Service disconnected.");
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ mResultFuture.complete(mPriorStageResult);
+ Log.i(this, "Binding died.");
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ mResultFuture.complete(mPriorStageResult);
+ Log.i(this, "Null binding.");
+ unbindCallScreeningService();
+ }
+ }
public CallScreeningServiceFilter(
+ Call call,
+ String packageName,
+ int packageType,
Context context,
CallsManager callsManager,
- PhoneAccountRegistrar phoneAccountRegistrar,
- ParcelableCallUtils.Converter parcelableCallUtilsConverter,
- TelecomSystem.SyncRoot lock,
- SettingsSecureAdapter settingsSecureAdapter) {
- mContext = context;
- mCallsManager = callsManager;
- mParcelableCallUtilsConverter = parcelableCallUtilsConverter;
- mTelecomLock = lock;
- mSettingsSecureAdapter = settingsSecureAdapter;
- }
-
- public void startCallScreeningFilter(Call call,
- CallScreeningFilterResultCallback callback,
- String packageName,
- CharSequence appName,
- int callScreeningServiceType) {
- if (mHasFinished) {
- Log.w(this, "Attempting to reuse CallScreeningServiceFilter. Ignoring.");
- return;
- }
- Log.addEvent(call, LogUtils.Events.SCREENING_SENT, packageName);
+ AppLabelProxy appLabelProxy,
+ ParcelableCallUtils.Converter parcelableCallUtilsConverter) {
+ super();
mCall = call;
- mCallback = callback;
mPackageName = packageName;
- mAppName = appName;
- mCallScreeningServiceType = callScreeningServiceType;
+ mPackagetype = packageType;
+ mContext = context;
+ mPackageManager = mContext.getPackageManager();
+ mCallsManager = callsManager;
+ mAppName = appLabelProxy.getAppLabel(mPackageName);
+ mParcelableCallUtilsConverter = parcelableCallUtilsConverter;
+ }
- mConnection = new CallScreeningServiceConnection();
+ @Override
+ public CompletionStage<CallFilteringResult> startFilterLookup(
+ CallFilteringResult priorStageResult) {
+ mPriorStageResult = priorStageResult;
+ if (mPackageName == null) {
+ return CompletableFuture.completedFuture(priorStageResult);
+ }
+
+ if (!priorStageResult.shouldAllowCall) {
+ // Call already blocked by other filters, no need to bind to call screening service.
+ return CompletableFuture.completedFuture(priorStageResult);
+ }
+
+ if (priorStageResult.contactExists && (!hasReadContactsPermission())) {
+ // Binding to the call screening service will be skipped if it does NOT hold
+ // READ_CONTACTS permission and the number is in the user’s contacts
+ return CompletableFuture.completedFuture(priorStageResult);
+ }
+
+ CompletableFuture<CallFilteringResult> resultFuture = new CompletableFuture<>();
+
+ bindCallScreeningService(resultFuture);
+ return resultFuture;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ": " + mPackageName;
+ }
+
+ private boolean hasReadContactsPermission() {
+ int permission = PackageManager.PERMISSION_DENIED;
+ if (mPackagetype == PACKAGE_TYPE_CARRIER || mPackagetype == PACKAGE_TYPE_DEFAULT_DIALER) {
+ permission = PackageManager.PERMISSION_GRANTED;
+ } else if (mPackageManager != null) {
+ permission = mPackageManager.checkPermission(Manifest.permission.READ_CONTACTS,
+ mPackageName);
+ }
+ return permission == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private void bindCallScreeningService(
+ CompletableFuture<CallFilteringResult> resultFuture) {
+ mConnection = new CallScreeningServiceConnection(resultFuture);
if (!CallScreeningServiceHelper.bindCallScreeningService(mContext,
- mCallsManager.getCurrentUserHandle(),
- mPackageName,
- mConnection)) {
- Log.i(this, "Could not bind to call screening service");
- finishCallScreening();
+ mCallsManager.getCurrentUserHandle(), mPackageName, mConnection)) {
+ Log.i(this, "Call screening service binding failed.");
+ resultFuture.complete(mPriorStageResult);
}
}
- private void finishCallScreening() {
- if (!mHasFinished) {
- Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, mResult);
- mCallback.onCallScreeningFilterComplete(mCall, mResult, mPackageName);
-
- if (mConnection != null) {
- // We still need to call unbind even if the service disconnected.
- try {
- mContext.unbindService(mConnection);
- } catch (IllegalArgumentException ie) {
- Log.e(this, ie, "Unbind error");
- }
- mConnection = null;
+ public void unbindCallScreeningService() {
+ if (mConnection != null) {
+ try {
+ mContext.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ Log.i(this, "Exception when unbind service %s : %s", mConnection,
+ e.getMessage());
}
- mService = null;
- mHasFinished = true;
+ }
+ mConnection = null;
+ }
+
+ private boolean isSystemDialer() {
+ if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
+ return false;
+ } else {
+ return mPackageName.equals(
+ mContext.getSystemService(TelecomManager.class).getSystemDialerPackage());
}
}
- private void onServiceBound(ICallScreeningService service) {
- mService = service;
- try {
- boolean isSystemDialer =
- mCallScreeningServiceType
- == CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_SYSTEM_DIALER;
- // Important: Only send a minimal subset of the call to the screening service.
- // We will send some of the call extras to the call screening service which the system
- // dialer implements.
- mService.screenCall(new CallScreeningAdapter(),
- mParcelableCallUtilsConverter.toParcelableCallForScreening(mCall,
- isSystemDialer));
- } catch (RemoteException e) {
- Log.e(this, e, "Failed to set the call screening adapter.");
- finishCallScreening();
- }
- }
-
- private boolean isLoggable(ComponentName componentName, boolean shouldAddToCallLog) {
- if (isCarrierCallScreeningApp(componentName)) {
- return shouldAddToCallLog;
- } else if (isDefaultDialer(componentName) || isUserChosenCallScreeningApp(componentName)) {
- return true;
- }
-
- return shouldAddToCallLog;
- }
-
- private boolean isCarrierCallScreeningApp(ComponentName componentName) {
- String carrierCallScreeningApp = null;
- CarrierConfigManager configManager = (CarrierConfigManager) mContext
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle configBundle = configManager.getConfig();
- if (configBundle != null) {
- carrierCallScreeningApp = configBundle
- .getString(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING);
- }
-
- if (!TextUtils.isEmpty(carrierCallScreeningApp) && carrierCallScreeningApp
- .equals(componentName.flattenToString())) {
- return true;
- }
-
- return false;
- }
-
- private boolean isDefaultDialer(ComponentName componentName) {
- String defaultDialer = TelecomManager.from(mContext).getDefaultDialerPackage();
-
- if (!TextUtils.isEmpty(defaultDialer) && defaultDialer
- .equals(componentName.getPackageName())) {
- return true;
- }
-
- return false;
- }
-
- private boolean isUserChosenCallScreeningApp(ComponentName componentName) {
- String defaultCallScreeningApplication = mSettingsSecureAdapter
- .getStringForUser(mContext.getContentResolver(),
- Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT, UserHandle.USER_CURRENT);
-
- if (!TextUtils.isEmpty(defaultCallScreeningApplication) && defaultCallScreeningApplication
- .equals(componentName.flattenToString())) {
- return true;
- }
-
- return false;
+ private boolean packageTypeShouldAdd(int packageType) {
+ return packageType != PACKAGE_TYPE_CARRIER;
}
}
diff --git a/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java b/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
deleted file mode 100644
index 71cb3e4..0000000
--- a/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
+++ /dev/null
@@ -1,89 +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.callfiltering;
-
-import android.net.Uri;
-import android.provider.CallLog.Calls;
-import android.telecom.Log;
-
-import android.telecom.CallerInfo;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.LogUtils;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-
-import java.util.Objects;
-
-public class DirectToVoicemailCallFilter implements IncomingCallFilter.CallFilter {
- private final CallerInfoLookupHelper mCallerInfoLookupHelper;
-
- public DirectToVoicemailCallFilter(CallerInfoLookupHelper callerInfoLookupHelper) {
- mCallerInfoLookupHelper = callerInfoLookupHelper;
- }
-
- @Override
- public void startFilterLookup(final Call call, CallFilterResultCallback callback) {
- Log.addEvent(call, LogUtils.Events.DIRECT_TO_VM_INITIATED);
- final Uri callHandle = call.getHandle();
-
- mCallerInfoLookupHelper.startLookup(callHandle,
- new CallerInfoLookupHelper.OnQueryCompleteListener() {
- @Override
- public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) {
- CallFilteringResult result;
- if ((handle != null) && Objects.equals(callHandle, handle)) {
- if (info != null && info.shouldSendToVoicemail) {
- result = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL)
- .setCallScreeningAppName(null)
- .setCallScreeningComponentName(null)
- .build();
- } else {
- result = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- }
- Log.addEvent(call, LogUtils.Events.DIRECT_TO_VM_FINISHED, result);
- callback.onCallFilteringComplete(call, result);
- } else {
- result = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- Log.addEvent(call, LogUtils.Events.DIRECT_TO_VM_FINISHED, result);
- Log.w(this, "CallerInfo lookup returned with a different handle than " +
- "what was passed in. Was %s, should be %s", handle, callHandle);
- callback.onCallFilteringComplete(call, result);
- }
- }
-
- @Override
- public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) {
- // ignore
- }
- });
- }
-}
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
index 03d27bd..1543270 100644
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
+++ b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
@@ -126,6 +126,12 @@
mFinished = true;
mHandlerThread.quit();
}
+ for (CallFilter filter : mFiltersList) {
+ // unbind timed out call screening service
+ if (filter instanceof CallScreeningServiceFilter) {
+ ((CallScreeningServiceFilter) filter).unbindCallScreeningService();
+ }
+ }
}
}.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
}
@@ -148,6 +154,8 @@
CompletableFuture.completedFuture(input);
PostFilterTask postFilterTask = new PostFilterTask(filter);
+ // TODO: improve these filter logging names to be more reflective of the filters that are
+ // executing
startFuture.thenComposeAsync(filter::startFilterLookup,
new LoggedHandlerExecutor(mHandler, "ICFG.sF", null))
.thenApplyAsync(postFilterTask::whenDone,
diff --git a/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java
deleted file mode 100644
index 80996e5..0000000
--- a/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * 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.callfiltering;
-
-import android.Manifest;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.provider.CallLog;
-import android.telecom.Log;
-import android.telecom.TelecomManager;
-
-import com.android.internal.telecom.ICallScreeningAdapter;
-import com.android.internal.telecom.ICallScreeningService;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallScreeningServiceHelper;
-import com.android.server.telecom.CallsManager;
-import com.android.server.telecom.ParcelableCallUtils;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-
-public class NewCallScreeningServiceFilter extends CallFilter {
- //TODO: Change the name of this class with CallScreeningServiceFilter
- public static final int PACKAGE_TYPE_CARRIER = 0;
- public static final int PACKAGE_TYPE_DEFAULT_DIALER = 1;
- public static final int PACKAGE_TYPE_USER_CHOSEN = 2;
- public static final long CALL_SCREENING_FILTER_TIMEOUT = 5000;
-
- private final Call mCall;
- private final String mPackageName;
- private final int mPackagetype;
- private PackageManager mPackageManager;
- private Context mContext;
- private CallScreeningServiceConnection mConnection;
- private final CallsManager mCallsManager;
- private CharSequence mAppName;
- private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
-
- private class CallScreeningAdapter extends ICallScreeningAdapter.Stub {
- private CompletableFuture<CallFilteringResult> mResultFuture;
-
- public CallScreeningAdapter(CompletableFuture<CallFilteringResult> resultFuture) {
- mResultFuture = resultFuture;
- }
-
- @Override
- public void allowCall(String callId) {
- Long token = Binder.clearCallingIdentity();
- if (mCall == null || (!mCall.getId().equals(callId))) {
- Log.w(this, "allowCall, unknown call id: %s", callId);
- }
- mResultFuture.complete(mPriorStageResult);
- Binder.restoreCallingIdentity(token);
- unbindCallScreeningService();
- }
-
- @Override
- public void disallowCall(String callId, boolean shouldReject,
- boolean shouldAddToCallLog, boolean shouldShowNotification,
- ComponentName componentName) {
- long token = Binder.clearCallingIdentity();
- if (mCall != null && mCall.getId().equals(callId)) {
- mResultFuture.complete(new CallFilteringResult.Builder()
- .setShouldAllowCall(false)
- .setShouldReject(shouldReject)
- .setShouldSilence(false)
- .setShouldAddToCallLog(shouldAddToCallLog
- || packageTypeShouldAdd(mPackagetype))
- .setShouldShowNotification(shouldShowNotification)
- .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(mAppName)
- .setCallScreeningComponentName(componentName.flattenToString())
- .setContactExists(mPriorStageResult.contactExists)
- .build());
- } else {
- Log.w(this, "disallowCall, unknown call id: %s", callId);
- mResultFuture.complete(mPriorStageResult);
- }
- Binder.restoreCallingIdentity(token);
- unbindCallScreeningService();
- }
-
- @Override
- public void silenceCall(String callId) {
- long token = Binder.clearCallingIdentity();
- if (mCall != null && mCall.getId().equals(callId)) {
- mResultFuture.complete(new CallFilteringResult.Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setContactExists(mPriorStageResult.contactExists)
- .build());
- } else {
- Log.w(this, "silenceCall, unknown call id: %s" , callId);
- mResultFuture.complete(mPriorStageResult);
- }
- Binder.restoreCallingIdentity(token);
- unbindCallScreeningService();
- }
-
- @Override
- public void screenCallFurther(String callId) {
- long token = Binder.clearCallingIdentity();
- if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
- throw new SecurityException("Only the default/system dialer may request screen via"
- + "background call audio");
- }
- // TODO: add permission check for the additional role-based permission
-
- if (mCall != null && mCall.getId().equals(callId)) {
- mResultFuture.complete(new CallFilteringResult.Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(false)
- .setShouldScreenViaAudio(true)
- .setContactExists(mPriorStageResult.contactExists)
- .build());
- } else {
- Log.w(this, "screenCallFurther, unknown call id: %s", callId);
- mResultFuture.complete(mPriorStageResult);
- }
- Binder.restoreCallingIdentity(token);
- unbindCallScreeningService();
- }
- }
-
- private class CallScreeningServiceConnection implements ServiceConnection {
- private CompletableFuture<CallFilteringResult> mResultFuture;
-
- public CallScreeningServiceConnection(CompletableFuture<CallFilteringResult> resultFuture) {
- mResultFuture = resultFuture;
- }
-
- @Override
- public void onServiceConnected(ComponentName componentName, IBinder service) {
- ICallScreeningService callScreeningService =
- ICallScreeningService.Stub.asInterface(service);
-
- try {
- callScreeningService.screenCall(new CallScreeningAdapter(mResultFuture),
- mParcelableCallUtilsConverter.
- toParcelableCallForScreening(mCall, isSystemDialer()));
- } catch (RemoteException e) {
- Log.e(this, e, "Failed to set the call screening adapter");
- mResultFuture.complete(mPriorStageResult);
- }
- Log.i(this, "Binding completed.");
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) {
- mResultFuture.complete(mPriorStageResult);
- Log.i(this, "Service disconnected.");
- }
-
- @Override
- public void onBindingDied(ComponentName name) {
- mResultFuture.complete(mPriorStageResult);
- Log.i(this, "Binding died.");
- }
-
- @Override
- public void onNullBinding(ComponentName name) {
- mResultFuture.complete(mPriorStageResult);
- Log.i(this, "Null binding.");
- }
- }
-
- public NewCallScreeningServiceFilter(
- Call call,
- String packageName,
- int packageType,
- Context context,
- CallsManager callsManager,
- CallScreeningServiceHelper.AppLabelProxy appLabelProxy,
- ParcelableCallUtils.Converter parcelableCallUtilsConverter) {
- super();
- mCall = call;
- mPackageName = packageName;
- mPackagetype = packageType;
- mContext = context;
- mPackageManager = mContext.getPackageManager();
- mCallsManager = callsManager;
- mAppName = appLabelProxy.getAppLabel(mPackageName);
- mParcelableCallUtilsConverter = parcelableCallUtilsConverter;
- }
-
- @Override
- public CompletionStage<CallFilteringResult> startFilterLookup(
- CallFilteringResult priorStageResult) {
- mPriorStageResult = priorStageResult;
- if (mPackageName == null) {
- return CompletableFuture.completedFuture(priorStageResult);
- }
-
- if (!priorStageResult.shouldAllowCall) {
- // Call already blocked by other filters, no need to bind to call screening service.
- return CompletableFuture.completedFuture(priorStageResult);
- }
-
- if (priorStageResult.contactExists && (!hasReadContactsPermission())) {
- // Binding to the call screening service will be skipped if it does NOT hold
- // READ_CONTACTS permission and the number is in the user’s contacts
- return CompletableFuture.completedFuture(priorStageResult);
- }
-
- CompletableFuture<CallFilteringResult> resultFuture = new CompletableFuture<>();
-
- bindCallScreeningService(resultFuture);
- return resultFuture;
- }
-
- private boolean hasReadContactsPermission() {
- int permission = PackageManager.PERMISSION_DENIED;
- if (mPackagetype == PACKAGE_TYPE_CARRIER || mPackagetype == PACKAGE_TYPE_DEFAULT_DIALER) {
- permission = PackageManager.PERMISSION_GRANTED;
- } else if (mPackageManager != null) {
- permission = mPackageManager.checkPermission(Manifest.permission.READ_CONTACTS,
- mPackageName);
- }
- return permission == PackageManager.PERMISSION_GRANTED;
- }
-
- private void bindCallScreeningService(
- CompletableFuture<CallFilteringResult> resultFuture) {
- mConnection = new CallScreeningServiceConnection(resultFuture);
- if (!CallScreeningServiceHelper.bindCallScreeningService(mContext,
- mCallsManager.getCurrentUserHandle(), mPackageName, mConnection)) {
- Log.i(this, "Call screening service binding failed.");
- resultFuture.complete(mPriorStageResult);
- }
- }
-
- private void unbindCallScreeningService() {
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- }
- mConnection = null;
- }
-
- private boolean isSystemDialer() {
- if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
- return false;
- } else {
- return mPackageName.equals(TelecomManager.from(mContext).getSystemDialerPackage());
- }
- }
-
- private boolean packageTypeShouldAdd(int packageType) {
- return packageType != PACKAGE_TYPE_CARRIER;
- }
-}
diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
index 7a54118..e93ef22 100644
--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
+++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
@@ -196,7 +196,7 @@
synchronized (mTelecomLock) {
mRedirectionGatewayInfo = mCallRedirectionProcessorHelper
.getGatewayInfoFromGatewayUri(mComponentName.getPackageName(),
- gatewayUri, mDestinationUri);
+ gatewayUri, mDestinationUri, mPostDialDigits);
mPhoneAccountHandle = targetPhoneAccount;
// If carrier redirects call, we should skip to notify users about
// the user-defined call redirection service.
@@ -247,6 +247,12 @@
private Uri mProcessedDestinationUri;
/**
+ * The post dial digits which were removed from {@link #mDestinationUri} when determining
+ * {@link #mProcessedDestinationUri}.
+ */
+ private String mPostDialDigits;
+
+ /**
* Indicates if Telecom should cancel the call when the whole call redirection finishes.
*/
private boolean mShouldCancelCall = false;
@@ -293,6 +299,7 @@
context, callsManager, phoneAccountRegistrar);
mProcessedDestinationUri = mCallRedirectionProcessorHelper.formatNumberForRedirection(
mDestinationUri);
+ mPostDialDigits = mCallRedirectionProcessorHelper.getPostDialDigits(mDestinationUri);
}
@Override
diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessorHelper.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessorHelper.java
index 4126da0..9771d65 100644
--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessorHelper.java
+++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessorHelper.java
@@ -129,6 +129,18 @@
return removePostDialDigits(formatNumberToE164(handle));
}
+ /**
+ * Extras the post dial digits from a given handle.
+ * @param handle The handle
+ * @return The post dial digits.
+ */
+ public String getPostDialDigits(Uri handle) {
+ if (handle == null) {
+ return "";
+ }
+ return PhoneNumberUtils.extractPostDialPortion(handle.getSchemeSpecificPart());
+ }
+
protected Uri formatNumberToE164(Uri handle) {
String number = handle.getSchemeSpecificPart();
@@ -163,10 +175,17 @@
}
}
- protected GatewayInfo getGatewayInfoFromGatewayUri(
- String gatewayPackageName, Uri gatewayUri, Uri destinationUri) {
+ public static GatewayInfo getGatewayInfoFromGatewayUri(
+ String gatewayPackageName, Uri gatewayUri, Uri destinationUri, String postdialDigits) {
if (!TextUtils.isEmpty(gatewayPackageName) && gatewayUri != null) {
- return new GatewayInfo(gatewayPackageName, gatewayUri, destinationUri);
+ Uri gatewayWithPostdial = gatewayUri;
+ if (gatewayUri != null && !TextUtils.isEmpty(postdialDigits)) {
+ gatewayWithPostdial = new Uri.Builder()
+ .scheme(gatewayUri.getScheme())
+ .encodedOpaquePart(gatewayUri.getSchemeSpecificPart() + postdialDigits)
+ .build();
+ }
+ return new GatewayInfo(gatewayPackageName, gatewayWithPostdial, destinationUri);
}
return null;
}
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index e20da80..b6705f4 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -30,6 +30,10 @@
import android.telecom.Log;
import android.telecom.CallerInfoAsyncQuery;
+
+import com.android.internal.telecom.IInternalServiceRetriever;
+import com.android.internal.telecom.ITelecomLoader;
+import com.android.internal.telecom.ITelecomService;
import com.android.server.telecom.AsyncRingtonePlayer;
import com.android.server.telecom.BluetoothAdapterProxy;
import com.android.server.telecom.BluetoothPhoneServiceImpl;
@@ -41,16 +45,17 @@
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ContactsAsyncHelper;
import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
import com.android.server.telecom.HeadsetMediaButton;
import com.android.server.telecom.HeadsetMediaButtonFactory;
import com.android.server.telecom.InCallWakeLockControllerFactory;
import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.InternalServiceRetrieverAdapter;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
import com.android.server.telecom.ProximitySensorManagerFactory;
import com.android.server.telecom.InCallWakeLockController;
import com.android.server.telecom.ProximitySensorManager;
-import com.android.server.telecom.R;
import com.android.server.telecom.RoleManagerAdapterImpl;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.TelecomWakeLock;
@@ -68,10 +73,17 @@
@Override
public IBinder onBind(Intent intent) {
Log.d(this, "onBind");
- initializeTelecomSystem(this);
- synchronized (getTelecomSystem().getLock()) {
- return getTelecomSystem().getTelecomServiceImpl().getBinder();
- }
+ return new ITelecomLoader.Stub() {
+ @Override
+ public ITelecomService createTelecomService(IInternalServiceRetriever retriever) {
+ InternalServiceRetrieverAdapter adapter =
+ new InternalServiceRetrieverAdapter(retriever);
+ initializeTelecomSystem(TelecomService.this, adapter);
+ synchronized (getTelecomSystem().getLock()) {
+ return getTelecomSystem().getTelecomServiceImpl().getBinder();
+ }
+ }
+ };
}
/**
@@ -84,7 +96,8 @@
*
* @param context
*/
- static void initializeTelecomSystem(Context context) {
+ static void initializeTelecomSystem(Context context,
+ InternalServiceRetrieverAdapter internalServiceRetriever) {
if (TelecomSystem.getInstance() == null) {
NotificationChannelManager notificationChannelManager =
new NotificationChannelManager();
@@ -98,9 +111,11 @@
public MissedCallNotifierImpl makeMissedCallNotifierImpl(
Context context,
PhoneAccountRegistrar phoneAccountRegistrar,
- DefaultDialerCache defaultDialerCache) {
+ DefaultDialerCache defaultDialerCache,
+ DeviceIdleControllerAdapter idleControllerAdapter) {
return new MissedCallNotifierImpl(context,
- phoneAccountRegistrar, defaultDialerCache);
+ phoneAccountRegistrar, defaultDialerCache,
+ idleControllerAdapter);
}
},
new CallerInfoAsyncQueryFactory() {
@@ -191,7 +206,8 @@
new RoleManagerAdapterImpl(context,
(RoleManager) context.getSystemService(Context.ROLE_SERVICE)),
new IncomingCallFilter.Factory(),
- new ContactsAsyncHelper.Factory()));
+ new ContactsAsyncHelper.Factory(),
+ internalServiceRetriever.getDeviceIdleController()));
}
if (BluetoothAdapter.getDefaultAdapter() != null) {
context.startService(new Intent(context, BluetoothPhoneService.class));
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
index 1593e23..1fe7c5f 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
@@ -19,6 +19,7 @@
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;
@@ -34,9 +35,12 @@
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.view.LayoutInflater;
@@ -54,6 +58,7 @@
import com.android.server.telecom.R;
+
/**
* Activity to manage blocked numbers using {@link BlockedNumberContract}.
*/
@@ -79,6 +84,7 @@
private ProgressBar mProgressBar;
private RelativeLayout mButterBar;
@Nullable private Button mBlockButton;
+ @Nullable private Button mBlockButtonNegative;
private TextView mReEnableButton;
private BroadcastReceiver mBlockingStatusReceiver;
@@ -260,6 +266,10 @@
public void onShow(DialogInterface dialog) {
mBlockButton = ((AlertDialog) dialog)
.getButton(AlertDialog.BUTTON_POSITIVE);
+ mBlockButtonNegative = ((AlertDialog) dialog)
+ .getButton(AlertDialog.BUTTON_NEGATIVE);
+ mBlockButton.setAllCaps(false);
+ mBlockButtonNegative.setAllCaps(false);
mBlockButton.setEnabled(false);
// show keyboard
InputMethodManager inputMethodManager =
@@ -276,7 +286,7 @@
* Add blocked number if it does not exist.
*/
private void addBlockedNumber(String number) {
- if (PhoneNumberUtils.isEmergencyNumber(number)) {
+ if (isEmergencyNumber(this, number)) {
Toast.makeText(
this,
getString(R.string.blocked_numbers_block_emergency_number_message),
@@ -289,6 +299,16 @@
}
}
+ private boolean isEmergencyNumber(Context context, String number) {
+ try {
+ TelephonyManager tm = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return tm.isEmergencyNumber(number);
+ } catch (IllegalStateException ise) {
+ return false;
+ }
+ }
+
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// no-op
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
index 1278a4b..df68f6e 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
@@ -28,6 +28,7 @@
import android.view.View;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
+
import com.android.server.telecom.R;
public class BlockedNumbersAdapter extends SimpleCursorAdapter {
@@ -42,10 +43,18 @@
final String rawNumber = cursor.getString(cursor.getColumnIndex(
BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER));
final String formattedNumber = BlockedNumbersUtil.formatNumber(rawNumber);
- TextView numberView = (TextView) view.findViewById(R.id.blocked_number);
- Spannable numberSpannable = new SpannableString(formattedNumber);
- PhoneNumberUtils.addTtsSpan(numberSpannable, 0, numberSpannable.length());
- numberView.setText(numberSpannable);
+ TextView textView = (TextView) view.findViewById(R.id.blocked_number);
+
+ if (formattedNumber != null
+ && formattedNumber.contains("@") || formattedNumber.contains("%40")) {
+ // An email address
+ textView.setText(formattedNumber);
+ } else {
+ // A phone number
+ Spannable numberSpannable = new SpannableString(formattedNumber);
+ PhoneNumberUtils.addTtsSpan(numberSpannable, 0, numberSpannable.length());
+ textView.setText(numberSpannable);
+ }
View deleteButton = view.findViewById(R.id.delete_blocked_number);
deleteButton.setOnClickListener(new View.OnClickListener() {
@@ -63,7 +72,7 @@
Spannable messageSpannable = new SpannableString(message);
PhoneNumberUtils.addTtsSpan(messageSpannable, startingPosition,
startingPosition + formattedNumber.length());
- new AlertDialog.Builder(context)
+ AlertDialog dialog = new AlertDialog.Builder(context)
.setMessage(messageSpannable)
.setPositiveButton(R.string.unblock_button,
new DialogInterface.OnClickListener() {
@@ -79,8 +88,15 @@
}
}
)
- .create()
- .show();
+ .create();
+ dialog.setOnShowListener(new AlertDialog.OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialog) {
+ ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE).setAllCaps(false);
+ ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEGATIVE).setAllCaps(false);
+ }
+ });
+ dialog.show();
}
private void deleteBlockedNumber(Context context, String number) {
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
index 5acfe64..67634e4 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
@@ -108,7 +108,7 @@
.setContentText(message)
.setContentIntent(pendingIntent)
.setShowWhen(true)
- .setChannel(NotificationChannelManager.CHANNEL_ID_CALL_BLOCKING)
+ .setChannelId(NotificationChannelManager.CHANNEL_ID_CALL_BLOCKING)
.build();
notification.flags |= Notification.FLAG_NO_CLEAR;
diff --git a/src/com/android/server/telecom/ui/CallRedirectionConfirmDialogActivity.java b/src/com/android/server/telecom/ui/CallRedirectionConfirmDialogActivity.java
deleted file mode 100644
index 0d3599e..0000000
--- a/src/com/android/server/telecom/ui/CallRedirectionConfirmDialogActivity.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.ui;
-
-import com.android.server.telecom.R;
-import com.android.server.telecom.TelecomBroadcastIntentProcessor;
-import com.android.server.telecom.components.TelecomBroadcastReceiver;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Bundle;
-import android.telecom.Log;
-import android.view.LayoutInflater;
-import android.view.View.OnClickListener;
-import android.view.View;
-import android.widget.Button;
-
-/**
- * Dialog activity used when there is an ongoing call redirected by the call redirection service.
- * The dialog prompts the user to see if they want to place the redirected outgoing call.
- */
-public class CallRedirectionConfirmDialogActivity extends Activity {
- public static final String EXTRA_REDIRECTION_OUTGOING_CALL_ID =
- "android.telecom.extra.REDIRECTION_OUTGOING_CALL_ID";
- public static final String EXTRA_REDIRECTION_APP_NAME =
- "android.telecom.extra.REDIRECTION_APP_NAME";
-
- private String mCallId;
- private AlertDialog mConfirmDialog;
- /**
- * Tracks whether the activity has stopped due to a loss of focus (e.g. use hitting the home
- * button) or whether its going to stop because a button in the dialog was pressed.
- */
- private boolean mHasLostFocus = true;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.i(this, "CallRedirectionConfirmDialogActivity onCreate.");
- final CharSequence redirectionAppName = getIntent().getStringExtra(
- EXTRA_REDIRECTION_APP_NAME);
- mCallId = getIntent().getStringExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID);
- showDialog(redirectionAppName);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (mHasLostFocus) {
- Log.i(this, "onStop: dialog lost focus; canceling redirection for call %s", mCallId);
- mConfirmDialog.dismiss();
- cancelRedirection();
- }
- }
-
- private void showDialog(final CharSequence redirectionAppName) {
- Log.i(this, "showDialog: confirming redirection with %s", redirectionAppName);
-
- mConfirmDialog = new AlertDialog.Builder(this).create();
- LayoutInflater layoutInflater = LayoutInflater.from(this);
- View dialogView = layoutInflater.inflate(R.layout.call_redirection_confirm_dialog, null);
-
- Button buttonFirstLine = (Button) dialogView.findViewById(R.id.buttonFirstLine);
- buttonFirstLine.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent proceedWithoutRedirectedCall = new Intent(
- TelecomBroadcastIntentProcessor.ACTION_PLACE_UNREDIRECTED_CALL,
- null, CallRedirectionConfirmDialogActivity.this,
- TelecomBroadcastReceiver.class);
- proceedWithoutRedirectedCall.putExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID, mCallId);
- sendBroadcast(proceedWithoutRedirectedCall);
- mConfirmDialog.dismiss();
- mHasLostFocus = false;
- finish();
- }
- });
-
- Button buttonSecondLine = (Button) dialogView.findViewById(R.id.buttonSecondLine);
- buttonSecondLine.setText(getString(R.string.alert_place_outgoing_call_with_redirection,
- redirectionAppName));
- buttonSecondLine.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent proceedWithRedirectedCall = new Intent(
- TelecomBroadcastIntentProcessor
- .ACTION_PLACE_REDIRECTED_CALL, null,
- CallRedirectionConfirmDialogActivity.this,
- TelecomBroadcastReceiver.class);
- proceedWithRedirectedCall.putExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID, mCallId);
- sendBroadcast(proceedWithRedirectedCall);
- mConfirmDialog.dismiss();
- mHasLostFocus = false;
- finish();
- }
- });
-
- Button buttonThirdLine = (Button) dialogView.findViewById(R.id.buttonThirdLine);
- buttonThirdLine.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- Intent cancelRedirectedCall = new Intent(
- TelecomBroadcastIntentProcessor.ACTION_CANCEL_REDIRECTED_CALL,
- null, CallRedirectionConfirmDialogActivity.this,
- TelecomBroadcastReceiver.class);
- cancelRedirectedCall.putExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID, mCallId);
- sendBroadcast(cancelRedirectedCall);
- mConfirmDialog.dismiss();
- mHasLostFocus = false;
- finish();
- }
- });
-
- mConfirmDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- cancelRedirection();
- dialog.dismiss();
- mHasLostFocus = false;
- finish();
- }
- });
-
- mConfirmDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
-
- mConfirmDialog.setCancelable(false);
- mConfirmDialog.setCanceledOnTouchOutside(false);
- mConfirmDialog.setView(dialogView);
-
- mConfirmDialog.show();
- }
-
- /**
- * Signals to Telecom that redirection of the call is to be cancelled.
- */
- private void cancelRedirection() {
- Intent cancelRedirectedCall = new Intent(
- TelecomBroadcastIntentProcessor.ACTION_CANCEL_REDIRECTED_CALL,
- null, CallRedirectionConfirmDialogActivity.this,
- TelecomBroadcastReceiver.class);
- cancelRedirectedCall.putExtra(EXTRA_REDIRECTION_OUTGOING_CALL_ID, mCallId);
- sendBroadcast(cancelRedirectedCall);
- }
-}
diff --git a/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java b/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java
index aa05552..3f54689 100644
--- a/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java
+++ b/src/com/android/server/telecom/ui/DisconnectedCallNotifier.java
@@ -78,15 +78,17 @@
public final Bitmap callerInfoIcon;
public final Drawable callerInfoPhoto;
public final String callerInfoName;
+ public final boolean isEmergency;
public CallInfo(UserHandle userHandle, Uri handle, long endTimeMs, Bitmap callerInfoIcon,
- Drawable callerInfoPhoto, String callerInfoName) {
+ Drawable callerInfoPhoto, String callerInfoName, boolean isEmergency) {
this.userHandle = userHandle;
this.handle = handle;
this.endTimeMs = endTimeMs;
this.callerInfoIcon = callerInfoIcon;
this.callerInfoPhoto = callerInfoPhoto;
this.callerInfoName = callerInfoName;
+ this.isEmergency = isEmergency;
}
@Override
@@ -94,6 +96,7 @@
return "CallInfo{" +
"userHandle=" + userHandle +
", handle=" + handle +
+ ", isEmergency=" + isEmergency +
", endTimeMs=" + endTimeMs +
", callerInfoIcon=" + callerInfoIcon +
", callerInfoPhoto=" + callerInfoPhoto +
@@ -146,7 +149,7 @@
if (userHandle == null) userHandle = mCallsManager.getCurrentUserHandle();
mPendingCallNotification = new CallInfo(userHandle, call.getHandle(),
call.getCreationTimeMillis() + call.getAgeMillis(), call.getPhotoIcon(),
- call.getPhoto(), call.getName());
+ call.getPhoto(), call.getName(), call.isEmergencyCall());
}
}
@@ -154,8 +157,10 @@
Log.i(this, "showDisconnectedNotification: userHandle=%d", call.userHandle.getIdentifier());
final int titleResId = R.string.notification_disconnectedCall_title;
- final String expandedText = mContext.getString(R.string.notification_disconnectedCall_body,
- getNameForCallNotification(call));
+ final CharSequence expandedText = call.isEmergency
+ ? mContext.getText(R.string.notification_disconnectedCall_generic_body)
+ : mContext.getString(R.string.notification_disconnectedCall_body,
+ getNameForCallNotification(call));
// Create a public viewable version of the notification, suitable for display when sensitive
// notification content is hidden.
@@ -173,9 +178,12 @@
// Notification details shows that there are disconnected call(s), but does not
// reveal the caller information.
.setContentText(mContext.getText(titleResId))
- .setContentIntent(createCallLogPendingIntent(call.userHandle))
.setAutoCancel(true);
+ if (!call.isEmergency) {
+ publicBuilder.setContentIntent(createCallLogPendingIntent(call.userHandle));
+ }
+
// Create the notification suitable for display when sensitive information is showing.
Notification.Builder builder = new Notification.Builder(contextForUser,
NotificationChannelManager.CHANNEL_ID_DISCONNECTED_CALLS);
@@ -186,7 +194,6 @@
.setContentTitle(mContext.getText(titleResId))
//Only show expanded text for sensitive information
.setStyle(new Notification.BigTextStyle().bigText(expandedText))
- .setContentIntent(createCallLogPendingIntent(call.userHandle))
.setAutoCancel(true)
// Include a public version of the notification to be shown when the call
// notification is shown on the user's lock screen and they have chosen to hide
@@ -194,10 +201,15 @@
.setPublicVersion(publicBuilder.build())
.setChannelId(NotificationChannelManager.CHANNEL_ID_DISCONNECTED_CALLS);
+ if (!call.isEmergency) {
+ builder.setContentIntent(createCallLogPendingIntent(call.userHandle));
+ }
+
String handle = call.handle != null ? call.handle.getSchemeSpecificPart() : null;
if (!TextUtils.isEmpty(handle)
- && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))) {
+ && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))
+ && !call.isEmergency) {
builder.addAction(new Notification.Action.Builder(
Icon.createWithResource(contextForUser, R.drawable.ic_phone_24dp),
// Reuse missed call "Call back"
diff --git a/src/com/android/server/telecom/ui/IncomingCallNotifier.java b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
index 6e203aa..edea89b 100644
--- a/src/com/android/server/telecom/ui/IncomingCallNotifier.java
+++ b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
@@ -41,6 +41,7 @@
import com.android.server.telecom.TelecomBroadcastIntentProcessor;
import com.android.server.telecom.components.TelecomBroadcastReceiver;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -68,7 +69,7 @@
public static final int NOTIFICATION_INCOMING_CALL = 1;
@VisibleForTesting
public static final String NOTIFICATION_TAG = IncomingCallNotifier.class.getSimpleName();
-
+ private final Object mLock = new Object();
public final Call.ListenerBase mCallListener = new Call.ListenerBase() {
@Override
@@ -104,8 +105,10 @@
@Override
public void onCallAdded(Call call) {
- if (!mCalls.contains(call)) {
- mCalls.add(call);
+ synchronized (mLock) {
+ if (!mCalls.contains(call)) {
+ mCalls.add(call);
+ }
}
updateIncomingCall();
@@ -113,10 +116,11 @@
@Override
public void onCallRemoved(Call call) {
- if (mCalls.contains(call)) {
- mCalls.remove(call);
+ synchronized (mLock) {
+ if (mCalls.contains(call)) {
+ mCalls.remove(call);
+ }
}
-
updateIncomingCall();
}
@@ -130,11 +134,16 @@
* UI.
*/
private void updateIncomingCall() {
- Optional<Call> incomingCallOp = mCalls.stream()
- .filter(call -> call.isSelfManaged() && call.isIncoming() &&
- call.getState() == CallState.RINGING &&
- call.getHandoverState() == HandoverState.HANDOVER_NONE)
- .findFirst();
+ Optional<Call> incomingCallOp;
+ synchronized (mLock) {
+ incomingCallOp = mCalls.stream()
+ .filter(Objects::nonNull)
+ .filter(call -> call.isSelfManaged() && call.isIncoming() &&
+ call.getState() == CallState.RINGING &&
+ call.getHandoverState() == HandoverState.HANDOVER_NONE)
+ .findFirst();
+ }
+
Call incomingCall = incomingCallOp.orElse(null);
if (incomingCall != null && mCallsManagerProxy != null &&
!mCallsManagerProxy.hasUnholdableCallsForOtherConnectionService(
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index e64e67c..4e32c9f 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -19,8 +19,10 @@
import static android.Manifest.permission.READ_PHONE_STATE;
import android.annotation.NonNull;
+import android.app.BroadcastOptions;
import android.content.ContentProvider;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
import android.telecom.Logging.Runnable;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -29,11 +31,13 @@
import com.android.server.telecom.CallsManagerListenerBase;
import com.android.server.telecom.Constants;
import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
import com.android.server.telecom.MissedCallNotifier;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.R;
import com.android.server.telecom.TelecomBroadcastIntentProcessor;
import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.Timeouts;
import com.android.server.telecom.components.TelecomBroadcastReceiver;
import android.app.Notification;
@@ -86,7 +90,8 @@
public interface MissedCallNotifierImplFactory {
MissedCallNotifier makeMissedCallNotifierImpl(Context context,
PhoneAccountRegistrar phoneAccountRegistrar,
- DefaultDialerCache defaultDialerCache);
+ DefaultDialerCache defaultDialerCache,
+ DeviceIdleControllerAdapter deviceIdleControllerAdapter);
}
public interface NotificationBuilderFactory {
@@ -124,12 +129,14 @@
private static final int MISSED_CALL_NOTIFICATION_ID = 1;
private static final String NOTIFICATION_TAG = MissedCallNotifierImpl.class.getSimpleName();
+ private static final String MISSED_CALL_POWER_SAVE_REASON = "missed-call";
private final Context mContext;
private final PhoneAccountRegistrar mPhoneAccountRegistrar;
private final NotificationManager mNotificationManager;
private final NotificationBuilderFactory mNotificationBuilderFactory;
private final DefaultDialerCache mDefaultDialerCache;
+ private final DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
private UserHandle mCurrentUserHandle;
// Used to track the number of missed calls.
@@ -138,19 +145,22 @@
private List<UserHandle> mUsersToLoadAfterBootComplete = new ArrayList<>();
public MissedCallNotifierImpl(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
- DefaultDialerCache defaultDialerCache) {
+ DefaultDialerCache defaultDialerCache,
+ DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
this(context, phoneAccountRegistrar, defaultDialerCache,
- new DefaultNotificationBuilderFactory());
+ new DefaultNotificationBuilderFactory(), deviceIdleControllerAdapter);
}
public MissedCallNotifierImpl(Context context,
PhoneAccountRegistrar phoneAccountRegistrar,
DefaultDialerCache defaultDialerCache,
- NotificationBuilderFactory notificationBuilderFactory) {
+ NotificationBuilderFactory notificationBuilderFactory,
+ DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
mContext = context;
mPhoneAccountRegistrar = phoneAccountRegistrar;
mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mDeviceIdleControllerAdapter = deviceIdleControllerAdapter;
mDefaultDialerCache = defaultDialerCache;
mNotificationBuilderFactory = notificationBuilderFactory;
@@ -162,7 +172,8 @@
public void clearMissedCalls(UserHandle userHandle) {
// If the default dialer is showing the missed call notification then it will modify the
// call log and we don't have to do anything here.
- if (!shouldManageNotificationThroughDefaultDialer(userHandle)) {
+ String dialerPackage = getDefaultDialerPackage(userHandle);
+ if (!shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
markMissedCallsAsRead(userHandle);
}
cancelMissedCallNotification(userHandle);
@@ -194,6 +205,15 @@
}.prepare());
}
+ private String getDefaultDialerPackage(UserHandle userHandle) {
+ String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
+ userHandle.getIdentifier());
+ if (TextUtils.isEmpty(dialerPackage)) {
+ return null;
+ }
+ return dialerPackage;
+ }
+
/**
* Returns the missed-call notification intent to send to the default dialer for the given user.
* Note, the passed in userHandle is always the non-managed user for SIM calls (multi-user
@@ -204,18 +224,16 @@
* handle of the phone account. This could be a managed user. In that case we return the default
* dialer for the given user which could be a managed (work profile) dialer.
*/
- private Intent getShowMissedCallIntentForDefaultDialer(UserHandle userHandle) {
- String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
- userHandle.getIdentifier());
- if (TextUtils.isEmpty(dialerPackage)) {
- return null;
- }
+ private Intent getShowMissedCallIntentForDefaultDialer(String dialerPackage) {
return new Intent(TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION)
.setPackage(dialerPackage);
}
- private boolean shouldManageNotificationThroughDefaultDialer(UserHandle userHandle) {
- Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle);
+ private boolean shouldManageNotificationThroughDefaultDialer(String dialerPackage,
+ UserHandle userHandle) {
+ if (TextUtils.isEmpty(dialerPackage)) return false;
+
+ Intent intent = getShowMissedCallIntentForDefaultDialer(dialerPackage);
if (intent == null) {
return false;
}
@@ -225,9 +243,29 @@
return receivers.size() > 0;
}
- private void sendNotificationThroughDefaultDialer(CallInfo callInfo, UserHandle userHandle) {
+ /**
+ * For dialers that manage missed call handling themselves, we must temporarily add them to the
+ * power save exemption list, as they must perform operations such as modifying the call log and
+ * power save restrictions can cause these types of operations to not complete (sometimes
+ * causing ANRs).
+ */
+ private Bundle exemptFromPowerSavingTemporarily(String dialerPackage, UserHandle handle) {
+ if (TextUtils.isEmpty(dialerPackage)) {
+ return null;
+ }
+ BroadcastOptions bopts = BroadcastOptions.makeBasic();
+ long duration = Timeouts.getDialerMissedCallPowerSaveExemptionTimeMillis(
+ mContext.getContentResolver());
+ mDeviceIdleControllerAdapter.exemptAppTemporarilyForEvent(dialerPackage, duration,
+ handle.getIdentifier(), MISSED_CALL_POWER_SAVE_REASON);
+ bopts.setTemporaryAppWhitelistDuration(duration);
+ return bopts.toBundle();
+ }
+
+ private void sendNotificationThroughDefaultDialer(String dialerPackage, CallInfo callInfo,
+ UserHandle userHandle) {
int count = mMissedCallCounts.get(userHandle).get();
- Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle)
+ Intent intent = getShowMissedCallIntentForDefaultDialer(dialerPackage)
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT,
createClearMissedCallsPendingIntent(userHandle))
@@ -248,7 +286,8 @@
Log.w(this, "Showing missed calls through default dialer.");
- mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE);
+ Bundle options = exemptFromPowerSavingTemporarily(dialerPackage, userHandle);
+ mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE, options);
}
/**
@@ -276,8 +315,9 @@
mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0));
int missCallCounts = mMissedCallCounts.get(userHandle).incrementAndGet();
- if (shouldManageNotificationThroughDefaultDialer(userHandle)) {
- sendNotificationThroughDefaultDialer(callInfo, userHandle);
+ String dialerPackage = getDefaultDialerPackage(userHandle);
+ if (shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
+ sendNotificationThroughDefaultDialer(dialerPackage, callInfo, userHandle);
return;
}
@@ -393,8 +433,9 @@
mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0));
mMissedCallCounts.get(userHandle).set(0);
- if (shouldManageNotificationThroughDefaultDialer(userHandle)) {
- sendNotificationThroughDefaultDialer(null, userHandle);
+ String dialerPackage = getDefaultDialerPackage(userHandle);
+ if (shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
+ sendNotificationThroughDefaultDialer(dialerPackage, null, userHandle);
return;
}
@@ -472,7 +513,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);
}
/**
@@ -518,7 +559,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);
}
/**
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 4238191..9c461ca 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -15,40 +15,41 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- coreApp="true"
- package="com.android.server.telecom.testapps">
+ coreApp="true"
+ package="com.android.server.telecom.testapps">
- <uses-sdk
- android:minSdkVersion="28"
- android:targetSdkVersion="30" />
+ <uses-sdk android:minSdkVersion="28"
+ android:targetSdkVersion="30"/>
- <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-permission android:name="android.permission.CALL_PHONE" />
- <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
- <uses-permission android:name="android.permission.READ_CALL_LOG" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
- <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
- <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
- <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <uses-permission android:name="android.permission.ACCEPT_HANDOVER"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.CALL_PHONE"/>
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
+ <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER"/>
+ <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"/>
+ <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<application android:label="@string/app_name">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<!-- Miscellaneous telecom app-related test activities. -->
<service android:name="com.android.server.telecom.testapps.TestConnectionService"
- android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >
+ android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+ android:exported="true">
<intent-filter>
- <action android:name="android.telecom.ConnectionService" />
+ <action android:name="android.telecom.ConnectionService"/>
</intent-filter>
</service>
- <receiver android:name=".TestConnectionServiceReceiver">
+ <receiver android:name=".TestConnectionServiceReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.server.telecom.testapps.ACTION_SWITCH_PHONE_ACCOUNT"/>
<action android:name="android.server.telecom.testapps.ACTION_SWITCH_PHONE_ACCOUNT_WRONG"/>
@@ -56,23 +57,27 @@
</receiver>
<service android:name="com.android.server.telecom.testapps.TestConnectionManager"
- android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >
+ android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+ android:exported="true">
<intent-filter>
- <action android:name="android.telecom.ConnectionService" />
+ <action android:name="android.telecom.ConnectionService"/>
</intent-filter>
</service>
<service android:name="com.android.server.telecom.testapps.TestInCallServiceImpl"
- android:process="com.android.server.telecom.testapps.TestInCallService"
- android:permission="android.permission.BIND_INCALL_SERVICE" >
- <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true"/>
+ android:process="com.android.server.telecom.testapps.TestInCallService"
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:exported="true">
+ <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI"
+ android:value="true"/>
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
</service>
<receiver android:name="com.android.server.telecom.testapps.TestInCallServiceBroadcastReceiver"
- android:process="com.android.server.telecom.testapps.TestInCallService" >
+ android:process="com.android.server.telecom.testapps.TestInCallService"
+ android:exported="true">
<intent-filter>
<action android:name="android.server.telecom.testapps.ACTION_SEND_UPDATE_REQUEST_FROM_TEST_INCALL_SERVICE"/>
<action android:name="android.server.telecom.testapps.ACTION_SEND_UPGRADE_RESPONSE"/>
@@ -84,201 +89,212 @@
<activity android:name="com.android.server.telecom.testapps.TestInCallUI"
- android:process="com.android.server.telecom.testapps.TestInCallService"
- android:label="@string/inCallUiAppLabel"
- android:launchMode="singleInstance">
+ android:process="com.android.server.telecom.testapps.TestInCallService"
+ android:label="@string/inCallUiAppLabel"
+ android:launchMode="singleInstance"
+ 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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.TestRttActivity"
- android:process="com.android.server.telecom.testapps.TestInCallService"
- android:label="@string/rttUiLabel"
- android:launchMode="singleInstance">
+ android:process="com.android.server.telecom.testapps.TestInCallService"
+ android:label="@string/rttUiLabel"
+ android:launchMode="singleInstance"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.TestCallActivity"
- android:theme="@android:style/Theme.NoDisplay"
- android:label="@string/testCallActivityLabel">
+ android:theme="@android:style/Theme.NoDisplay"
+ android:label="@string/testCallActivityLabel"
+ 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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
- <action android:name="android.telecom.testapps.ACTION_START_INCOMING_CALL" />
- <action android:name="android.telecom.testapps.ACTION_NEW_UNKNOWN_CALL" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="tel" />
- <data android:scheme="sip" />
+ <action android:name="android.telecom.testapps.ACTION_START_INCOMING_CALL"/>
+ <action android:name="android.telecom.testapps.ACTION_NEW_UNKNOWN_CALL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="tel"/>
+ <data android:scheme="sip"/>
</intent-filter>
<intent-filter>
- <action android:name="android.telecom.testapps.ACTION_HANGUP_CALLS" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.telecom.testapps.ACTION_HANGUP_CALLS"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
- <action android:name="android.telecom.testapps.ACTION_SEND_UPGRADE_REQUEST" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="int" />
+ <action android:name="android.telecom.testapps.ACTION_SEND_UPGRADE_REQUEST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="int"/>
</intent-filter>
<intent-filter>
- <action android:name="android.telecom.testapps.ACTION_RTT_CALL" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="tel" />
+ <action android:name="android.telecom.testapps.ACTION_RTT_CALL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="tel"/>
</intent-filter>
<intent-filter>
- <action android:name="android.telecom.testapps.ACTION_REMOTE_RTT_UPGRADE" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.telecom.testapps.ACTION_REMOTE_RTT_UPGRADE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<receiver android:name="com.android.server.telecom.testapps.CallNotificationReceiver"
- android:exported="false">
+ android:exported="false">
<intent-filter>
- <action android:name="com.android.server.telecom.testapps.ACTION_CALL_SERVICE_EXIT" />
+ <action android:name="com.android.server.telecom.testapps.ACTION_CALL_SERVICE_EXIT"/>
</intent-filter>
</receiver>
<activity android:name="com.android.server.telecom.testapps.TestDialerActivity"
- android:label="@string/testDialerActivityLabel"
- android:process="com.android.server.telecom.testapps.TestInCallService">
+ android:label="@string/testDialerActivityLabel"
+ android:process="com.android.server.telecom.testapps.TestInCallService"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:mimeType="vnd.android.cursor.item/phone" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:mimeType="vnd.android.cursor.item/phone"/>
+ <data android:mimeType="vnd.android.cursor.item/person"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="voicemail" />
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="voicemail"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="tel" />
+ <action android:name="android.intent.action.VIEW"/>
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="tel"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.TestUssdActivity"
- android:label="@string/UssdUiAppLabel"
- android:launchMode="singleInstance">
+ android:label="@string/UssdUiAppLabel"
+ android:launchMode="singleInstance"
+ 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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.TestCertActivity"
- android:label="@string/KeyUiAppLabel"
- android:launchMode="singleInstance">
+ android:label="@string/KeyUiAppLabel"
+ android:launchMode="singleInstance"
+ 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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.SelfManagedCallingActivity"
- android:label="@string/selfManagedCallingActivityLabel"
- android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
- android:theme="@android:style/Theme.Material.Light">
+ android:label="@string/selfManagedCallingActivityLabel"
+ android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+ android:theme="@android:style/Theme.Material.Light"
+ 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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.IncomingSelfManagedCallActivity"
- android:label="@string/selfManagedCallingActivityLabel"
- android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+ android:label="@string/selfManagedCallingActivityLabel"
+ android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.testapps.HandoverActivity"
- android:label="@string/selfManagedCallingActivityLabel"
- android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+ android:label="@string/selfManagedCallingActivityLabel"
+ android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
<service android:name="com.android.server.telecom.testapps.SelfManagedConnectionService"
- android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
- android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+ android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+ android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+ android:exported="true">
<intent-filter>
- <action android:name="android.telecom.ConnectionService" />
+ <action android:name="android.telecom.ConnectionService"/>
</intent-filter>
</service>
<receiver android:exported="false"
- android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
- android:name="com.android.server.telecom.testapps.SelfManagedCallNotificationReceiver" />
+ android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+ android:name="com.android.server.telecom.testapps.SelfManagedCallNotificationReceiver"/>
<receiver android:exported="true"
- android:name="com.android.server.telecom.testapps.NuisanceReportReceiver">
+ android:name="com.android.server.telecom.testapps.NuisanceReportReceiver">
<intent-filter>
- <action android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
+ <action android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED"/>
</intent-filter>
</receiver>
- <service
- android:name=".TestCallScreeningService"
- android:permission="android.permission.BIND_SCREENING_SERVICE">
+ <service android:name=".TestCallScreeningService"
+ android:permission="android.permission.BIND_SCREENING_SERVICE"
+ android:exported="true">
<intent-filter>
<action android:name="android.telecom.CallScreeningService"/>
</intent-filter>
</service>
<activity android:name=".CallScreeningActivity"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance">
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance">
</activity>
- <service
- android:name=".TestCallRedirectionService"
- android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
+ <service android:name=".TestCallRedirectionService"
+ android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE"
+ android:exported="true">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService"/>
</intent-filter>
</service>
<activity android:name=".CallRedirectionActivity"
- android:configChanges="orientation|screenSize|keyboardHidden"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance">
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance">
</activity>
<activity android:name=".PostCallActivity"
- android:label="@string/postCallActivityLabel">
+ android:label="@string/postCallActivityLabel"
+ android:exported="true">
<intent-filter>
- <action android:name="android.telecom.action.POST_CALL" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.telecom.action.POST_CALL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
diff --git a/testapps/carmodedialer/AndroidManifest.xml b/testapps/carmodedialer/AndroidManifest.xml
index 7f55f7e..f237211 100644
--- a/testapps/carmodedialer/AndroidManifest.xml
+++ b/testapps/carmodedialer/AndroidManifest.xml
@@ -15,75 +15,77 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- coreApp="true"
- package="com.android.server.telecom.carmodedialer">
+ coreApp="true"
+ package="com.android.server.telecom.carmodedialer">
- <uses-sdk
- android:minSdkVersion="28"
- android:targetSdkVersion="29" />
+ <uses-sdk android:minSdkVersion="28"
+ android:targetSdkVersion="29"/>
- <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
- <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.ENTER_CAR_MODE_PRIORITIZED" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_CALL_LOG" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+ <uses-permission android:name="android.permission.ACCEPT_HANDOVER"/>
+ <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.ENTER_CAR_MODE_PRIORITIZED"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<application android:label="Telecom CarMode">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name="com.android.server.telecom.carmodedialer.CarModeInCallServiceImpl"
- android:permission="android.permission.BIND_INCALL_SERVICE" >
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:exported="true">
<meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
- android:value="true"/>
+ android:value="true"/>
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
</service>
<activity android:name="com.android.server.telecom.carmodedialer.CarModeInCallUI"
- android:label="CarMode Dialer"
- android:launchMode="singleInstance">
+ android:label="CarMode Dialer"
+ android:launchMode="singleInstance"
+ 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" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.android.server.telecom.carmodedialer.CarModeDialerActivity"
- android:label="CarMode Dialer">
+ android:label="CarMode Dialer"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:mimeType="vnd.android.cursor.item/phone" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:mimeType="vnd.android.cursor.item/phone"/>
+ <data android:mimeType="vnd.android.cursor.item/person"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="voicemail" />
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="voicemail"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <action android:name="android.intent.action.DIAL" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="tel" />
+ <action android:name="android.intent.action.VIEW"/>
+ <action android:name="android.intent.action.DIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="tel"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <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>
diff --git a/testapps/res/layout/testdialer_main.xml b/testapps/res/layout/testdialer_main.xml
index e2ea30c..3f397b8 100644
--- a/testapps/res/layout/testdialer_main.xml
+++ b/testapps/res/layout/testdialer_main.xml
@@ -90,4 +90,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toggle InCallService" />
+
+ <Button
+ android:id="@+id/send_contact_discovery_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/send_contact_discovery" />
</LinearLayout>
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index fcd6eff..7331d5a 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -113,4 +113,6 @@
<item>The FCC has mandated that I respond... I will do so begrudgingly</item>
<item>😂😂😂💯</item>
</string-array>
+
+ <string name="send_contact_discovery">Send Contact Discovery Intent</string>
</resources>
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
index abb9108..5c78d52 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
@@ -37,7 +37,6 @@
/**
* Service which acts as a fake ConnectionManager if so configured.
- * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
*/
public class TestConnectionManager extends ConnectionService {
public final class TestManagedConnection extends Connection {
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index f6fa116..3d1bc70 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -53,7 +53,6 @@
/**
* Service which provides fake calls to test the ConnectionService interface.
- * TODO: Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
*/
public class TestConnectionService extends ConnectionService {
/**
@@ -430,9 +429,9 @@
int videoState = extras.getInt(EXTRA_START_VIDEO_STATE, VideoProfile.STATE_AUDIO_ONLY);
Uri providedHandle = extras.getParcelable(EXTRA_HANDLE);
- // Use dummy number for testing incoming calls.
+ // Use test number for testing incoming calls.
Uri address = providedHandle == null ?
- Uri.fromParts(PhoneAccount.SCHEME_TEL, getDummyNumber(
+ Uri.fromParts(PhoneAccount.SCHEME_TEL, getRandomNumber(
VideoProfile.isVideo(videoState)), null)
: providedHandle;
connection.setVideoState(videoState);
@@ -480,7 +479,7 @@
final Uri providedHandle = extras.getParcelable(EXTRA_HANDLE);
Uri handle = providedHandle == null ?
- Uri.fromParts(PhoneAccount.SCHEME_TEL, getDummyNumber(false), null)
+ Uri.fromParts(PhoneAccount.SCHEME_TEL, getRandomNumber(false), null)
: providedHandle;
connection.setAddress(handle, TelecomManager.PRESENTATION_ALLOWED);
@@ -613,7 +612,7 @@
* @param isVideo {@code True} if the call is a video call.
* @return The phone number.
*/
- private String getDummyNumber(boolean isVideo) {
+ private String getRandomNumber(boolean isVideo) {
int videoDigit = isVideo ? 1 : 0;
int number = mRandom.nextInt(999);
return String.format("555%s%03d", videoDigit, number);
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
index 19f09e6..1e06387 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -11,12 +11,18 @@
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.provider.CallLog.Calls;
+import android.provider.Settings;
import android.telecom.PhoneAccount;
import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsRcsManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
@@ -80,6 +86,10 @@
toggleInCallService();
}
});
+
+ Button discoveryButton = findViewById(R.id.send_contact_discovery_button);
+ discoveryButton.setOnClickListener(v -> sendContactDiscoveryIntent());
+
mPriorityView = findViewById(R.id.priority);
updateMutableUi();
}
@@ -201,4 +211,10 @@
== PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
Toast.makeText(this, "Is UI enabled? " + isEnabled, Toast.LENGTH_LONG).show();
}
+
+ private void sendContactDiscoveryIntent() {
+ Intent intent = new Intent(ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN);
+ intent.putExtra(Settings.EXTRA_SUB_ID, SubscriptionManager.getDefaultSubscriptionId());
+ startActivity(intent);
+ }
}
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index 3fb2a84..02b35a4 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -27,4 +27,10 @@
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.TestFailureModuleController">
+ <option name="screenshot-on-failure" value="false" />
+ <option name="bugreportz-on-failure" value="false" />
+ <option name="logcat-on-failure" value="true" />
+ </object>
</configuration>
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index ec5f7ba..a64f39d 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -16,6 +16,8 @@
package com.android.server.telecom.tests;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -127,7 +129,8 @@
Analytics.dump(ip);
String dumpResult = sr.toString();
String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
- "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"};
+ "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService",
+ "missedReason"};
for (String field : expectedFields) {
assertTrue(dumpResult.contains(field));
}
@@ -200,6 +203,8 @@
assertTrue(callAnalytics2.startTime > 0);
assertEquals(0, callAnalytics1.endTime);
assertEquals(0, callAnalytics2.endTime);
+ assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics1.missedReason);
+ assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics2.missedReason);
assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
diff --git a/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java b/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java
deleted file mode 100644
index ee34b0c..0000000
--- a/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java
+++ /dev/null
@@ -1,207 +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.tests;
-
-import static android.provider.BlockedNumberContract.STATUS_BLOCKED_IN_LIST;
-import static android.provider.BlockedNumberContract.STATUS_NOT_BLOCKED;
-
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.provider.CallLog.Calls;
-import android.telecom.TelecomManager;
-import android.telephony.CarrierConfigManager;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
-import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
-import com.android.server.telecom.callfiltering.CallFilterResultCallback;
-import com.android.server.telecom.callfiltering.CallFilteringResult;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-
-import org.junit.After;
-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 java.util.concurrent.CountDownLatch;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(JUnit4.class)
-public class AsyncBlockCheckFilterTest extends TelecomTestCase {
- @Mock private BlockCheckerAdapter mBlockCheckerAdapter;
- @Mock private Call mCall;
- @Mock private CallFilterResultCallback mCallback;
- @Mock private CallerInfoLookupHelper mCallerInfoLookupHelper;
- @Mock private CarrierConfigManager mCarrierConfigManager;
-
- private AsyncBlockCheckFilter mFilter;
- private static final CallFilteringResult BLOCK_RESULT = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(false)
- .setCallBlockReason(Calls.BLOCK_REASON_BLOCKED_NUMBER)
- .setCallScreeningAppName(null)
- .setCallScreeningComponentName(null)
- .build();
-
- private static final CallFilteringResult PASS_RESULT = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
-
- private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");
- private static final int TEST_TIMEOUT = 1000;
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- when(mCall.getHandle()).thenReturn(TEST_HANDLE);
- mFilter = new AsyncBlockCheckFilter(mContext, mBlockCheckerAdapter,
- mCallerInfoLookupHelper, null);
- }
-
- @Override
- @After
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- @SmallTest
- @Test
- public void testBlockNumber() {
- final CountDownLatch latch = new CountDownLatch(1);
- doAnswer(invocation -> {
- latch.countDown();
- return STATUS_BLOCKED_IN_LIST;
- }).when(mBlockCheckerAdapter)
- .getBlockStatus(any(Context.class), eq(TEST_HANDLE.getSchemeSpecificPart()),
- any(Bundle.class));
-
- setEnhancedBlockingEnabled(false);
- mFilter.startFilterLookup(mCall, mCallback);
-
- waitOnLatch(latch);
- verify(mCallback, timeout(TEST_TIMEOUT))
- .onCallFilteringComplete(eq(mCall), eq(BLOCK_RESULT));
- }
-
- @SmallTest
- @Test
- public void testBlockNumber_enhancedBlockingEnabled() {
- final CountDownLatch latch = new CountDownLatch(1);
- doAnswer(invocation -> {
- latch.countDown();
- return STATUS_BLOCKED_IN_LIST;
- }).when(mBlockCheckerAdapter)
- .getBlockStatus(any(Context.class), eq(TEST_HANDLE.getSchemeSpecificPart()),
- any(Bundle.class));
-
- setEnhancedBlockingEnabled(true);
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyEnhancedLookupStart();
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, null);
-
- waitOnLatch(latch);
- verify(mCallback, timeout(TEST_TIMEOUT))
- .onCallFilteringComplete(eq(mCall), eq(BLOCK_RESULT));
- }
-
- @SmallTest
- @Test
- public void testDontBlockNumber() {
- final CountDownLatch latch = new CountDownLatch(1);
- doAnswer(invocation -> {
- latch.countDown();
- return STATUS_NOT_BLOCKED;
- }).when(mBlockCheckerAdapter)
- .getBlockStatus(any(Context.class), eq(TEST_HANDLE.getSchemeSpecificPart()),
- any(Bundle.class));
-
- setEnhancedBlockingEnabled(false);
- mFilter.startFilterLookup(mCall, mCallback);
-
- waitOnLatch(latch);
- verify(mCallback, timeout(TEST_TIMEOUT))
- .onCallFilteringComplete(eq(mCall), eq(PASS_RESULT));
- }
-
- @SmallTest
- @Test
- public void testDontBlockNumber_enhancedBlockingEnabled() {
- final CountDownLatch latch = new CountDownLatch(1);
- doAnswer(invocation -> {
- latch.countDown();
- return STATUS_NOT_BLOCKED;
- }).when(mBlockCheckerAdapter)
- .getBlockStatus(any(Context.class), eq(TEST_HANDLE.getSchemeSpecificPart()),
- any(Bundle.class));
-
- setEnhancedBlockingEnabled(true);
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyEnhancedLookupStart();
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, null);
-
- waitOnLatch(latch);
- verify(mCallback, timeout(TEST_TIMEOUT))
- .onCallFilteringComplete(eq(mCall), eq(PASS_RESULT));
- }
-
- private void setEnhancedBlockingEnabled(Boolean value) {
- PersistableBundle bundle = new PersistableBundle();
- bundle.putBoolean(CarrierConfigManager.KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL,
- value);
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(mCarrierConfigManager);
- when(mCarrierConfigManager.getConfig()).thenReturn(bundle);
- }
-
- private CallerInfoLookupHelper.OnQueryCompleteListener verifyEnhancedLookupStart() {
- // The enhanced lookup will only be excuted when enhanced blocking enabled and the
- // presentation is PRESENTATION_ALLOWED.
- when(mCall.getHandlePresentation()).thenReturn(TelecomManager.PRESENTATION_ALLOWED);
- mFilter.startFilterLookup(mCall, mCallback);
- ArgumentCaptor<CallerInfoLookupHelper.OnQueryCompleteListener> captor =
- ArgumentCaptor.forClass(CallerInfoLookupHelper.OnQueryCompleteListener.class);
- verify(mCallerInfoLookupHelper).startLookup(eq(TEST_HANDLE), captor.capture());
- return captor.getValue();
- }
-
- private void waitOnLatch(CountDownLatch latch) {
- while (latch.getCount() > 0) {
- try {
- latch.await();
- } catch (InterruptedException e) {
- // do nothing
- }
- }
- }
-}
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index d536cbd..a8e1c00 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -103,8 +103,10 @@
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DISCONNECTING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DISCONNECTING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
@@ -161,6 +163,9 @@
.getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
telecomManager.acceptRingingCall();
+ waitForHandlerAction(mTelecomSystem.getCallsManager()
+ .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.answer(eq(ids.mConnectionId), any());
mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
@@ -217,6 +222,9 @@
.getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
telecomManager.acceptRingingCall(VideoProfile.STATE_AUDIO_ONLY);
+ waitForHandlerAction(mTelecomSystem.getCallsManager()
+ .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
// The generic answer method on the ConnectionService is used to answer audio-only calls.
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.answer(eq(ids.mConnectionId), any());
@@ -246,6 +254,9 @@
.getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
telecomManager.acceptRingingCall(999 /* invalid videostate */);
+ waitForHandlerAction(mTelecomSystem.getCallsManager()
+ .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
// Answer video API should be called
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any());
@@ -259,12 +270,15 @@
IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DISCONNECTING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DISCONNECTING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME);
when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME);
mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
+
assertEquals(Call.STATE_DISCONNECTED,
mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_DISCONNECTED,
@@ -621,6 +635,10 @@
mConnectionServiceFixtureA.
sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
+ waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+ .getCallAudioModeStateMachine().getHandler(), TEST_TIMEOUT);
+ waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+ .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
verify(audioManager, timeout(TEST_TIMEOUT))
.abandonAudioFocusForCall();
verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
@@ -810,8 +828,9 @@
private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception {
when(getBlockedNumberProvider().call(
anyString(),
+ nullable(String.class),
anyString(),
- eq(BlockedNumberContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
+ eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
eq(phoneNumber),
nullable(Bundle.class))).thenAnswer(answer);
}
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
index 8ba6b63..b36d74b 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
@@ -346,6 +346,8 @@
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)))
+ .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
if (audioOnDevice != null) {
when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice);
when(mHeadsetProxy.getAudioState(audioOnDevice))
@@ -634,6 +636,22 @@
.setExpectedBluetoothInteraction(NONE)
.setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
.build());
+
+ result.add(new BluetoothRouteTestParametersBuilder()
+ .setName("connect BT to an already active device when in audio off.")
+ .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
+ .setAudioOnDevice(DEVICE2)
+ .setActiveDevice(DEVICE2)
+ .setConnectedDevices(DEVICE2, DEVICE3)
+ .setHearingAidBtDevices(Collections.singletonList(DEVICE2))
+ .setMessageType(BluetoothRouteManager.CONNECT_HFP)
+ .setMessageDevice(DEVICE2)
+ .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
+ .setExpectedBluetoothInteraction(NONE)
+ .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
+ + ":" + DEVICE2)
+ .build());
+
return result;
}
}
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
index ca84c4c..38f58fd 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
@@ -180,6 +180,81 @@
CallAudioRouteStateMachine.RINGING_FOCUS);
}
+ @SmallTest
+ @Test
+ public void testDoNotRingTwiceWhenHfpConnected() {
+ CallAudioModeStateMachine sm = new CallAudioModeStateMachine(mSystemStateHelper,
+ mAudioManager, mTestThread.getLooper());
+ sm.setCallAudioManager(mCallAudioManager);
+ sm.sendMessage(CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ resetMocks();
+ when(mCallAudioManager.startRinging()).thenReturn(true);
+
+ sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL, new Builder()
+ .setHasActiveOrDialingCalls(false)
+ .setHasRingingCalls(true)
+ .setHasHoldingCalls(false)
+ .setIsTonePlaying(false)
+ .setForegroundCallIsVoip(false)
+ .setSession(null)
+ .build());
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());
+
+ verify(mAudioManager).requestAudioFocusForCall(AudioManager.STREAM_RING,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ verify(mAudioManager).setMode(AudioManager.MODE_RINGTONE);
+ verify(mCallAudioManager).setCallAudioRouteFocusState(
+ CallAudioRouteStateMachine.RINGING_FOCUS);
+
+ when(mCallAudioManager.isRingtonePlaying()).thenReturn(true);
+ sm.sendMessage(CallAudioModeStateMachine.RINGER_MODE_CHANGE);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ // Make sure we don't try and start ringing again.
+ verify(mCallAudioManager, times(1)).startRinging();
+ }
+
+ @SmallTest
+ @Test
+ public void testStartRingingAfterHfpConnectedIfNotAlreadyPlaying() {
+ CallAudioModeStateMachine sm = new CallAudioModeStateMachine(mSystemStateHelper,
+ mAudioManager, mTestThread.getLooper());
+ sm.setCallAudioManager(mCallAudioManager);
+ sm.sendMessage(CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ resetMocks();
+ when(mCallAudioManager.startRinging()).thenReturn(true);
+
+ sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL, new Builder()
+ .setHasActiveOrDialingCalls(false)
+ .setHasRingingCalls(true)
+ .setHasHoldingCalls(false)
+ .setIsTonePlaying(false)
+ .setForegroundCallIsVoip(false)
+ .setSession(null)
+ .build());
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());
+
+ verify(mAudioManager).requestAudioFocusForCall(AudioManager.STREAM_RING,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ verify(mAudioManager).setMode(AudioManager.MODE_RINGTONE);
+ verify(mCallAudioManager).setCallAudioRouteFocusState(
+ CallAudioRouteStateMachine.RINGING_FOCUS);
+
+ when(mCallAudioManager.isRingtonePlaying()).thenReturn(false);
+ sm.sendMessage(CallAudioModeStateMachine.RINGER_MODE_CHANGE);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ // Make sure we do try and start ringing again, since the ringtone wasn't already playing.
+ verify(mCallAudioManager, times(2)).startRinging();
+ }
private void resetMocks() {
clearInvocations(mCallAudioManager, mAudioManager);
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
index 2047867..c7e5aa9 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
@@ -137,9 +137,20 @@
resetMocks();
when(mCallAudioManager.startRinging()).thenReturn(true);
+ if (mParams.initialAudioState
+ == CallAudioModeStateMachine.ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING) {
+ when(mAudioManager.getMode())
+ .thenReturn(CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
+ }
sm.sendMessage(mParams.messageType, mParams.externalState);
waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+ if (mParams.expectedFocus == FOCUS_OFF
+ && mParams.messageType != CallAudioModeStateMachine.AUDIO_OPERATIONS_COMPLETE) {
+ // If we expect the focus to turn off, we need to signal operations complete first
+ sm.sendMessage(CallAudioModeStateMachine.AUDIO_OPERATIONS_COMPLETE);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+ }
assertEquals(mParams.expectedFinalStateName, sm.getCurrentStateName());
@@ -809,7 +820,7 @@
.build(),
CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
FOCUS_RING, // expectedFocus
- AudioManager.MODE_RINGTONE, // expectedMode
+ NO_CHANGE, // expectedMode
ON, // expectedRingingInteraction
// We expect a call to stopCallWaiting because it happens whenever the ringer starts
OFF // expectedCallWaitingInteraction
@@ -830,7 +841,7 @@
.build(),
CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
FOCUS_RING, // expectedFocus
- AudioManager.MODE_RINGTONE, // expectedMode
+ NO_CHANGE, // expectedMode
ON, // expectedRingingInteraction
// We expect a call to stopCallWaiting because it happens whenever the ringer starts
OFF // expectedCallWaitingInteraction
@@ -856,6 +867,46 @@
NO_CHANGE // expectedCallWaitingInteraction
));
+ result.add(new ModeTestParameters(
+ "No change to focus without signaling audio ops complete",
+ CallAudioModeStateMachine.ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, // initialAudioS
+ CallAudioModeStateMachine.TONE_STOPPED_PLAYING, // messageType
+ new MessageArgs.Builder()
+ .setHasActiveOrDialingCalls(false)
+ .setHasRingingCalls(false)
+ .setHasHoldingCalls(false)
+ .setHasAudioProcessingCalls(false)
+ .setIsTonePlaying(false)
+ .setForegroundCallIsVoip(false)
+ .setSession(null)
+ .build(),
+ CallAudioModeStateMachine.UNFOCUSED_STATE_NAME, // expectedFinalStateName
+ FOCUS_NO_CHANGE, // expectedFocus
+ AudioManager.MODE_NORMAL, // expectedMode
+ NO_CHANGE, // expectedRingingInteraction
+ NO_CHANGE // expectedCallWaitingInteraction
+ ));
+
+ result.add(new ModeTestParameters(
+ "Abandon focus once audio ops are complete",
+ CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING, // initialAudioS
+ CallAudioModeStateMachine.AUDIO_OPERATIONS_COMPLETE, // messageType
+ new MessageArgs.Builder()
+ .setHasActiveOrDialingCalls(false)
+ .setHasRingingCalls(false)
+ .setHasHoldingCalls(false)
+ .setHasAudioProcessingCalls(false)
+ .setIsTonePlaying(false)
+ .setForegroundCallIsVoip(false)
+ .setSession(null)
+ .build(),
+ CallAudioModeStateMachine.UNFOCUSED_STATE_NAME, // expectedFinalStateName
+ FOCUS_OFF, // expectedFocus
+ NO_CHANGE, // expectedMode
+ NO_CHANGE, // expectedRingingInteraction
+ NO_CHANGE // expectedCallWaitingInteraction
+ ));
+
return result;
}
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 5a739a5..24476f0 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -54,9 +54,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
@@ -486,9 +488,10 @@
CallAudioRouteStateMachine.ACTIVE_FOCUS);
waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
- // Make sure that we've successfully switched to the active BT route without actually
- // calling connectAudio.
- verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(nullable(String.class));
+ // Make sure that we've successfully switched to the active BT route and that we've
+ // called connectAudio on the right device.
+ verify(mockBluetoothRouteManager, atLeastOnce())
+ .connectBluetoothAudio(eq(bluetoothDevice1.getAddress()));
assertTrue(stateMachine.isInActiveState());
}
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
index 58f1ee7..879ed0f 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
@@ -384,8 +384,12 @@
// rest of the system
verifyNoSystemAudioChanges();
+ // Special case for SPEAKER_ON -- we don't expect any route transitions to happen when
+ // there are no calls, so set the expected state to the initial route.
+ int expectedRoute = (mParams.action == CallAudioRouteStateMachine.SPEAKER_ON)
+ ? mParams.initialRoute : mParams.expectedRoute;
// Verify the end state
- CallAudioState expectedState = new CallAudioState(false, mParams.expectedRoute,
+ CallAudioState expectedState = new CallAudioState(false, expectedRoute,
mParams.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER,
mParams.expectedBluetoothDevice, mParams.availableBluetoothDevices);
assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
@@ -811,7 +815,7 @@
"Speakerphone turned off externally during speaker", // name
CallAudioState.ROUTE_SPEAKER, // initialRoute
CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
- NONE, // speakerInteraction
+ OFF, // speakerInteraction
ON, // bluetoothInteraction
CallAudioRouteStateMachine.SPEAKER_OFF, // action
CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index d53c73c..953c711 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -16,15 +16,13 @@
package com.android.server.telecom.tests;
-
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.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -34,9 +32,9 @@
import android.content.ComponentName;
import android.content.ContentProvider;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
-import android.content.IContentProvider;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.location.Country;
@@ -45,6 +43,7 @@
import android.net.Uri;
import android.os.Looper;
import android.os.PersistableBundle;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.CallLog;
@@ -74,6 +73,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
@@ -85,7 +85,6 @@
public class CallLogManagerTest extends TelecomTestCase {
private CallLogManager mCallLogManager;
- private IContentProvider mContentProvider;
private PhoneAccountHandle mDefaultAccountHandle;
private PhoneAccountHandle mOtherUserAccountHandle;
private PhoneAccountHandle mManagedProfileAccountHandle;
@@ -112,8 +111,10 @@
private static final String TEST_ISO = "KR";
private static final String TEST_ISO_2 = "JP";
- @Mock PhoneAccountRegistrar mMockPhoneAccountRegistrar;
-
+ @Mock(answer = Answers.CALLS_REAL_METHODS)
+ ContentProvider mContentProvider;
+ @Mock
+ PhoneAccountRegistrar mMockPhoneAccountRegistrar;
@Mock
MissedCallNotifier mMissedCallNotifier;
@@ -124,8 +125,6 @@
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
mCallLogManager = new CallLogManager(mContext, mMockPhoneAccountRegistrar,
mMissedCallNotifier);
- mContentProvider =
- mContext.getContentResolver().acquireProvider("0@call_log");
mDefaultAccountHandle = new PhoneAccountHandle(
new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"),
TEST_PHONE_ACCOUNT_ID,
@@ -150,6 +149,9 @@
UserHandle.of(CURRENT_USER_ID)
);
+ // Since we can't mock ContentResolver directly, use a ContentProvider
+ when(mContext.getContentResolver()).thenReturn(ContentResolver.wrap(mContentProvider));
+
UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
UserInfo userInfo = new UserInfo(CURRENT_USER_ID, "test", 0);
UserInfo otherUserInfo = new UserInfo(OTHER_USER_ID, "test2", 0);
@@ -159,9 +161,9 @@
doAnswer(new Answer<Uri>() {
@Override
public Uri answer(InvocationOnMock invocation) throws Throwable {
- return (Uri) invocation.getArguments()[1];
+ return (Uri) invocation.getArguments()[0];
}
- }).when(mContentProvider).insert(anyString(), any(Uri.class), any(ContentValues.class));
+ }).when(mContentProvider).insert(any(Uri.class), any(ContentValues.class));
when(userManager.isUserRunning(any(UserHandle.class))).thenReturn(true);
when(userManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
@@ -538,13 +540,24 @@
// Outgoing call placed through a phone account with multi user capability is inserted to
// all users except managed profile.
- ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
- assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
- Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
- insertedValues = verifyInsertionWithCapture(OTHER_USER_ID);
- assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
- Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
- verifyNoInsertionInUser(MANAGED_USER_ID);
+ SystemClock.sleep(TEST_TIMEOUT_MILLIS);
+
+ ArgumentCaptor<Uri> uris = ArgumentCaptor.forClass(Uri.class);
+ ArgumentCaptor<ContentValues> values = ArgumentCaptor.forClass(ContentValues.class);
+
+ verify(mContentProvider, atLeast(2)).insert(uris.capture(), values.capture());
+
+ assertTrue(uris.getAllValues().contains(
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, CURRENT_USER_ID)));
+ assertTrue(uris.getAllValues().contains(
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, OTHER_USER_ID)));
+ assertFalse(uris.getAllValues().contains(
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, MANAGED_USER_ID)));
+
+ for (ContentValues v : values.getAllValues()) {
+ assertEquals(v.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.OUTGOING_TYPE));
+ }
}
@MediumTest
@@ -572,13 +585,24 @@
// Incoming call using a phone account with multi user capability is inserted to all users
// except managed profile.
- ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
- assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
- Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
- insertedValues = verifyInsertionWithCapture(OTHER_USER_ID);
- assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
- Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
- verifyNoInsertionInUser(MANAGED_USER_ID);
+ SystemClock.sleep(TEST_TIMEOUT_MILLIS);
+
+ ArgumentCaptor<Uri> uris = ArgumentCaptor.forClass(Uri.class);
+ ArgumentCaptor<ContentValues> values = ArgumentCaptor.forClass(ContentValues.class);
+
+ verify(mContentProvider, atLeast(2)).insert(uris.capture(), values.capture());
+
+ assertTrue(uris.getAllValues().contains(
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, CURRENT_USER_ID)));
+ assertTrue(uris.getAllValues().contains(
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, OTHER_USER_ID)));
+ assertFalse(uris.getAllValues().contains(
+ ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, MANAGED_USER_ID)));
+
+ for (ContentValues v : values.getAllValues()) {
+ assertEquals(v.getAsInteger(CallLog.Calls.TYPE),
+ Integer.valueOf(CallLog.Calls.INCOMING_TYPE));
+ }
}
@MediumTest
@@ -929,48 +953,26 @@
}
private void verifyNoInsertion() {
- try {
- Thread.sleep(TEST_TIMEOUT_MILLIS);
- verify(mContentProvider, never()).insert(any(String.class),
- any(Uri.class), any(ContentValues.class));
- } catch (android.os.RemoteException e) {
- fail("Remote exception occurred during test execution");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ SystemClock.sleep(TEST_TIMEOUT_MILLIS);
+
+ verify(mContentProvider, never()).insert(any(Uri.class), any(ContentValues.class));
}
-
private void verifyNoInsertionInUser(int userId) {
- try {
- Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
- Thread.sleep(TEST_TIMEOUT_MILLIS);
- verify(getContentProviderForUser(userId), never())
- .insert(any(String.class), eq(uri), any(ContentValues.class));
- } catch (android.os.RemoteException e) {
- fail("Remote exception occurred during test execution");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ SystemClock.sleep(TEST_TIMEOUT_MILLIS);
+
+ Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
+ verify(mContentProvider, never()).insert(eq(uri), any(ContentValues.class));
}
private ContentValues verifyInsertionWithCapture(int userId) {
+ Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
- try {
- Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
- verify(getContentProviderForUser(userId), timeout(TEST_TIMEOUT_MILLIS).atLeastOnce())
- .insert(any(String.class), eq(uri), captor.capture());
- } catch (android.os.RemoteException e) {
- fail("Remote exception occurred during test execution");
- }
-
+ verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).times(1)).insert(
+ eq(uri), captor.capture());
return captor.getValue();
}
- private IContentProvider getContentProviderForUser(int userId) {
- return mContext.getContentResolver().acquireProvider(userId + "@call_log");
- }
-
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/CallRecordingTonePlayerTest.java b/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java
index 5151d4c..b5c6468 100644
--- a/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java
@@ -22,22 +22,37 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+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.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
+import android.media.MediaPlayer;
import android.media.MediaRecorder;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.MediumTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallRecordingTonePlayer;
+import com.android.server.telecom.CallState;
import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.Timeouts;
import org.junit.After;
import org.junit.Before;
@@ -48,6 +63,7 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import java.util.ArrayList;
import java.util.List;
@@ -62,22 +78,29 @@
private static final String PHONE_ACCOUNT_CLASS = "MyFancyConnectionService";
private static final String PHONE_ACCOUNT_ID = "1";
private static final String RECORDING_APP_PACKAGE = "com.recording.app";
+ private static final long TEST_RECORDING_TONE_INTERVAL = 300L;
private static final PhoneAccountHandle TEST_PHONE_ACCOUNT = new PhoneAccountHandle(
new ComponentName(PHONE_ACCOUNT_PACKAGE, PHONE_ACCOUNT_CLASS), PHONE_ACCOUNT_ID);
private CallRecordingTonePlayer mCallRecordingTonePlayer;
- private TelecomSystem.SyncRoot mSyncRoot = new TelecomSystem.SyncRoot() { };
- @Mock private AudioManager mAudioManager;
+ private TelecomSystem.SyncRoot mSyncRoot = new TelecomSystem.SyncRoot() {
+ };
+ @Mock
+ private AudioManager mAudioManager;
+ @Mock
+ private Timeouts.Adapter mTimeouts;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
+ when(mTimeouts.getCallRecordingToneRepeatIntervalMillis(nullable(ContentResolver.class)))
+ .thenReturn(500L);
mCallRecordingTonePlayer = new CallRecordingTonePlayer(
mComponentContextFixture.getTestDouble().getApplicationContext(),
- mAudioManager, mSyncRoot);
+ mAudioManager, mTimeouts, mSyncRoot);
when(mAudioManager.getActiveRecordingConfigurations()).thenReturn(null);
}
@@ -87,6 +110,45 @@
super.tearDown();
}
+ @MediumTest
+ @Test
+ public void testToneLooping() throws Exception {
+ MediaPlayer mockMediaPlayer = mock(MediaPlayer.class);
+ MockitoSession session = ExtendedMockito.mockitoSession().mockStatic(MediaPlayer.class)
+ .startMocking();
+ ExtendedMockito.doReturn(mockMediaPlayer).when(() ->
+ MediaPlayer.create(nullable(Context.class), anyInt()));
+
+ when(mAudioManager.getActiveRecordingConfigurations()).thenReturn(
+ getAudioRecordingConfig(RECORDING_APP_PACKAGE));
+
+ AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
+ when(mockAudioDeviceInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_TELEPHONY);
+ when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS))
+ .thenReturn(new AudioDeviceInfo[] { mockAudioDeviceInfo });
+
+ Call call = addValidCall();
+ when(call.isActive()).thenReturn(true);
+ mCallRecordingTonePlayer.onCallStateChanged(call, CallState.NEW, CallState.ACTIVE);
+
+ waitForHandlerAction(Handler.getMain(), TEST_TIMEOUT);
+ verify(mockMediaPlayer).start();
+
+ // Sleep for 4x the interval, then make sure it played more. No exact count,
+ // since timing can be tricky in tests.
+ Thread.sleep(TEST_RECORDING_TONE_INTERVAL * 4);
+ verify(mockMediaPlayer, atLeast(2)).start();
+ reset(mockMediaPlayer);
+
+ // Remove the call and verify that we're not starting the tone anymore.
+ mCallRecordingTonePlayer.onCallRemoved(call);
+ Thread.sleep(TEST_RECORDING_TONE_INTERVAL * 3 + 50);
+ verify(mockMediaPlayer, never()).start();
+ verify(mockMediaPlayer).release();
+
+ session.finishMocking();
+ }
+
/**
* Ensures that child calls are not tracked.
*/
diff --git a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
index 90d4dee..ff16880 100644
--- a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
@@ -23,11 +23,15 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.UserHandle;
import android.telecom.GatewayInfo;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
+
+import com.android.internal.telecom.ICallRedirectionAdapter;
import com.android.internal.telecom.ICallRedirectionService;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallsManager;
@@ -39,24 +43,30 @@
import com.android.server.telecom.callredirection.CallRedirectionProcessor;
import com.android.server.telecom.callredirection.CallRedirectionProcessorHelper;
+import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.junit.Before;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
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;
@@ -82,6 +92,11 @@
@Mock private Timeouts.Adapter mTimeoutsAdapter;
+ private static final Uri ORIGINAL_NUMBER_WITH_POST_DIAL = Uri.parse("tel:6505551212,,,1234");
+ private static final Uri ORIGINAL_NUMBER_NO_POST_DIAL = Uri.parse("tel:6505551212");
+ private static final Uri REDIRECTED_GATEWAY_NUMBER = Uri.parse("tel:6505551213");
+ private static final Uri REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL =
+ Uri.parse("tel:6505551213,,,1234");
private static final String USER_DEFINED_PKG_NAME = "user_defined_pkg";
private static final String USER_DEFINED_CLS_NAME = "user_defined_cls";
private static final String CARRIER_PKG_NAME = "carrier_pkg";
@@ -130,6 +145,8 @@
@Override
@After
public void tearDown() throws Exception {
+ mProcessor.getHandler().removeCallbacksAndMessages(null);
+ waitForHandlerAction(new Handler(Looper.getMainLooper()), TelecomSystemTest.TEST_TIMEOUT);
super.tearDown();
}
@@ -158,7 +175,11 @@
}
private void startProcessWithNoGateWayInfo() {
- mProcessor = new CallRedirectionProcessor(mContext, mCallsManager, mCall, mHandle,
+ startProcessWithNoGateWayInfo(mHandle);
+ }
+
+ private void startProcessWithNoGateWayInfo(Uri handle) {
+ mProcessor = new CallRedirectionProcessor(mContext, mCallsManager, mCall, handle,
mPhoneAccountRegistrar, null, SPEAKER_PHONE_ON, VIDEO_STATE);
mProcessor.setCallRedirectionServiceHelper(mCallRedirectionProcessorHelper);
}
@@ -287,4 +308,50 @@
eq(mPhoneAccountHandle), eq(mGatewayInfo), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
}
+
+ @Test
+ public void testStripPostDialDigits() throws Exception {
+ startProcessWithNoGateWayInfo(ORIGINAL_NUMBER_WITH_POST_DIAL);
+ enableUserDefinedCallRedirectionService();
+ disableCarrierCallRedirectionService();
+
+ mProcessor.performCallRedirection();
+
+ // Capture binding and mock it out.
+ ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(
+ ServiceConnection.class);
+ verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
+ serviceConnectionCaptor.capture(), anyInt(), any(UserHandle.class));
+
+ // Mock out a service which performed a redirection
+ IBinder mockBinder = mock(IBinder.class);
+ ICallRedirectionService mockCallRedirectionService = mock(ICallRedirectionService.class);
+ when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockCallRedirectionService);
+ serviceConnectionCaptor.getValue().onServiceConnected(
+ USER_DEFINED_SERVICE_TEST_COMPONENT_NAME, mockBinder);
+
+ ArgumentCaptor<ICallRedirectionAdapter> redirectionAdapterCaptor = ArgumentCaptor.forClass(
+ ICallRedirectionAdapter.class);
+ ArgumentCaptor<Uri> uriArgumentCaptor = ArgumentCaptor.forClass(Uri.class);
+ verify(mockCallRedirectionService, times(1)).placeCall(redirectionAdapterCaptor.capture(),
+ uriArgumentCaptor.capture(), any(), anyBoolean());
+
+ // Verify the service did not get passed post-dial digits.
+ assertEquals(ORIGINAL_NUMBER_NO_POST_DIAL, uriArgumentCaptor.getValue());
+
+ // Pretend it was verified.
+ redirectionAdapterCaptor.getValue().redirectCall(REDIRECTED_GATEWAY_NUMBER,
+ mPhoneAccountHandle, false);
+
+ waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY);
+
+ ArgumentCaptor<GatewayInfo> gatewayInfoArgumentCaptor = ArgumentCaptor.forClass(
+ GatewayInfo.class);
+ verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall),
+ eq(ORIGINAL_NUMBER_WITH_POST_DIAL), eq(mPhoneAccountHandle),
+ gatewayInfoArgumentCaptor.capture(), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
+ eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
+ assertEquals(REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL,
+ gatewayInfoArgumentCaptor.getValue().getGatewayAddress());
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
deleted file mode 100644
index 6f37fdc..0000000
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.telecom.tests;
-
-import android.Manifest;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.net.Uri;
-import android.os.PersistableBundle;
-import android.os.UserHandle;
-import android.provider.CallLog;
-import android.provider.CallLog.Calls;
-import android.telecom.TelecomManager;
-import android.telephony.CarrierConfigManager;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.telecom.CallerInfo;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallScreeningServiceHelper;
-import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.CallsManager;
-import com.android.server.telecom.ParcelableCallUtils;
-import com.android.server.telecom.PhoneAccountRegistrar;
-import com.android.server.telecom.RoleManagerAdapter;
-import com.android.server.telecom.TelecomServiceImpl;
-import com.android.server.telecom.TelecomSystem;
-import com.android.server.telecom.callfiltering.CallFilterResultCallback;
-import com.android.server.telecom.callfiltering.CallFilteringResult;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-import com.android.server.telecom.callfiltering.CallScreeningServiceController;
-
-import org.junit.After;
-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 java.util.Collections;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(JUnit4.class)
-public class CallScreeningServiceControllerTest extends TelecomTestCase {
-
- private static final String CALL_ID = "u89prgt9ps78y5";
- private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");
- private static final String DEFAULT_DIALER_PACKAGE = "com.android.dialer";
- private static final String PKG_NAME = "com.android.services.telecom.tests";
- private static final String CLS_NAME = "CallScreeningService";
- private static final String APP_NAME = "Screeny McScreenface";
- private static final ComponentName CARRIER_DEFINED_CALL_SCREENING = new ComponentName(
- "com.android.carrier", "com.android.carrier.callscreeningserviceimpl");
- private static final ComponentName DEFAULT_DIALER_CALL_SCREENING = new ComponentName(
- "com.android.dialer", "com.android.dialer.callscreeningserviceimpl");
- private static final ComponentName USER_CHOSEN_CALL_SCREENING = new ComponentName(
- "com.android.userchosen", "com.android.userchosen.callscreeningserviceimpl");
- private static final CallFilteringResult PASS_RESULT = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- @Mock
- Context mContext;
- @Mock
- Call mCall;
- @Mock
- CallsManager mCallsManager;
- @Mock
- RoleManagerAdapter mRoleManagerAdapter;
- @Mock
- CarrierConfigManager mCarrierConfigManager;
- @Mock
- PackageManager mPackageManager;
- @Mock
- ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
- @Mock
- PhoneAccountRegistrar mPhoneAccountRegistrar;
- CallScreeningServiceHelper.AppLabelProxy mAppLabelProxy =
- new CallScreeningServiceHelper.AppLabelProxy() {
- @Override
- public CharSequence getAppLabel(String packageName) {
- return APP_NAME;
- }
- };
- @Mock
- private CallFilterResultCallback mCallback;
- @Mock
- private TelecomManager mTelecomManager;
- @Mock
- private CallerInfoLookupHelper mCallerInfoLookupHelper;
- private ResolveInfo mResolveInfo;
- private TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter =
- spy(new CallScreeningServiceFilterTest.SettingsSecureAdapterFake());
- private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {
- };
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- when(mRoleManagerAdapter.getCallCompanionApps()).thenReturn(Collections.emptyList());
- when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(null);
- when(mCallsManager.getRoleManagerAdapter()).thenReturn(mRoleManagerAdapter);
- when(mCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mCall.getId()).thenReturn(CALL_ID);
-
- setCarrierDefinedCallScreeningApplication();
- when(TelecomManager.from(mContext)).thenReturn(mTelecomManager);
- when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
-
- mResolveInfo = new ResolveInfo() {{
- serviceInfo = new ServiceInfo();
- serviceInfo.packageName = PKG_NAME;
- serviceInfo.name = CLS_NAME;
- serviceInfo.permission = Manifest.permission.BIND_SCREENING_SERVICE;
- }};
-
- when(mPackageManager.queryIntentServicesAsUser(nullable(Intent.class), anyInt(), anyInt()))
- .thenReturn(Collections.singletonList(mResolveInfo));
- when(mParcelableCallUtilsConverter.toParcelableCall(
- eq(mCall), anyBoolean(), eq(mPhoneAccountRegistrar))).thenReturn(null);
- when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
- anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
- when(mCall.getHandle()).thenReturn(TEST_HANDLE);
- }
-
- @Override
- @After
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- @SmallTest
- @Test
- public void testAllAllowCall() {
- when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(
- USER_CHOSEN_CALL_SCREENING.getPackageName());
- CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
- mCallsManager, mPhoneAccountRegistrar,
- mParcelableCallUtilsConverter, mLock,
- mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
-
- controller.startFilterLookup(mCall, mCallback);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName());
-
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.contactExists = false;
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- DEFAULT_DIALER_CALL_SCREENING.getPackageName());
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT, USER_CHOSEN_CALL_SCREENING
- .getPackageName());
-
- verify(mContext, times(3)).bindServiceAsUser(any(Intent.class), any(ServiceConnection
- .class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- verify(mCallback).onCallFilteringComplete(eq(mCall), eq(PASS_RESULT));
- }
-
- @SmallTest
- @Test
- public void testCarrierAllowCallAndContactExists() {
- CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
- mCallsManager,
- mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mLock,
- mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
-
- controller.startFilterLookup(mCall, mCallback);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName());
-
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.contactExists = true;
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-
- verify(mContext, times(1)).bindServiceAsUser(any(Intent.class), any(ServiceConnection
- .class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- verify(mCallback).onCallFilteringComplete(eq(mCall), eq(PASS_RESULT));
- }
-
- @SmallTest
- @Test
- public void testCarrierCallScreeningRejectCall() {
- CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
- mCallsManager,
- mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mLock,
- mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
-
- controller.startFilterLookup(mCall, mCallback);
-
- CallFilteringResult expectedResult = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(false)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(
- CARRIER_DEFINED_CALL_SCREENING.flattenToString())
- .build();
-
- controller.onCallScreeningFilterComplete(mCall, expectedResult,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName());
-
- verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
- any(ServiceConnection.class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- verify(mCallback)
- .onCallFilteringComplete(eq(mCall), eq(expectedResult));
- }
-
- @SmallTest
- @Test
- public void testDefaultDialerRejectCall() {
- when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(
- USER_CHOSEN_CALL_SCREENING.getPackageName());
- CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
- mCallsManager,
- mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mLock,
- mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
-
- controller.startFilterLookup(mCall, mCallback);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName());
-
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.contactExists = false;
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-
- CallFilteringResult.Builder resultBuilder = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString());
-
- CallFilteringResult providedResult = resultBuilder
- .setShouldAddToCallLog(false)
- .build();
-
- controller.onCallScreeningFilterComplete(mCall, providedResult,
- DEFAULT_DIALER_CALL_SCREENING.getPackageName());
-
- verify(mContext, times(3)).bindServiceAsUser(any(Intent.class),
- any(ServiceConnection.class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- CallFilteringResult expectedResult = resultBuilder
- .setShouldAddToCallLog(true)
- .build();
-
- verify(mCallback).onCallFilteringComplete(eq(mCall), eq(expectedResult));
- }
-
- @SmallTest
- @Test
- public void testUserChosenRejectCall() {
- when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(
- USER_CHOSEN_CALL_SCREENING.getPackageName());
- CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
- mCallsManager,
- mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mLock,
- mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
-
- controller.startFilterLookup(mCall, mCallback);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName());
-
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.contactExists = false;
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- DEFAULT_DIALER_CALL_SCREENING.getPackageName());
-
- CallFilteringResult.Builder resultBuilder = new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString());
- CallFilteringResult providedResult = resultBuilder
- .setShouldAddToCallLog(false)
- .build();
-
- controller.onCallScreeningFilterComplete(mCall, providedResult,
- USER_CHOSEN_CALL_SCREENING.getPackageName());
-
- verify(mContext, times(3)).bindServiceAsUser(any(Intent.class),
- any(ServiceConnection.class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- CallFilteringResult expectedResult = resultBuilder
- .setShouldAddToCallLog(true)
- .build();
-
- verify(mCallback).onCallFilteringComplete(eq(mCall), eq(expectedResult));
- }
-
- /**
- * This test verifies that where the default dialer role is filled by the same app as the caller
- * id and spam role, we will only bind to that call screening service once.
- */
- @SmallTest
- @Test
- public void testOnlyBindOnce() {
- // Assume the user chose the default dialer to also fill the caller id and spam role.
- when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(
- DEFAULT_DIALER_CALL_SCREENING.getPackageName());
- CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
- mCallsManager,
- mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mLock,
- mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
-
- controller.startFilterLookup(mCall, mCallback);
-
- controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName());
-
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.contactExists = false;
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-
- controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult.Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(false)
- .setShouldShowNotification(true)
- .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(
- DEFAULT_DIALER_CALL_SCREENING.flattenToString())
- .build(),
- DEFAULT_DIALER_CALL_SCREENING.getPackageName());
-
- controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult.Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(false)
- .setShouldShowNotification(true)
- .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString())
- .build(), USER_CHOSEN_CALL_SCREENING.getPackageName());
-
- // Expect to bind twice; once to the carrier defined service, and then again to the default
- // dialer.
- verify(mContext, times(2)).bindServiceAsUser(any(Intent.class),
- any(ServiceConnection.class),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- // Expect filtering to complete only a single time from the default dialer service.
- verify(mCallback, times(1)).onCallFilteringComplete(eq(mCall),
- eq(new CallFilteringResult.Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(
- DEFAULT_DIALER_CALL_SCREENING.flattenToString())
- .build()));
- }
-
- private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart() {
- return verifyLookupStart(TEST_HANDLE);
- }
-
- private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart(Uri handle) {
-
- ArgumentCaptor<CallerInfoLookupHelper.OnQueryCompleteListener> captor =
- ArgumentCaptor.forClass(CallerInfoLookupHelper.OnQueryCompleteListener.class);
- verify(mCallerInfoLookupHelper).startLookup(eq(handle), captor.capture());
- return captor.getValue();
- }
-
- private void setCarrierDefinedCallScreeningApplication() {
- String carrierDefined = CARRIER_DEFINED_CALL_SCREENING.flattenToString();
- PersistableBundle bundle = new PersistableBundle();
- bundle.putString(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING,
- carrierDefined);
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(mCarrierConfigManager);
- when(mCarrierConfigManager.getConfig()).thenReturn(bundle);
- }
-
- public static class SettingsSecureAdapterFake implements
- TelecomServiceImpl.SettingsSecureAdapter {
- @Override
- public void putStringForUser(ContentResolver resolver, String name, String value,
- int userHandle) {
-
- }
-
- @Override
- public String getStringForUser(ContentResolver resolver, String name, int userHandle) {
- return USER_CHOSEN_CALL_SCREENING.flattenToString();
- }
- }
-}
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index 7b3a499..c7b3a7e 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -11,14 +11,25 @@
* 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
+ * limitations under the License.
*/
package com.android.server.telecom.tests;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.Manifest;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
@@ -26,29 +37,23 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.CallLog.Calls;
+import android.provider.CallLog;
import android.telecom.CallScreeningService;
import android.telecom.ParcelableCall;
import android.telecom.TelecomManager;
-import android.telephony.CarrierConfigManager;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telecom.ICallScreeningAdapter;
import com.android.internal.telecom.ICallScreeningService;
+import com.android.server.telecom.AppLabelProxy;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.ParcelableCallUtils;
import com.android.server.telecom.PhoneAccountRegistrar;
-import com.android.server.telecom.TelecomServiceImpl;
import com.android.server.telecom.callfiltering.CallFilteringResult;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
-import com.android.server.telecom.TelecomSystem;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,94 +62,41 @@
import org.mockito.Mock;
import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
public class CallScreeningServiceFilterTest extends TelecomTestCase {
+ static @Mock Call mCall;
@Mock Context mContext;
- @Mock CallsManager mCallsManager;
- @Mock PhoneAccountRegistrar mPhoneAccountRegistrar;
- @Mock ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
- private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
-
- @Mock Call mCall;
- @Mock CallScreeningServiceFilter.CallScreeningFilterResultCallback mCallback;
-
+ @Mock TelecomManager mTelecomManager;
@Mock PackageManager mPackageManager;
- @Mock IBinder mBinder;
+ @Mock CallsManager mCallsManager;
+ @Mock AppLabelProxy mAppLabelProxy;
+ @Mock ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
+ @Mock PhoneAccountRegistrar mPhoneAccountRegistrar;
@Mock ICallScreeningService mCallScreeningService;
- @Mock CarrierConfigManager mCarrierConfigManager;
- @Mock private TelecomManager mTelecomManager;
- private TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter =
- spy(new SettingsSecureAdapterFake());
+ @Mock IBinder mBinder;
+ private static final String CALL_ID = "u89prgt9ps78y5";
private static final String PKG_NAME = "com.android.services.telecom.tests";
private static final String APP_NAME = "TeleTestApp";
private static final String CLS_NAME = "CallScreeningService";
private static final ComponentName COMPONENT_NAME = new ComponentName(PKG_NAME, CLS_NAME);
- private static final String CALL_ID = "u89prgt9ps78y5";
- private static final String DEFAULT_DIALER_PACKAGE = "com.android.dialer";
- private static final ComponentName CARRIER_DEFINED_CALL_SCREENING = new ComponentName(
- "com.android.carrier", "com.android.carrier.callscreeningserviceimpl");
- private static final String CARRIER_DEFINED_CALL_SCREENING_APP_NAME = "GMob";
- private static final ComponentName DEFAULT_DIALER_CALL_SCREENING = new ComponentName(
- "com.android.dialer", "com.android.dialer.callscreeningserviceimpl");
- private static final String DEFAULT_DIALER_APP_NAME = "Dialer";
- private static final ComponentName USER_CHOSEN_CALL_SCREENING = new ComponentName(
- "com.android.userchosen", "com.android.userchosen.callscreeningserviceimpl");
- private static final String USER_CHOSEN_CALL_SCREENING_APP_NAME = "UserChosen";
private ResolveInfo mResolveInfo;
+ private CallFilteringResult inputResult;
- private static final CallFilteringResult PASS_RESULT = new Builder()
+ private static final CallFilteringResult PASS_RESULT = new CallFilteringResult.Builder()
.setShouldAllowCall(true)
.setShouldReject(false)
.setShouldAddToCallLog(true)
.setShouldShowNotification(true)
.build();
- private static final CallFilteringResult PASS_RESULT_WITH_SILENCE = new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
-
- private CallScreeningServiceFilter mFilter;
-
- public static class SettingsSecureAdapterFake implements
- TelecomServiceImpl.SettingsSecureAdapter {
- @Override
- public void putStringForUser(ContentResolver resolver, String name, String value,
- int userHandle) {
-
- }
-
- @Override
- public String getStringForUser(ContentResolver resolver, String name, int userHandle) {
- return USER_CHOSEN_CALL_SCREENING.flattenToString();
- }
- }
-
@Override
@Before
public void setUp() throws Exception {
super.setUp();
- when(mCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mCall.getId()).thenReturn(CALL_ID);
- doReturn(mCallScreeningService).when(mBinder).queryLocalInterface(anyString());
mResolveInfo = new ResolveInfo() {{
serviceInfo = new ServiceInfo();
@@ -152,223 +104,248 @@
serviceInfo.name = CLS_NAME;
serviceInfo.permission = Manifest.permission.BIND_SCREENING_SERVICE;
}};
+ inputResult = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldAddToCallLog(true)
+ .setShouldShowNotification(true)
+ .build();
- mFilter = new CallScreeningServiceFilter(mContext, mCallsManager, mPhoneAccountRegistrar,
- mParcelableCallUtilsConverter, mLock, mSettingsSecureAdapter);
-
- when(mPackageManager.queryIntentServicesAsUser(nullable(Intent.class), anyInt(), anyInt()))
- .thenReturn(Collections.singletonList(mResolveInfo));
+ when(mCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
+ when(mCall.getId()).thenReturn(CALL_ID);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getSystemService(TelecomManager.class))
+ .thenReturn(mTelecomManager);
+ when(mTelecomManager.getSystemDialerPackage()).thenReturn(PKG_NAME);
+ when(mAppLabelProxy.getAppLabel(PKG_NAME)).thenReturn(APP_NAME);
when(mParcelableCallUtilsConverter.toParcelableCall(
eq(mCall), anyBoolean(), eq(mPhoneAccountRegistrar))).thenReturn(null);
when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
- }
-
- @Override
- @After
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- @SmallTest
- @Test
- public void testNoPackageName() {
- mFilter.startCallScreeningFilter(mCall, mCallback, null, null,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(null));
- }
-
- @SmallTest
- @Test
- public void testNoResolveEntries() {
when(mPackageManager.queryIntentServicesAsUser(nullable(Intent.class), anyInt(), anyInt()))
- .thenReturn(Collections.emptyList());
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(PKG_NAME));
+ .thenReturn(Collections.singletonList(mResolveInfo));
+ doReturn(mCallScreeningService).when(mBinder).queryLocalInterface(anyString());
}
@SmallTest
@Test
- public void testBadResolveEntry() {
- mResolveInfo.serviceInfo = null;
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(PKG_NAME));
+ public void testNoPackageName() throws Exception {
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, null,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ assertEquals(PASS_RESULT,
+ filter.startFilterLookup(inputResult).toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
}
@SmallTest
@Test
- public void testPermissionlessFilterService() {
- mResolveInfo.serviceInfo.permission = null;
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(PKG_NAME));
- }
-
- @SmallTest
- @Test
- public void testContextFailToBind() {
+ public void testContextFailToBind() throws Exception {
when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
anyInt(), eq(UserHandle.CURRENT))).thenReturn(false);
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(PKG_NAME));
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ assertEquals(PASS_RESULT,
+ filter.startFilterLookup(inputResult).toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
}
@SmallTest
@Test
- public void testExceptionInScreeningService() throws Exception {
- doThrow(new RemoteException()).when(mCallScreeningService).screenCall(
- nullable(ICallScreeningAdapter.class), nullable(ParcelableCall.class));
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- ServiceConnection serviceConnection = verifyBindingIntent();
- serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(PKG_NAME));
+ public void testNoResolveEntries() throws Exception {
+ when(mPackageManager.queryIntentServicesAsUser(nullable(Intent.class), anyInt(), anyInt()))
+ .thenReturn(Collections.emptyList());
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ assertEquals(PASS_RESULT,
+ filter.startFilterLookup(inputResult).toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
+ }
+
+ @SmallTest
+ @Test
+ public void testBadResolveEntry() throws Exception {
+ mResolveInfo.serviceInfo = null;
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ assertEquals(PASS_RESULT,
+ filter.startFilterLookup(inputResult).toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
+ }
+
+ @SmallTest
+ @Test
+ public void testNoBindingCondition() {
+ // Make sure there will be no binding if the package has no READ_CONTACT permission and
+ // contact exist.
+ when(mPackageManager.checkPermission(Manifest.permission.READ_CONTACTS, PKG_NAME))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
+ anyInt(), eq(UserHandle.CURRENT))).thenThrow(new SecurityException());
+ inputResult.contactExists = true;
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_USER_CHOSEN, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ filter.startFilterLookup(inputResult);
+ }
+
+ @SmallTest
+ @Test
+ public void testBindingCondition() {
+ // Make sure there will be binding if the package has READ_CONTACT permission and contact
+ // exist.
+ inputResult.contactExists = true;
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ filter.startFilterLookup(inputResult);
+ ServiceConnection connection = verifyBindingIntent();
+ connection.onServiceDisconnected(COMPONENT_NAME);
+ }
+
+ @SmallTest
+ @Test
+ public void testUnbindingException() {
+ // Make sure that exceptions when unbinding won't make the device crash.
+ doThrow(new IllegalArgumentException()).when(mContext)
+ .unbindService(nullable(ServiceConnection.class));
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ filter.startFilterLookup(inputResult);
+ filter.unbindCallScreeningService();
}
@SmallTest
@Test
public void testAllowCall() throws Exception {
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
+
ServiceConnection serviceConnection = verifyBindingIntent();
+
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
csAdapter.allowCall(CALL_ID);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT), eq(PKG_NAME));
+ assertEquals(PASS_RESULT,
+ resultFuture.toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
+ serviceConnection.onServiceDisconnected(COMPONENT_NAME);
+ }
+
+ @SmallTest
+ @Test
+ public void testDisallowCall() throws Exception {
+ CallFilteringResult expectedResult = new CallFilteringResult.Builder()
+ .setShouldAllowCall(false)
+ .setShouldReject(true)
+ .setShouldSilence(false)
+ .setShouldAddToCallLog(true)
+ .setShouldShowNotification(true)
+ .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+ .setCallScreeningAppName(APP_NAME)
+ .setCallScreeningComponentName(COMPONENT_NAME.flattenToString())
+ .build();
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
+
+ ServiceConnection serviceConnection = verifyBindingIntent();
+
+ serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
+ ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
+ csAdapter.disallowCall(CALL_ID,
+ true, // shouldReject
+ true, //shouldAddToCallLog
+ true, // shouldShowNotification
+ COMPONENT_NAME);
+ assertEquals(expectedResult,
+ resultFuture.toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
+ serviceConnection.onServiceDisconnected(COMPONENT_NAME);
}
@SmallTest
@Test
public void testSilenceCall() throws Exception {
- mFilter.startCallScreeningFilter(mCall, mCallback, PKG_NAME, APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
+ CallFilteringResult expectedResult = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(true)
+ .setShouldAddToCallLog(true)
+ .setShouldShowNotification(true)
+ .build();
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
+
ServiceConnection serviceConnection = verifyBindingIntent();
+
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
csAdapter.silenceCall(CALL_ID);
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(PASS_RESULT_WITH_SILENCE),
- eq(PKG_NAME));
+ assertEquals(expectedResult,
+ resultFuture.toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
+
+ serviceConnection.onServiceDisconnected(COMPONENT_NAME);
}
@SmallTest
@Test
- public void testDisallowCallForCarrierDefined() throws Exception {
- mResolveInfo.serviceInfo.packageName = CARRIER_DEFINED_CALL_SCREENING.getPackageName();
- mResolveInfo.serviceInfo.name = CARRIER_DEFINED_CALL_SCREENING.getClassName();
- setCarrierDefinedCallScreeningApplication();
- when(TelecomManager.from(mContext)).thenReturn(mTelecomManager);
- when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
+ public void testScreenCallFurther() throws Exception {
+ CallFilteringResult expectedResult = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(false)
+ .setShouldScreenViaAudio(true)
+ .setCallScreeningAppName(APP_NAME)
+ .build();
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+ CallScreeningServiceFilter.PACKAGE_TYPE_DEFAULT_DIALER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+ CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
- mFilter.startCallScreeningFilter(mCall, mCallback,
- CARRIER_DEFINED_CALL_SCREENING.getPackageName(),
- CARRIER_DEFINED_CALL_SCREENING_APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_CARRIER);
ServiceConnection serviceConnection = verifyBindingIntent();
+
serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.disallowCall(CALL_ID,
- true, // shouldReject
- false, // shouldAddToCallLog
- true, // shouldShowNotification
- CARRIER_DEFINED_CALL_SCREENING
- );
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(false)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(CARRIER_DEFINED_CALL_SCREENING_APP_NAME)
- .setCallScreeningComponentName(
- CARRIER_DEFINED_CALL_SCREENING.flattenToString())
- .build()),
- eq(CARRIER_DEFINED_CALL_SCREENING.getPackageName()));
- }
-
- @SmallTest
- @Test
- public void testDisallowCallForDefaultDialer() throws Exception {
- mResolveInfo.serviceInfo.packageName = DEFAULT_DIALER_CALL_SCREENING.getPackageName();
- mResolveInfo.serviceInfo.name = DEFAULT_DIALER_CALL_SCREENING.getClassName();
- setCarrierDefinedCallScreeningApplication();
- when(TelecomManager.from(mContext)).thenReturn(mTelecomManager);
- when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
-
- mFilter.startCallScreeningFilter(mCall, mCallback,
- DEFAULT_DIALER_CALL_SCREENING.getPackageName(),
- DEFAULT_DIALER_APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_DEFAULT_DIALER);
- ServiceConnection serviceConnection = verifyBindingIntent();
- serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
- ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.disallowCall(CALL_ID,
- true, // shouldReject
- false, // shouldAddToCallLog
- true, // shouldShowNotification
- DEFAULT_DIALER_CALL_SCREENING
- );
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(DEFAULT_DIALER_APP_NAME)
- .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString())
- .build()),
- eq(DEFAULT_DIALER_CALL_SCREENING.getPackageName()));
- }
-
- @SmallTest
- @Test
- public void testDisallowCallForUserChosen() throws Exception {
- mResolveInfo.serviceInfo.packageName = USER_CHOSEN_CALL_SCREENING.getPackageName();
- mResolveInfo.serviceInfo.name = USER_CHOSEN_CALL_SCREENING.getClassName();
- setCarrierDefinedCallScreeningApplication();
- when(TelecomManager.from(mContext)).thenReturn(mTelecomManager);
- when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
-
- mFilter.startCallScreeningFilter(mCall, mCallback,
- USER_CHOSEN_CALL_SCREENING.getPackageName(),
- USER_CHOSEN_CALL_SCREENING_APP_NAME,
- CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
- ServiceConnection serviceConnection = verifyBindingIntent();
- serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
- ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.disallowCall(CALL_ID,
- true, // shouldReject
- false, // shouldAddToCallLog
- true, // shouldShowNotification
- USER_CHOSEN_CALL_SCREENING
- );
- verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(USER_CHOSEN_CALL_SCREENING_APP_NAME)
- .setCallScreeningComponentName(USER_CHOSEN_CALL_SCREENING.flattenToString())
- .build()),
- eq(USER_CHOSEN_CALL_SCREENING.getPackageName()));
+ csAdapter.screenCallFurther(CALL_ID);
+ assertEquals(expectedResult,
+ resultFuture.toCompletableFuture().get(
+ CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
+ TimeUnit.MILLISECONDS));
+ serviceConnection.onServiceDisconnected(COMPONENT_NAME);
}
private ServiceConnection verifyBindingIntent() {
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- ArgumentCaptor<ServiceConnection> serviceCaptor =
- ArgumentCaptor.forClass(ServiceConnection.class);
- verify(mContext).bindServiceAsUser(intentCaptor.capture(), serviceCaptor.capture(),
+ ArgumentCaptor<ServiceConnection> serviceCaptor = ArgumentCaptor
+ .forClass(ServiceConnection.class);
+ verify(mContext, timeout(CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT))
+ .bindServiceAsUser(intentCaptor.capture(), serviceCaptor.capture(),
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
eq(UserHandle.CURRENT));
Intent capturedIntent = intentCaptor.getValue();
assertEquals(CallScreeningService.SERVICE_INTERFACE, capturedIntent.getAction());
assertEquals(mResolveInfo.serviceInfo.packageName, capturedIntent.getPackage());
- assertEquals(new ComponentName(mResolveInfo.serviceInfo.packageName, mResolveInfo
- .serviceInfo.name), capturedIntent.getComponent());
+ assertEquals(new ComponentName(mResolveInfo.serviceInfo.packageName,
+ mResolveInfo.serviceInfo.name), capturedIntent.getComponent());
return serviceCaptor.getValue();
}
@@ -376,17 +353,9 @@
private ICallScreeningAdapter getCallScreeningAdapter() throws Exception {
ArgumentCaptor<ICallScreeningAdapter> captor =
ArgumentCaptor.forClass(ICallScreeningAdapter.class);
- verify(mCallScreeningService).screenCall(captor.capture(), nullable(ParcelableCall.class));
+ verify(mCallScreeningService,
+ timeout(CallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT))
+ .screenCall(captor.capture(), nullable(ParcelableCall.class));
return captor.getValue();
}
-
- private void setCarrierDefinedCallScreeningApplication() {
- String carrierDefined = CARRIER_DEFINED_CALL_SCREENING.flattenToString();
- PersistableBundle bundle = new PersistableBundle();
- bundle.putString(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING,
- carrierDefined);
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(mCarrierConfigManager);
- when(mCarrierConfigManager.getConfig()).thenReturn(bundle);
- }
}
diff --git a/tests/src/com/android/server/telecom/tests/CallTest.java b/tests/src/com/android/server/telecom/tests/CallTest.java
index 0566999..541d278 100644
--- a/tests/src/com/android/server/telecom/tests/CallTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallTest.java
@@ -225,6 +225,54 @@
@Test
@SmallTest
+ public void testCanPullCallRemovedDuringEmergencyCall() {
+ Call call = new Call(
+ "1", /* callId */
+ mContext,
+ mMockCallsManager,
+ mLock,
+ null /* ConnectionServiceRepository */,
+ mMockPhoneNumberUtilsAdapter,
+ TEST_ADDRESS,
+ null /* GatewayInfo */,
+ null /* connectionManagerPhoneAccountHandle */,
+ SIM_1_HANDLE,
+ Call.CALL_DIRECTION_INCOMING,
+ false /* shouldAttachToExistingConnection*/,
+ false /* isConference */,
+ mMockClockProxy,
+ mMockToastProxy);
+ boolean[] hasCalledConnectionCapabilitiesChanged = new boolean[1];
+ call.addListener(new Call.ListenerBase() {
+ @Override
+ public void onConnectionCapabilitiesChanged(Call call) {
+ hasCalledConnectionCapabilitiesChanged[0] = true;
+ }
+ });
+ call.setConnectionService(mMockConnectionService);
+ call.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL);
+ call.setConnectionCapabilities(Connection.CAPABILITY_CAN_PULL_CALL);
+ call.setState(CallState.ACTIVE, "");
+ assertTrue(hasCalledConnectionCapabilitiesChanged[0]);
+ // Capability should be present
+ assertTrue((call.getConnectionCapabilities() | Connection.CAPABILITY_CAN_PULL_CALL) > 0);
+ hasCalledConnectionCapabilitiesChanged[0] = false;
+ // Emergency call in progress
+ call.setIsPullExternalCallSupported(false /*isPullCallSupported*/);
+ assertTrue(hasCalledConnectionCapabilitiesChanged[0]);
+ // Capability should not be present
+ assertEquals(0, call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL);
+ hasCalledConnectionCapabilitiesChanged[0] = false;
+ // Emergency call complete
+ call.setIsPullExternalCallSupported(true /*isPullCallSupported*/);
+ assertTrue(hasCalledConnectionCapabilitiesChanged[0]);
+ // Capability should be present
+ assertEquals(Connection.CAPABILITY_CAN_PULL_CALL,
+ call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL);
+ }
+
+ @Test
+ @SmallTest
public void testCanNotPullCallDuringEmergencyCall() {
Call call = new Call(
"1", /* callId */
@@ -253,4 +301,36 @@
verify(mMockConnectionService, never()).pullExternalCall(any());
verify(mMockToast).show();
}
+
+ @Test
+ @SmallTest
+ public void testCallDirection() {
+ Call call = new Call(
+ "1", /* callId */
+ mContext,
+ mMockCallsManager,
+ mLock,
+ null /* ConnectionServiceRepository */,
+ mMockPhoneNumberUtilsAdapter,
+ TEST_ADDRESS,
+ null /* GatewayInfo */,
+ null /* connectionManagerPhoneAccountHandle */,
+ SIM_1_HANDLE,
+ Call.CALL_DIRECTION_UNDEFINED,
+ false /* shouldAttachToExistingConnection*/,
+ true /* isConference */,
+ mMockClockProxy,
+ mMockToastProxy);
+ boolean[] hasCallDirectionChanged = new boolean[1];
+ call.addListener(new Call.ListenerBase() {
+ @Override
+ public void onCallDirectionChanged(Call call) {
+ hasCallDirectionChanged[0] = true;
+ }
+ });
+ assertFalse(call.isIncoming());
+ call.setCallDirection(Call.CALL_DIRECTION_INCOMING);
+ assertTrue(hasCallDirectionChanged[0]);
+ assertTrue(call.isIncoming());
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index e6fa1d0..3fd5e60 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.tests;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertEquals;
@@ -32,14 +33,20 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+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.Context;
+import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -52,6 +59,7 @@
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
import android.widget.Toast;
import com.android.server.telecom.AsyncRingtonePlayer;
@@ -62,6 +70,7 @@
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.CallsManagerListenerBase;
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory;
@@ -86,6 +95,7 @@
import com.android.server.telecom.WiredHeadsetManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
+import com.android.server.telecom.callfiltering.CallFilteringResult;
import com.android.server.telecom.callfiltering.IncomingCallFilter;
import com.android.server.telecom.ui.AudioProcessingNotification;
import com.android.server.telecom.ui.DisconnectedCallNotifier;
@@ -101,6 +111,8 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -108,6 +120,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -118,13 +132,18 @@
ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
private static final PhoneAccountHandle SIM_2_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.foo/.Blah"), "Sim2");
+ private static final PhoneAccountHandle CONNECTION_MGR_1_HANDLE = new PhoneAccountHandle(
+ ComponentName.unflattenFromString("com.bar/.Conn"), "Cm1");
+ private static final PhoneAccountHandle CONNECTION_MGR_2_HANDLE = new PhoneAccountHandle(
+ ComponentName.unflattenFromString("com.spa/.Conn"), "Cm2");
private static final PhoneAccountHandle VOIP_1_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.voip/.Stuff"), "Voip1");
private static final PhoneAccountHandle SELF_MANAGED_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.baz/.Self"), "Self");
private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
.setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
- | PhoneAccount.CAPABILITY_CALL_PROVIDER)
+ | PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
.setIsEnabled(true)
.build();
private static final PhoneAccount SIM_2_ACCOUNT = new PhoneAccount.Builder(SIM_2_HANDLE, "Sim2")
@@ -623,6 +642,23 @@
@SmallTest
@Test
+ public void testDuplicateAnswerCall() {
+ Call incomingCall = addSpyCall(CallState.RINGING);
+ doAnswer(invocation -> {
+ doReturn(CallState.ANSWERED).when(incomingCall).getState();
+ return null;
+ }).when(incomingCall).answer(anyInt());
+ mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
+ verifyFocusRequestAndExecuteCallback(incomingCall);
+ reset(mConnectionSvrFocusMgr);
+ mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
+ verifyFocusRequestAndExecuteCallback(incomingCall);
+
+ verify(incomingCall, times(2)).answer(anyInt());
+ }
+
+ @SmallTest
+ @Test
public void testAnswerCallWhenOngoingCallCanBeHeld() {
// GIVEN a CallsManager with ongoing call, and this call can be held
Call ongoingCall = addSpyCall();
@@ -989,7 +1025,7 @@
@SmallTest
@Test
public void testHangupActiveCallWhenHeadsetMediaButtonLongPressDuringTwoCalls() {
- // GIVEN an ongoing call
+ // GIVEN an ongoing call
Call ongoingCall = addSpyCall();
doReturn(CallState.ACTIVE).when(ongoingCall).getState();
@@ -1104,7 +1140,7 @@
newEmergencyCall.setHandle(Uri.fromParts("tel", "5551213", null),
TelecomManager.PRESENTATION_ALLOWED);
- assertTrue(mCallsManager.makeRoomForOutgoingCall(newEmergencyCall, true /*isEmergency*/));
+ assertTrue(mCallsManager.makeRoomForOutgoingEmergencyCall(newEmergencyCall));
verify(ongoingCall).disconnect(anyLong(), anyString());
}
@@ -1119,7 +1155,7 @@
newEmergencyCall.setHandle(Uri.fromParts("tel", "5551213", null),
TelecomManager.PRESENTATION_ALLOWED);
- assertTrue(mCallsManager.makeRoomForOutgoingCall(newEmergencyCall, true /*isEmergency*/));
+ assertTrue(mCallsManager.makeRoomForOutgoingEmergencyCall(newEmergencyCall));
verify(ongoingCall).reject(anyBoolean(), any(), any());
}
@@ -1134,7 +1170,7 @@
newEmergencyCall.setHandle(Uri.fromParts("tel", "5551213", null),
TelecomManager.PRESENTATION_ALLOWED);
- assertTrue(mCallsManager.makeRoomForOutgoingCall(newEmergencyCall, true /*isEmergency*/));
+ assertTrue(mCallsManager.makeRoomForOutgoingEmergencyCall(newEmergencyCall));
verify(ongoingCall).disconnect(anyString());
}
@@ -1150,10 +1186,29 @@
newEmergencyCall.setHandle(Uri.fromParts("tel", "5551213", null),
TelecomManager.PRESENTATION_ALLOWED);
- assertTrue(mCallsManager.makeRoomForOutgoingCall(newEmergencyCall, true /*isEmergency*/));
+ assertTrue(mCallsManager.makeRoomForOutgoingEmergencyCall(newEmergencyCall));
verify(ongoingCall).reject(anyBoolean(), any(), any());
}
+ @SmallTest
+ @Test
+ public void testMakeRoomForEmergencyCallDuringActiveAndRingingCallDisconnectRinging() {
+ when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(SIM_1_HANDLE))
+ .thenReturn(SIM_1_ACCOUNT);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ Call ringingCall = addSpyCall(SIM_1_HANDLE, CallState.RINGING);
+
+ Call newEmergencyCall = createCall(SIM_1_HANDLE, CallState.NEW);
+ when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
+ .thenReturn(true);
+ newEmergencyCall.setHandle(Uri.fromParts("tel", "5551213", null),
+ TelecomManager.PRESENTATION_ALLOWED);
+
+ assertTrue(mCallsManager.makeRoomForOutgoingEmergencyCall(newEmergencyCall));
+ verify(ringingCall).reject(anyBoolean(), any(), any());
+ }
+
/**
* Verifies that changes to a {@link PhoneAccount}'s
* {@link PhoneAccount#CAPABILITY_VIDEO_CALLING} capability will be reflected on a call.
@@ -1196,6 +1251,41 @@
}
/**
+ * Verifies that adding and removing a call triggers external calls to have capabilities
+ * recalculated.
+ */
+ @SmallTest
+ @Test
+ public void testExternalCallCapabilitiesUpdated() throws InterruptedException {
+ Call externalCall = addSpyCall(SIM_2_HANDLE, null, CallState.ACTIVE,
+ Connection.CAPABILITY_CAN_PULL_CALL, Connection.PROPERTY_IS_EXTERNAL_CALL);
+ LinkedBlockingQueue<Integer> capabilitiesQueue = new LinkedBlockingQueue<>(1);
+ externalCall.addListener(new Call.ListenerBase() {
+ @Override
+ public void onConnectionCapabilitiesChanged(Call call) {
+ try {
+ capabilitiesQueue.put(call.getConnectionCapabilities());
+ } catch (InterruptedException e) {
+ fail();
+ }
+ }
+ });
+
+ Call call = createSpyCall(SIM_2_HANDLE, CallState.DIALING);
+ doReturn(true).when(call).isEmergencyCall();
+ mCallsManager.addCall(call);
+ Integer result = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertNotNull(result);
+ assertEquals(0, Connection.CAPABILITY_CAN_PULL_CALL & result);
+
+ mCallsManager.removeCall(call);
+ result = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertNotNull(result);
+ assertEquals(Connection.CAPABILITY_CAN_PULL_CALL,
+ Connection.CAPABILITY_CAN_PULL_CALL & result);
+ }
+
+ /**
* Verifies that speakers is disabled when there's no video capabilities, even if a video call
* tried to place.
* @throws Exception
@@ -1211,6 +1301,215 @@
assertFalse(outgoingCall.getStartWithSpeakerphoneOn());
}
+ /**
+ * Verify that a parent call will inherit the connect time of its children.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testParentInheritsChildConnectTime() throws Exception {
+ Call callSim1 = createCall(SIM_1_HANDLE, null, CallState.ACTIVE);
+ Call callSim2 = createCall(SIM_1_HANDLE, null, CallState.ACTIVE);
+ callSim1.setConnectTimeMillis(100);
+
+ // Pretend it is a conference made later.
+ callSim2.setConnectTimeMillis(0);
+
+ // Make the first call a child of the second (pretend conference).
+ callSim1.setChildOf(callSim2);
+
+ assertEquals(100, callSim2.getConnectTimeMillis());
+
+ // Add another later call.
+ Call callSim3 = createCall(SIM_1_HANDLE, null, CallState.ACTIVE);
+ callSim3.setConnectTimeMillis(200);
+ callSim3.setChildOf(callSim2);
+
+ // Later call shouldn't impact parent.
+ assertEquals(100, callSim2.getConnectTimeMillis());
+ }
+
+ /**
+ * Make sure that CallsManager handles a screening result that has both
+ * silence and screen-further set to true as a request to screen further.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testHandleSilenceVsBackgroundScreeningOrdering() throws Exception {
+ Call screenedCall = mock(Call.class);
+ String appName = "blah";
+ CallFilteringResult result = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(true)
+ .setShouldScreenViaAudio(true)
+ .setShouldAddToCallLog(true)
+ .setShouldShowNotification(true)
+ .setCallScreeningAppName(appName)
+ .build();
+ mCallsManager.onCallFilteringComplete(screenedCall, result);
+
+ verify(mConnectionSvrFocusMgr).requestFocus(eq(screenedCall),
+ nullable(ConnectionServiceFocusManager.RequestFocusCallback.class));
+ verify(screenedCall).setAudioProcessingRequestingApp(appName);
+ }
+
+ /**
+ * Verify the behavior of the {@link CallsManager#areFromSameSource(Call, Call)} method.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testAreFromSameSource() throws Exception {
+ Call callSim1 = createCall(SIM_1_HANDLE, null, CallState.ACTIVE);
+ Call callSim2 = createCall(SIM_2_HANDLE, null, CallState.ACTIVE);
+ Call callVoip1 = createCall(VOIP_1_HANDLE, null, CallState.ACTIVE);
+ assertTrue(CallsManager.areFromSameSource(callSim1, callSim1));
+ assertTrue(CallsManager.areFromSameSource(callSim1, callSim2));
+ assertFalse(CallsManager.areFromSameSource(callSim1, callVoip1));
+ assertFalse(CallsManager.areFromSameSource(callSim2, callVoip1));
+
+ Call callSim1ConnectionMgr1 = createCall(SIM_1_HANDLE, CONNECTION_MGR_1_HANDLE,
+ CallState.ACTIVE);
+ Call callSim2ConnectionMgr2 = createCall(SIM_2_HANDLE, CONNECTION_MGR_2_HANDLE,
+ CallState.ACTIVE);
+ assertFalse(CallsManager.areFromSameSource(callSim1ConnectionMgr1, callVoip1));
+ assertFalse(CallsManager.areFromSameSource(callSim2ConnectionMgr2, callVoip1));
+ // Even though the connection manager differs, the underlying telephony CS is the same
+ // so hold/swap will still work as expected.
+ assertTrue(CallsManager.areFromSameSource(callSim1ConnectionMgr1, callSim2ConnectionMgr2));
+
+ // Sometimes connection managers have been known to also have calls
+ Call callConnectionMgr = createCall(CONNECTION_MGR_2_HANDLE, CONNECTION_MGR_2_HANDLE,
+ CallState.ACTIVE);
+ assertTrue(CallsManager.areFromSameSource(callSim2ConnectionMgr2, callConnectionMgr));
+ }
+
+ /**
+ * This test verifies a race condition seen with the new outgoing call broadcast.
+ * The scenario occurs when an incoming call is handled by an app which receives the
+ * NewOutgoingCallBroadcast. That app cancels the call by modifying the new outgoing call
+ * broadcast. Meanwhile, it places that same call again, expecting that Telecom will reuse the
+ * same same. HOWEVER, if the system delays passing of the new outgoing call broadcast back to
+ * Telecom, the app will have placed a new outgoing call BEFORE telecom is aware that the call
+ * was cancelled.
+ * The consequence of this is that in CallsManager#startOutgoingCall, when we first get the
+ * call to reuse, it will come back empty. Meanwhile, by the time we get into the various
+ * completable futures, the call WILL be in the list of calls which can be reused. Since the
+ * reusable call was not found earlier on, we end up aborting the new outgoing call.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testReuseCallConcurrency() throws Exception {
+ // 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)));
+
+ // Let's add an existing call which is in connecting state; this emulates the case where
+ // we have an outgoing call which we have not yet disconnected as a result of the new
+ // outgoing call broadcast cancelling the call.
+ Call outgoingCall = addSpyCall(CallState.CONNECTING);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ // Get the handler for the main looper, which is the same one the CallsManager will use.
+ // We'll post a little something to block up the handler for now. This prevents
+ // startOutgoingCall from process it's completablefutures.
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(() -> {
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+
+ // Now while the main handler is blocked up we'll start another outgoing call.
+ CompletableFuture<Call> callFuture = mCallsManager.startOutgoingCall(
+ outgoingCall.getHandle(), outgoingCall.getTargetPhoneAccount(), new Bundle(),
+ UserHandle.CURRENT, new Intent(), "com.test.stuff");
+
+ // And we'll add the initial outgoing call to the list of pending disconnects; this
+ // emulates a scenario where the pending disconnect call came in AFTER this call began.
+ mCallsManager.addToPendingCallsToDisconnect(outgoingCall);
+
+ // And we'll unblock the handler; this will let all the startOutgoingCall futures to happen.
+ latch.countDown();
+
+ // Wait for the future to become the present.
+ callFuture.join();
+
+ // We should have gotten a call out of this; if we did not then it means the call was
+ // aborted.
+ assertNotNull(callFuture.get());
+
+ // And the original call should be disconnected now.
+ assertEquals(CallState.DISCONNECTED, outgoingCall.getState());
+ }
+
+ /**
+ * Ensures that if we have two calls hosted by the same connection manager, but with
+ * different target phone accounts, we can swap between them.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testSwapCallsWithSameConnectionMgr() throws Exception {
+ // GIVEN a CallsManager with ongoing call, and this call can not be held
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CONNECTION_MGR_1_HANDLE, CallState.ACTIVE);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
+
+ // and a held call which has the same connection manager, but a different target phone
+ // account. We have seen cases where a connection mgr adds its own calls and these can
+ // be problematic for swapping.
+ Call heldCall = addSpyCall(CONNECTION_MGR_1_HANDLE, CONNECTION_MGR_1_HANDLE,
+ CallState.ON_HOLD);
+
+ // WHEN unhold the held call
+ mCallsManager.unholdCall(heldCall);
+
+ // THEN the ongoing call is held
+ verify(ongoingCall).hold(any());
+ verifyFocusRequestAndExecuteCallback(heldCall);
+
+ // and held call is unhold now
+ verify(heldCall).unhold(any());
+ }
+
+ /**
+ * Verifies we inform the InCallService on local disconnect.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testRequestDisconnect() throws Exception {
+ CallsManager.CallsManagerListener listener = mock(CallsManager.CallsManagerListener.class);
+ mCallsManager.addListener(listener);
+
+ Call ongoingCall = addSpyCall(CallState.ACTIVE);
+ mCallsManager.addCall(ongoingCall);
+
+ mCallsManager.disconnectCall(ongoingCall);
+ // Seems odd, but ultimately the call state is still active even though it is locally
+ // disconnecting.
+ verify(listener).onCallStateChanged(eq(ongoingCall), eq(CallState.ACTIVE),
+ eq(CallState.ACTIVE));
+ }
private Call addSpyCall() {
return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
@@ -1221,7 +1520,35 @@
}
private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, int initialState) {
- Call ongoingCall = createCall(targetPhoneAccount, initialState);
+ return addSpyCall(targetPhoneAccount, null, initialState, 0 /*caps*/, 0 /*props*/);
+ }
+
+ private Call addSpyCall(PhoneAccountHandle targetPhoneAccount,
+ PhoneAccountHandle connectionMgrAcct, int initialState) {
+ return addSpyCall(targetPhoneAccount, connectionMgrAcct, initialState, 0 /*caps*/,
+ 0 /*props*/);
+ }
+
+ private Call addSpyCall(PhoneAccountHandle targetPhoneAccount,
+ PhoneAccountHandle connectionMgrAcct, int initialState,
+ int connectionCapabilities, int connectionProperties) {
+ Call ongoingCall = createCall(targetPhoneAccount, connectionMgrAcct, initialState);
+ ongoingCall.setConnectionProperties(connectionProperties);
+ ongoingCall.setConnectionCapabilities(connectionCapabilities);
+ Call callSpy = Mockito.spy(ongoingCall);
+
+ // Mocks some methods to not call the real method.
+ doNothing().when(callSpy).unhold();
+ doNothing().when(callSpy).hold();
+ doNothing().when(callSpy).answer(Matchers.anyInt());
+ doNothing().when(callSpy).setStartWithSpeakerphoneOn(Matchers.anyBoolean());
+
+ mCallsManager.addCall(callSpy);
+ return callSpy;
+ }
+
+ private Call createSpyCall(PhoneAccountHandle handle, int initialState) {
+ Call ongoingCall = createCall(handle, initialState);
Call callSpy = Mockito.spy(ongoingCall);
// Mocks some methods to not call the real method.
@@ -1231,11 +1558,15 @@
doNothing().when(callSpy).answer(Matchers.anyInt());
doNothing().when(callSpy).setStartWithSpeakerphoneOn(Matchers.anyBoolean());
- mCallsManager.addCall(callSpy);
return callSpy;
}
private Call createCall(PhoneAccountHandle targetPhoneAccount, int initialState) {
+ return createCall(targetPhoneAccount, null /* connectionManager */, initialState);
+ }
+
+ private Call createCall(PhoneAccountHandle targetPhoneAccount,
+ PhoneAccountHandle connectionManagerAccount, int initialState) {
Call ongoingCall = new Call(String.format("TC@%d", sCallId++), /* callId */
mContext,
mCallsManager,
@@ -1244,7 +1575,7 @@
mPhoneNumberUtilsAdapter,
TEST_ADDRESS,
null /* GatewayInfo */,
- null /* connectionManagerPhoneAccountHandle */,
+ connectionManagerAccount,
targetPhoneAccount,
Call.CALL_DIRECTION_INCOMING,
false /* shouldAttachToExistingConnection*/,
diff --git a/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java b/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
index 4ef4596..dbfcdb1 100644
--- a/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
@@ -17,6 +17,7 @@
package com.android.server.telecom.tests;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertNull;
@@ -104,6 +105,17 @@
}
/**
+ * Ensure that we don't keep a package around after it's been removed from the device
+ */
+ @Test
+ public void testForceExitCarMode() {
+ testEnterCarModeBasic();
+ mCarModeTracker.forceExitCarMode(CAR_MODE_APP1_PACKAGE_NAME);
+ assertFalse(mCarModeTracker.isInCarMode());
+ assertNull(mCarModeTracker.getCurrentCarModePackage());
+ }
+
+ /**
* Verifies only the first app at the default priority gets tracked.
*/
@Test
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 7effc47..a4302b6 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -39,8 +39,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
@@ -52,6 +54,7 @@
import android.os.Handler;
import android.os.IInterface;
import android.os.PersistableBundle;
+import android.os.PowerWhitelistManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.telecom.CallAudioState;
@@ -320,6 +323,12 @@
}
@Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
+ Bundle options) {
+ // Override so that this can be verified via spy.
+ }
+
+ @Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
int initialCode, String initialData, Bundle initialExtras) {
@@ -434,6 +443,7 @@
ArrayListMultimap.create();
private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>();
+ private final Map<ComponentName, ActivityInfo> mActivityInfoByComponentName = new HashMap<>();
private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>();
private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>();
@@ -476,6 +486,7 @@
private final RoleManager mRoleManager = mock(RoleManager.class);
private final TelephonyRegistryManager mTelephonyRegistryManager =
mock(TelephonyRegistryManager.class);
+ private final PermissionInfo mPermissionInfo = mock(PermissionInfo.class);
private TelecomManager mTelecomManager = mock(TelecomManager.class);
@@ -507,11 +518,37 @@
}
}).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
+ doAnswer(new Answer<List<ResolveInfo>>() {
+ @Override
+ public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
+ return doQueryIntentReceivers(
+ (Intent) invocation.getArguments()[0],
+ (Integer) invocation.getArguments()[1]);
+ }
+ }).when(mPackageManager).queryBroadcastReceivers((Intent) any(), anyInt());
+
+ doAnswer(new Answer<List<ResolveInfo>>() {
+ @Override
+ public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
+ return doQueryIntentReceivers(
+ (Intent) invocation.getArguments()[0],
+ (Integer) invocation.getArguments()[1]);
+ }
+ }).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);
+ try {
+ when(mPackageManager.getPermissionInfo(anyString(), anyInt())).thenReturn(
+ mPermissionInfo);
+ } catch (PackageManager.NameNotFoundException ex) {
+ }
+
+ when(mPermissionInfo.isAppOp()).thenReturn(true);
+
// 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
// chosen.
@@ -585,6 +622,14 @@
eq(componentName.getPackageName()))).thenReturn(PackageManager.PERMISSION_GRANTED);
}
+ public void addIntentReceiver(String action, ComponentName name) {
+ mComponentNamesByAction.put(action, name);
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = name.getPackageName();
+ activityInfo.name = name.getClassName();
+ mActivityInfoByComponentName.put(name, activityInfo);
+ }
+
public void putResource(int id, final String value) {
when(mResources.getText(eq(id))).thenReturn(value);
when(mResources.getString(eq(id))).thenReturn(value);
@@ -635,4 +680,14 @@
}
return result;
}
+
+ private List<ResolveInfo> doQueryIntentReceivers(Intent intent, int flags) {
+ List<ResolveInfo> result = new ArrayList<>();
+ for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = mActivityInfoByComponentName.get(componentName);
+ result.add(resolveInfo);
+ }
+ return result;
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index c1a3b80..26f24ef 100755
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -29,10 +29,8 @@
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
-import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.telecom.CallAudioState;
@@ -251,6 +249,7 @@
@Override
public void createConnectionComplete(String id, Session.Info info) throws RemoteException {
+ Log.i(ConnectionServiceFixture.this, "createConnectionComplete: %s", id);
mConnectionServiceDelegateAdapter.createConnectionComplete(id, null /*Session.Info*/);
}
@@ -714,22 +713,15 @@
}
private ParcelableConference parcelable(ConferenceInfo c) {
- return new ParcelableConference(
- c.phoneAccount,
- c.state,
- c.capabilities,
- c.properties,
- c.connectionIds,
- c.videoProvider,
- c.videoState,
- c.connectTimeMillis,
- c.connectElapsedTimeMillis,
- c.statusHints,
- c.extras,
- null,
- 0,
- null,
- 0);
+ return new ParcelableConference.Builder(c.phoneAccount, c.state)
+ .setConnectionCapabilities(c.capabilities)
+ .setConnectionProperties(c.properties)
+ .setConnectionIds(c.connectionIds)
+ .setVideoAttributes(c.videoProvider, c.videoState)
+ .setConnectTimeMillis(c.connectTimeMillis, c.connectElapsedTimeMillis)
+ .setStatusHints(c.statusHints)
+ .setExtras(c.extras)
+ .build();
}
private ParcelableConnection parcelable(ConnectionInfo c) {
diff --git a/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java b/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
deleted file mode 100644
index a55f9b5..0000000
--- a/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
+++ /dev/null
@@ -1,127 +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.tests;
-
-import android.net.Uri;
-import android.provider.CallLog.Calls;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import android.telecom.CallerInfo;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.callfiltering.CallFilterResultCallback;
-import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
-
-import org.junit.After;
-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 static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(JUnit4.class)
-public class DirectToVoicemailCallFilterTest extends TelecomTestCase {
- @Mock private CallerInfoLookupHelper mCallerInfoLookupHelper;
- @Mock private CallFilterResultCallback mCallback;
- @Mock private Call mCall;
-
- private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- }
-
- @Override
- @After
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- @SmallTest
- @Test
- public void testSendToVoicemail() {
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
-
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.shouldSendToVoicemail = true;
-
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
- verify(mCallback).onCallFilteringComplete(mCall, new Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL)
- .setCallScreeningAppName(null)
- .setCallScreeningComponentName(null)
- .build());
- }
-
- @SmallTest
- @Test
- public void testDontSendToVoicemail() {
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
-
- CallerInfo callerInfo = new CallerInfo();
- callerInfo.shouldSendToVoicemail = false;
-
- queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
- verify(mCallback).onCallFilteringComplete(mCall, new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build());
- }
-
- @SmallTest
- @Test
- public void testNullResponseFromLookupHelper() {
- CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart(null);
-
- queryListener.onCallerInfoQueryComplete(null, null);
- verify(mCallback).onCallFilteringComplete(mCall, new Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build());
- }
-
- private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart() {
- return verifyLookupStart(TEST_HANDLE);
- }
-
- private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart(Uri handle) {
- when(mCall.getHandle()).thenReturn(handle);
- DirectToVoicemailCallFilter filter =
- new DirectToVoicemailCallFilter(mCallerInfoLookupHelper);
- filter.startFilterLookup(mCall, mCallback);
- ArgumentCaptor<CallerInfoLookupHelper.OnQueryCompleteListener> captor =
- ArgumentCaptor.forClass(CallerInfoLookupHelper.OnQueryCompleteListener.class);
- verify(mCallerInfoLookupHelper).startLookup(eq(handle), captor.capture());
- return captor.getValue();
- }
-}
diff --git a/tests/src/com/android/server/telecom/tests/DisconnectedCallNotifierTest.java b/tests/src/com/android/server/telecom/tests/DisconnectedCallNotifierTest.java
index 22963de..2cdc23a 100644
--- a/tests/src/com/android/server/telecom/tests/DisconnectedCallNotifierTest.java
+++ b/tests/src/com/android/server/telecom/tests/DisconnectedCallNotifierTest.java
@@ -1,5 +1,8 @@
package com.android.server.telecom.tests;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -31,6 +34,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.Collections;
@@ -82,8 +86,37 @@
doReturn(Collections.EMPTY_LIST).when(mCallsManager).getCalls();
notifier.onCallRemoved(call);
+ ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
verify(mNotificationManager).notifyAsUser(anyString(), anyInt(),
+ captor.capture(), any(UserHandle.class));
+ Notification notification = captor.getValue();
+ assertNotNull(notification.contentIntent);
+ assertEquals(2, notification.actions.length);
+ }
+
+ @Test
+ @SmallTest
+ public void testNotificationShownForDisconnectedEmergencyCall() {
+ Call call = createCall(new DisconnectCause(DisconnectCause.LOCAL,
+ DisconnectCause.REASON_EMERGENCY_CALL_PLACED));
+ when(call.isEmergencyCall()).thenReturn(true);
+
+ DisconnectedCallNotifier notifier = new DisconnectedCallNotifier(mContext, mCallsManager);
+ notifier.onCallStateChanged(call, CallState.NEW, CallState.DIALING);
+ notifier.onCallStateChanged(call, CallState.DIALING, CallState.DISCONNECTED);
+ verify(mNotificationManager, never()).notifyAsUser(anyString(), anyInt(),
any(Notification.class), any(UserHandle.class));
+
+ doReturn(Collections.EMPTY_LIST).when(mCallsManager).getCalls();
+ notifier.onCallRemoved(call);
+ ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
+ verify(mNotificationManager).notifyAsUser(anyString(), anyInt(),
+ captor.capture(), any(UserHandle.class));
+ Notification notification = captor.getValue();
+ assertNull(notification.contentIntent);
+ if (notification.actions != null) {
+ assertEquals(0, notification.actions.length);
+ }
}
@Test
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 38a1798..6a6b9f3 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -23,6 +23,7 @@
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.anyLong;
import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.ArgumentMatchers.nullable;
@@ -34,11 +35,13 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.UiModeManager;
@@ -49,6 +52,7 @@
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
@@ -58,13 +62,14 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
+import android.telecom.CallAudioState;
import android.telecom.InCallService;
-import android.telecom.Log;
import android.telecom.ParcelableCall;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import com.android.internal.telecom.IInCallAdapter;
@@ -98,6 +103,7 @@
import java.util.Collections;
import java.util.LinkedList;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
@RunWith(JUnit4.class)
@@ -109,6 +115,7 @@
@Mock PackageManager mMockPackageManager;
@Mock Call mMockCall;
@Mock Resources mMockResources;
+ @Mock AppOpsManager mMockAppOpsManager;
@Mock MockContext mMockContext;
@Mock Timeouts.Adapter mTimeoutsAdapter;
@Mock DefaultDialerCache mDefaultDialerCache;
@@ -116,6 +123,7 @@
@Mock ClockProxy mClockProxy;
@Mock Analytics.CallInfoImpl mCallInfo;
@Mock NotificationManager mNotificationManager;
+ @Mock PermissionInfo mMockPermissionInfo;
private static final int CURRENT_USER_ID = 900973;
private static final String DEF_PKG = "defpkg";
@@ -133,6 +141,13 @@
private static final String CAR2_CLASS = "carcls";
private static final int CAR_UID = 4;
private static final int CAR2_UID = 5;
+ private static final String NONUI_PKG = "nonui_pkg";
+ private static final String NONUI_CLASS = "nonui_cls";
+ private static final int NONUI_UID = 6;
+ private static final String APPOP_NONUI_PKG = "appop_nonui_pkg";
+ private static final String APPOP_NONUI_CLASS = "appop_nonui_cls";
+ private static final int APPOP_NONUI_UID = 7;
+
private static final PhoneAccountHandle PA_HANDLE =
new PhoneAccountHandle(new ComponentName("pa_pkg", "pa_cls"), "pa_id");
@@ -140,6 +155,8 @@
private InCallController mInCallController;
private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {};
private EmergencyCallHelper mEmergencyCallHelper;
+ private SystemStateHelper.SystemStateListener mSystemStateListener;
+ private CarModeTracker mCarModeTracker = spy(new CarModeTracker());
@Override
@Before
@@ -148,6 +165,7 @@
MockitoAnnotations.initMocks(this);
when(mMockCall.getAnalytics()).thenReturn(new Analytics.CallInfo());
doReturn(mMockResources).when(mMockContext).getResources();
+ doReturn(mMockAppOpsManager).when(mMockContext).getSystemService(AppOpsManager.class);
doReturn(SYS_PKG).when(mMockResources).getString(
com.android.internal.R.string.config_defaultDialer);
doReturn(SYS_CLASS).when(mMockResources).getString(R.string.incall_default_class);
@@ -158,11 +176,19 @@
mEmergencyCallHelper = new EmergencyCallHelper(mMockContext, mDefaultDialerCache,
mTimeoutsAdapter);
when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
- mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
- mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
- mEmergencyCallHelper, new CarModeTracker(), mClockProxy);
when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
+ when(mMockPackageManager.getPermissionInfo(anyString(), anyInt())).thenReturn(
+ mMockPermissionInfo);
+ mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
+ mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
+ mEmergencyCallHelper, mCarModeTracker, mClockProxy);
+
+ ArgumentCaptor<SystemStateHelper.SystemStateListener> systemStateListenerArgumentCaptor
+ = ArgumentCaptor.forClass(SystemStateHelper.SystemStateListener.class);
+ verify(mMockSystemStateHelper).addListener(systemStateListenerArgumentCaptor.capture());
+ mSystemStateListener = systemStateListenerArgumentCaptor.getValue();
+
// Companion Apps don't have CONTROL_INCALL_EXPERIENCE permission.
doAnswer(invocation -> {
int uid = invocation.getArgument(0);
@@ -177,6 +203,10 @@
return new String[] { CAR_PKG };
case CAR2_UID:
return new String[] { CAR2_PKG };
+ case NONUI_UID:
+ return new String[] { NONUI_PKG };
+ case APPOP_NONUI_UID:
+ return new String[] { APPOP_NONUI_PKG };
}
return null;
}).when(mMockPackageManager).getPackagesForUid(anyInt());
@@ -189,6 +219,13 @@
when(mMockPackageManager.checkPermission(
matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
matches(CAR2_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mMockPackageManager.checkPermission(
+ matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
+ matches(NONUI_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mMockPackageManager.checkPermission(
+ matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
+ matches(APPOP_NONUI_PKG))).thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mMockCallsManager.getAudioState()).thenReturn(new CallAudioState(false, 0, 0));
}
@Override
@@ -199,6 +236,24 @@
super.tearDown();
}
+ @SmallTest
+ @Test
+ public void testCarModeAppRemoval() {
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+ when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+ when(mMockSystemStateHelper.isCarMode()).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);
+ assertFalse(mCarModeTracker.isInCarMode());
+ }
+
@MediumTest
@Test
public void testBindToService_NoServicesFound_IncomingCall() throws Exception {
@@ -291,7 +346,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -350,7 +406,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -388,6 +445,99 @@
eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle));
}
+ /**
+ * This test verifies the behavior of Telecom when the system dialer crashes on binding and must
+ * be restarted. Specifically, it ensures when the system dialer crashes we revoke the runtime
+ * location permission, and when it restarts we re-grant the permission.
+ * @throws Exception
+ */
+ @MediumTest
+ @Test
+ public void testBindToService_SystemDialer_Crash() throws Exception {
+ Bundle callExtras = new Bundle();
+ callExtras.putBoolean("whatever", true);
+
+ when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockCallsManager.isInEmergencyCall()).thenReturn(true);
+ when(mMockCall.isEmergencyCall()).thenReturn(true);
+ when(mMockCall.isIncoming()).thenReturn(false);
+ when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
+ when(mMockCall.getIntentExtras()).thenReturn(callExtras);
+ when(mMockCall.isExternalCall()).thenReturn(false);
+ when(mDefaultDialerCache.getDefaultDialerApplication(CURRENT_USER_ID))
+ .thenReturn(DEF_PKG);
+ ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
+ ArgumentCaptor.forClass(ServiceConnection.class);
+ when(mMockContext.bindServiceAsUser(any(Intent.class), serviceConnectionCaptor.capture(),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT))).thenReturn(true);
+ when(mTimeoutsAdapter.getEmergencyCallbackWindowMillis(any(ContentResolver.class)))
+ .thenReturn(300_000L);
+
+ setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+ setupMockPackageManagerLocationPermission(SYS_PKG, false /* granted */);
+
+ mInCallController.bindToServices(mMockCall);
+
+ // Query for the different InCallServices
+ ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
+ queryIntentCaptor.capture(),
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
+
+ // Verify call for default dialer InCallService
+ assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
+ // Verify call for car-mode InCallService
+ assertEquals(null, queryIntentCaptor.getAllValues().get(1).getPackage());
+ // Verify call for non-UI InCallServices
+ assertEquals(null, queryIntentCaptor.getAllValues().get(2).getPackage());
+
+ ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockContext, times(1)).bindServiceAsUser(
+ bindIntentCaptor.capture(),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
+
+ Intent bindIntent = bindIntentCaptor.getValue();
+ assertEquals(InCallService.SERVICE_INTERFACE, bindIntent.getAction());
+ assertEquals(SYS_PKG, bindIntent.getComponent().getPackageName());
+ assertEquals(SYS_CLASS, bindIntent.getComponent().getClassName());
+ assertEquals(PA_HANDLE, bindIntent.getExtras().getParcelable(
+ TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE));
+ assertEquals(callExtras, bindIntent.getExtras().getParcelable(
+ TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS));
+
+ verify(mMockPackageManager).grantRuntimePermission(eq(SYS_PKG),
+ eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle));
+
+ // Emulate a crash in the system dialer; we'll use the captured service connection to signal
+ // to InCallController that the dialer died.
+ ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
+ serviceConnection.onServiceDisconnected(bindIntent.getComponent());
+
+ // We expect that the permission is revoked at this point.
+ verify(mMockPackageManager).revokeRuntimePermission(eq(SYS_PKG),
+ eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle));
+
+ // Now, we expect to auto-rebind to the system dialer (verify 2 times since this is the
+ // second binding).
+ 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 we were re-granted the runtime permission.
+ verify(mMockPackageManager, times(2)).grantRuntimePermission(eq(SYS_PKG),
+ eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle));
+ }
+
@MediumTest
@Test
public void testBindToService_DefaultDialer_FallBackToSystem() throws Exception {
@@ -418,7 +568,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -489,6 +640,7 @@
any(Intent.class), any(ServiceConnection.class), anyInt(), any(UserHandle.class)))
.thenReturn(true);
when(mMockContext.getApplicationInfo()).thenReturn(applicationInfo);
+ when(mDefaultDialerCache.getDefaultDialerApplication(CURRENT_USER_ID)).thenReturn(DEF_PKG);
setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
mInCallController.bindToServices(mMockCall);
@@ -515,7 +667,7 @@
verify(mNotificationManager).notify(eq(NOTIFICATION_TAG),
eq(IN_CALL_SERVICE_NOTIFICATION_ID), any(Notification.class));
- verify(mCallInfo).addInCallService(eq(sysDialerComponentName.flattenToShortString()),
+ verify(mCallInfo).addInCallService(eq(defDialerComponentName.flattenToShortString()),
anyInt(), anyLong(), eq(true));
ArgumentCaptor<Intent> bindIntentCaptor2 = ArgumentCaptor.forClass(Intent.class);
@@ -525,6 +677,7 @@
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
eq(UserHandle.CURRENT));
+ assertEquals(sysDialerComponentName, bindIntentCaptor2.getValue().getComponent());
}
/**
@@ -542,7 +695,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -680,6 +834,49 @@
verifyBinding(bindIntentCaptor, 0, DEF_PKG, DEF_CLASS);
}
+ /**
+ * Ensures that the {@link InCallController} will bind to an {@link InCallService} which
+ * supports third party app
+ */
+ @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*/);
+
+ // 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);
+
+ // 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));
+
+ // Verify bind
+ assertEquals(2, bindIntentCaptor.getAllValues().size());
+
+ // 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);
+ }
+
+
@MediumTest
@Test
public void testSanitizeContactName() throws Exception {
@@ -792,13 +989,15 @@
nullable(ContentResolver.class))).thenReturn(500L);
when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
- setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+ setupMockPackageManager(true /* default */, true /* nonui */, false /* appop_nonui */ ,
+ true /* system */, false /* external calls */,
+ false /* self mgd in default*/, false /* self mgd in car*/);
mInCallController.bindToServices(mMockCall);
ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
ArgumentCaptor.forClass(ServiceConnection.class);
- verify(mMockContext, times(1)).bindServiceAsUser(
+ verify(mMockContext, times(2)).bindServiceAsUser(
bindIntentCaptor.capture(),
serviceConnectionCaptor.capture(),
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
@@ -811,20 +1010,146 @@
// Start the connection, make sure we don't unbind, and make sure that we don't send
// anything to the in-call service yet.
- ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
+ List<ServiceConnection> serviceConnections = serviceConnectionCaptor.getAllValues();
+ List<Intent> intents = bindIntentCaptor.getAllValues();
+
+ // Find the non-ui service and have it connect first.
+ int nonUiIdx = findFirstIndexMatching(intents,
+ i -> NONUI_PKG.equals(i.getComponent().getPackageName()));
+ if (nonUiIdx < 0) {
+ fail("Did not bind to non-ui incall");
+ }
+
+ {
+ ComponentName nonUiComponentName = new ComponentName(NONUI_PKG, NONUI_CLASS);
+ IBinder mockBinder = mock(IBinder.class);
+ IInCallService mockInCallService = mock(IInCallService.class);
+ when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
+ serviceConnections.get(nonUiIdx).onServiceConnected(nonUiComponentName, mockBinder);
+
+ // Make sure the non-ui binding didn't trigger the future.
+ assertFalse(bindTimeout.isDone());
+ }
+
+ int defDialerIdx = findFirstIndexMatching(intents,
+ i -> DEF_PKG.equals(i.getComponent().getPackageName()));
+ if (defDialerIdx < 0) {
+ fail("Did not bind to default dialer incall");
+ }
+
ComponentName defDialerComponentName = new ComponentName(DEF_PKG, DEF_CLASS);
IBinder mockBinder = mock(IBinder.class);
IInCallService mockInCallService = mock(IInCallService.class);
when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
- serviceConnection.onServiceConnected(defDialerComponentName, mockBinder);
+ serviceConnections.get(defDialerIdx).onServiceConnected(defDialerComponentName, mockBinder);
verify(mockInCallService).setInCallAdapter(nullable(IInCallAdapter.class));
// Make sure that the future completed without timing out.
assertTrue(bindTimeout.getNow(false));
}
+ /**
+ * Verify that if we go from a dialer which doesn't support self managed calls to a car mode
+ * dialer that does support them, we will bind.
+ */
+ @MediumTest
+ @Test
+ public void testBindToService_SelfManagedCarModeUI() throws Exception {
+ setupMocks(true /* isExternalCall */, true /* isSelfManaged*/);
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */,
+ false /* selfManagedInDefaultDialer */, true /* selfManagedInCarModeDialer */);
+
+ // Bind; we should not bind to anything right now; the dialer does not support self
+ // managed calls.
+ mInCallController.bindToServices(mMockCall);
+
+ // Bind InCallServices; make sure no binding took place. InCallController handles not
+ // binding initially, but the rebind (see next test case) will always happen.
+ verify(mMockContext, never()).bindServiceAsUser(
+ any(Intent.class),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
+
+ // Now switch to car mode.
+ // Enable car mode and enter car mode at default priority.
+ when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+ mInCallController.handleCarModeChange(UiModeManager.DEFAULT_PRIORITY, CAR_PKG, true);
+
+ ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mMockContext, times(1)).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 car mode ui
+ assertEquals(1, bindIntentCaptor.getAllValues().size());
+ verifyBinding(bindIntentCaptor, 0, CAR_PKG, CAR_CLASS);
+ }
+
+ /**
+ * Verify that if we go from a dialer which doesn't support self managed calls to a car mode
+ * dialer that does not support them, the calls are not sent to the call mode UI.
+ */
+ @MediumTest
+ @Test
+ public void testBindToService_SelfManagedNoCarModeUI() throws Exception {
+ setupMocks(true /* isExternalCall */, true /* isSelfManaged*/);
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */,
+ false /* selfManagedInDefaultDialer */, false /* selfManagedInCarModeDialer */);
+
+ // Bind; we should not bind to anything right now; the dialer does not support self
+ // managed calls.
+ mInCallController.bindToServices(mMockCall);
+
+ // Bind InCallServices; make sure no binding took place.
+ verify(mMockContext, never()).bindServiceAsUser(
+ any(Intent.class),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
+
+ // Now switch to car mode.
+ // Enable car mode and enter car mode at default priority.
+ when(mMockSystemStateHelper.isCarMode()).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
+ // for it. Its not perfect, but it reflects the fact that the InCallController isn't
+ // sophisticated enough to realize until its already bound whether there are in fact calls
+ // which will be sent to it.
+ ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
+ ArgumentCaptor.forClass(ServiceConnection.class);
+ verify(mMockContext, times(1)).bindServiceAsUser(
+ any(Intent.class),
+ serviceConnectionCaptor.capture(),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
+
+ ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
+ ComponentName defDialerComponentName = new ComponentName(DEF_PKG, DEF_CLASS);
+ IBinder mockBinder = mock(IBinder.class);
+ IInCallService mockInCallService = mock(IInCallService.class);
+ when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
+
+ // Emulate successful connection.
+ serviceConnection.onServiceConnected(defDialerComponentName, mockBinder);
+ verify(mockInCallService).setInCallAdapter(any(IInCallAdapter.class));
+
+ // We should not have gotten informed about any calls
+ verify(mockInCallService, never()).addCall(any(ParcelableCall.class));
+ }
+
private void setupMocks(boolean isExternalCall) {
+ setupMocks(isExternalCall, false /* isSelfManagedCall */);
+ }
+
+ private void setupMocks(boolean isExternalCall, boolean isSelfManagedCall) {
when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockCallsManager.isInEmergencyCall()).thenReturn(false);
@@ -834,9 +1159,11 @@
when(mMockContext.bindServiceAsUser(any(Intent.class), any(ServiceConnection.class),
anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
when(mMockCall.isExternalCall()).thenReturn(isExternalCall);
+ when(mMockCall.isSelfManaged()).thenReturn(isSelfManagedCall);
}
- private ResolveInfo getDefResolveInfo(final boolean includeExternalCalls) {
+ private ResolveInfo getDefResolveInfo(final boolean includeExternalCalls,
+ final boolean includeSelfManagedCalls) {
return new ResolveInfo() {{
serviceInfo = new ServiceInfo();
serviceInfo.packageName = DEF_PKG;
@@ -844,6 +1171,7 @@
serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.applicationInfo.uid = DEF_UID;
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+ serviceInfo.enabled = true;
serviceInfo.metaData = new Bundle();
serviceInfo.metaData.putBoolean(
TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
@@ -851,11 +1179,15 @@
serviceInfo.metaData.putBoolean(
TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true);
}
+ if (includeSelfManagedCalls) {
+ serviceInfo.metaData.putBoolean(
+ TelecomManager.METADATA_INCLUDE_SELF_MANAGED_CALLS, true);
+ }
}};
}
private ResolveInfo getCarModeResolveinfo(final String packageName, final String className,
- final boolean includeExternalCalls) {
+ final boolean includeExternalCalls, final boolean includeSelfManagedCalls) {
return new ResolveInfo() {{
serviceInfo = new ServiceInfo();
serviceInfo.packageName = packageName;
@@ -867,6 +1199,7 @@
serviceInfo.applicationInfo.uid = CAR2_UID;
}
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+ serviceInfo.enabled = true;
serviceInfo.metaData = new Bundle();
serviceInfo.metaData.putBoolean(
TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI, true);
@@ -874,6 +1207,10 @@
serviceInfo.metaData.putBoolean(
TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true);
}
+ if (includeSelfManagedCalls) {
+ serviceInfo.metaData.putBoolean(
+ TelecomManager.METADATA_INCLUDE_SELF_MANAGED_CALLS, true);
+ }
}};
}
@@ -884,6 +1221,7 @@
serviceInfo.name = SYS_CLASS;
serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.applicationInfo.uid = SYS_UID;
+ serviceInfo.enabled = true;
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
}};
}
@@ -895,13 +1233,55 @@
serviceInfo.name = COMPANION_CLASS;
serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.applicationInfo.uid = COMPANION_UID;
+ serviceInfo.enabled = true;
+ serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+ }};
+ }
+
+ private ResolveInfo getNonUiResolveinfo() {
+ return new ResolveInfo() {{
+ serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = NONUI_PKG;
+ serviceInfo.name = NONUI_CLASS;
+ serviceInfo.applicationInfo = new ApplicationInfo();
+ serviceInfo.applicationInfo.uid = NONUI_UID;
+ serviceInfo.enabled = true;
+ serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+ }};
+ }
+
+ private ResolveInfo getAppOpNonUiResolveinfo() {
+ return new ResolveInfo() {{
+ serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = APPOP_NONUI_PKG;
+ serviceInfo.name = APPOP_NONUI_CLASS;
+ serviceInfo.applicationInfo = new ApplicationInfo();
+ serviceInfo.applicationInfo.uid = APPOP_NONUI_UID;
+ serviceInfo.enabled = true;
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
}};
}
private void setupMockPackageManager(final boolean useDefaultDialer,
final boolean useSystemDialer, final boolean includeExternalCalls) {
+ setupMockPackageManager(useDefaultDialer, false, false, useSystemDialer, includeExternalCalls,
+ false /* self mgd */, false /* self mgd */);
+ }
+ private void setupMockPackageManager(final boolean useDefaultDialer,
+ final boolean useSystemDialer, final boolean includeExternalCalls,
+ final boolean includeSelfManagedCallsInDefaultDialer,
+ final boolean includeSelfManagedCallsInCarModeDialer) {
+ setupMockPackageManager(useDefaultDialer, false /* nonui */, false /* appop_nonui */,
+ useSystemDialer, includeExternalCalls, includeSelfManagedCallsInDefaultDialer,
+ includeSelfManagedCallsInCarModeDialer);
+ }
+
+ private void setupMockPackageManager(final boolean useDefaultDialer,
+ final boolean useNonUiInCalls, final boolean useAppOpNonUiInCalls,
+ final boolean useSystemDialer, final boolean includeExternalCalls,
+ final boolean includeSelfManagedCallsInDefaultDialer,
+ final boolean includeSelfManagedCallsInCarModeDialer) {
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
@@ -915,7 +1295,8 @@
LinkedList<ResolveInfo> resolveInfo = new LinkedList<ResolveInfo>();
if (!TextUtils.isEmpty(packageName)) {
if (packageName.equals(DEF_PKG) && useDefaultDialer) {
- resolveInfo.add(getDefResolveInfo(includeExternalCalls));
+ resolveInfo.add(getDefResolveInfo(includeExternalCalls,
+ includeSelfManagedCallsInDefaultDialer));
}
if (packageName.equals(SYS_PKG) && useSystemDialer) {
@@ -928,18 +1309,28 @@
if (packageName.equals(CAR_PKG)) {
resolveInfo.add(getCarModeResolveinfo(CAR_PKG, CAR_CLASS,
- includeExternalCalls));
+ includeExternalCalls, includeSelfManagedCallsInCarModeDialer));
}
if (packageName.equals(CAR2_PKG)) {
resolveInfo.add(getCarModeResolveinfo(CAR2_PKG, CAR2_CLASS,
- includeExternalCalls));
+ includeExternalCalls, includeSelfManagedCallsInCarModeDialer));
+ }
+ } else {
+ // InCallController uses a blank package name when querying for non-ui incalls
+ if (useNonUiInCalls) {
+ resolveInfo.add(getNonUiResolveinfo());
+ }
+ // InCallController uses a blank package name when querying for App Op non-ui incalls
+ if (useAppOpNonUiInCalls) {
+ resolveInfo.add(getAppOpNonUiResolveinfo());
}
}
+
return resolveInfo;
}
}).when(mMockPackageManager).queryIntentServicesAsUser(
- any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ any(Intent.class), anyInt(), eq(CURRENT_USER_ID));
}
private void setupMockPackageManagerLocationPermission(final String pkg,
diff --git a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
index fa59059..db44dcd 100644
--- a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
@@ -16,6 +16,10 @@
package com.android.server.telecom.tests;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -43,6 +47,7 @@
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.Constants;
import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
import com.android.server.telecom.MissedCallNotifier;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.TelecomBroadcastIntentProcessor;
@@ -67,6 +72,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
@@ -143,6 +150,9 @@
private static final UserHandle SECONARY_USER = UserHandle.of(12);
private static final int NO_CAPABILITY = 0;
private static final int TEST_TIMEOUT = 1000;
+ private static final long TEST_POWER_EXEMPT_TIME_MS = 1000;
+ private static final ComponentName COMPONENT_NAME = new ComponentName(
+ "com.anything", "com.whatever");
@Mock
private NotificationManager mNotificationManager;
@@ -155,6 +165,7 @@
@Mock TelecomSystem mTelecomSystem;
@Mock private DefaultDialerCache mDefaultDialerCache;
+ @Mock private DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
@Override
@Before
@@ -246,7 +257,8 @@
makeNotificationBuilderFactory(builders);
MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
- mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+ mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+ mDeviceIdleControllerAdapter);
missedCallNotifier.showMissedCallNotification(fakeCall);
missedCallNotifier.showMissedCallNotification(fakeCall);
@@ -388,9 +400,9 @@
TelecomBroadcastReceiver.class);
assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
- callBackIntent, PendingIntent.FLAG_NO_CREATE));
+ callBackIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
- smsIntent, PendingIntent.FLAG_NO_CREATE));
+ smsIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
}
@SmallTest
@@ -401,7 +413,8 @@
makeNotificationBuilderFactory(builder1);
MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
- mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+ mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+ mDeviceIdleControllerAdapter);
PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
MissedCallNotifier.CallInfo fakeCall =
@@ -424,9 +437,9 @@
TelecomBroadcastReceiver.class);
assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
- callBackIntent, PendingIntent.FLAG_NO_CREATE));
+ callBackIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
assertNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
- smsIntent, PendingIntent.FLAG_NO_CREATE));
+ smsIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
}
@SmallTest
@@ -445,7 +458,7 @@
CallLog.Calls.PRESENTATION_ALLOWED, CALL_TIMESTAMP)
.build();
- when(cp.query(anyString(), eq(queryUri), nullable(String[].class),
+ when(cp.query(anyString(), nullable(String.class), eq(queryUri), nullable(String[].class),
nullable(Bundle.class), nullable(ICancellationSignal.class)))
.thenReturn(mockMissedCallsCursor);
@@ -461,7 +474,8 @@
makeNotificationBuilderFactory(builder1);
MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
- mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+ mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+ mDeviceIdleControllerAdapter);
// AsyncQueryHandler used in reloadFromDatabase interacts poorly with the below
// timeout-verify, so run this in a new handler to mitigate that.
@@ -514,7 +528,7 @@
PRIMARY_USER.getIdentifier());
IContentProvider cp = getContentProviderForUser(PRIMARY_USER.getIdentifier());
- when(cp.query(anyString(), eq(queryUri), nullable(String[].class),
+ when(cp.query(anyString(), nullable(String.class), eq(queryUri), nullable(String[].class),
nullable(Bundle.class), nullable(ICancellationSignal.class)))
.thenReturn(mockMissedCallsCursor);
@@ -530,7 +544,8 @@
makeNotificationBuilderFactory(builder1);
MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
- mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+ mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+ mDeviceIdleControllerAdapter);
// AsyncQueryHandler used in reloadFromDatabase interacts poorly with the below
// timeout-verify, so run this in a new handler to mitigate that.
@@ -560,6 +575,49 @@
nullable(Notification.class), eq(PRIMARY_USER));
}
+ @SmallTest
+ @Test
+ public void testDialerHandleMissedCall() {
+ // Configure Notifier to send missed call intent and let dialer handle
+ enableDialerHandlesMissedCall();
+
+ Notification.Builder builder1 = makeNotificationBuilder("builder1");
+ MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
+ makeNotificationBuilderFactory(builder1);
+
+ MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
+ mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+ mDeviceIdleControllerAdapter);
+ PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
+
+ MissedCallNotifier.CallInfo fakeCall =
+ makeFakeCallInfo(SIP_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP,
+ phoneAccount.getAccountHandle());
+ missedCallNotifier.showMissedCallNotification(fakeCall);
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ ArgumentCaptor<Bundle> bundleCaptor =
+ ArgumentCaptor.forClass(Bundle.class);
+ verify(mDeviceIdleControllerAdapter).exemptAppTemporarilyForEvent(
+ eq(COMPONENT_NAME.getPackageName()), anyLong(), anyInt(), any());
+ verify(mContext).sendBroadcastAsUser(
+ intentCaptor.capture(),
+ any(),
+ eq(android.Manifest.permission.READ_PHONE_STATE), bundleCaptor.capture());
+ assertNotNull("Not expecting null intent", intentCaptor.getValue());
+ assertEquals("Incorrect intent received",
+ TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION,
+ intentCaptor.getValue().getAction());
+ 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);
+
+ // A notification should never be posted by Telecom
+ verify(mNotificationManager, never()).notifyAsUser(nullable(String.class), anyInt(),
+ nullable(Notification.class), eq(PRIMARY_USER));
+ }
+
private Notification.Builder makeNotificationBuilder(String label) {
Notification.Builder builder = spy(new Notification.Builder(mContext));
Notification notification = mock(Notification.class);
@@ -592,14 +650,14 @@
private MissedCallNotifier makeMissedCallNotifier(
NotificationBuilderFactory fakeBuilderFactory, UserHandle currentUser) {
MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
- mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+ mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+ mDeviceIdleControllerAdapter);
missedCallNotifier.setCurrentUserHandle(currentUser);
return missedCallNotifier;
}
private PhoneAccount makePhoneAccount(UserHandle userHandle, int capability) {
- ComponentName componentName = new ComponentName("com.anything", "com.whatever");
- PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, "id",
+ PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(COMPONENT_NAME, "id",
userHandle);
PhoneAccount.Builder builder = new PhoneAccount.Builder(phoneAccountHandle, "test");
builder.setCapabilities(capability);
@@ -609,6 +667,13 @@
return phoneAccount;
}
+ private void enableDialerHandlesMissedCall() {
+ doReturn(COMPONENT_NAME.getPackageName()).when(mDefaultDialerCache).
+ getDefaultDialerApplication(anyInt());
+ mComponentContextFixture.addIntentReceiver(
+ TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION, COMPONENT_NAME);
+ }
+
private IContentProvider getContentProviderForUser(int userId) {
return mContext.getContentResolver().acquireProvider(userId + "@call_log");
}
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
new file mode 100644
index 0000000..d2c832a
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.tests;
+
+import static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CallLog;
+import android.telecom.DisconnectCause;
+import android.telecom.TelecomManager;
+
+import com.android.server.telecom.Analytics;
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallIntentProcessor;
+import com.android.server.telecom.CallState;
+import com.android.server.telecom.CallsManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.Map;
+
+public class MissedInformationTest extends TelecomSystemTest {
+ private static final int TEST_TIMEOUT_MILLIS = 1000;
+ private static final String TEST_NUMBER = "650-555-1212";
+ private static final String TEST_NUMBER_1 = "7";
+ private static final String PACKAGE_NAME = "com.android.server.telecom.tests";
+ @Mock ContentResolver mContentResolver;
+ @Mock IContentProvider mContentProvider;
+ @Mock Call mEmergencyCall;
+ @Mock Analytics.CallInfo mCallInfo;
+ private CallsManager mCallsManager;
+ private CallIntentProcessor.AdapterImpl mAdapter;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mCallsManager = mTelecomSystem.getCallsManager();
+ mAdapter = new CallIntentProcessor.AdapterImpl(mCallsManager.getDefaultDialerCache());
+ when(mContentResolver.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mContentResolver.acquireProvider(any(String.class))).thenReturn(mContentProvider);
+ when(mContentProvider.call(any(String.class), any(String.class),
+ any(String.class), any(Bundle.class))).thenReturn(new Bundle());
+ doReturn(mContentResolver).when(mSpyContext).getContentResolver();
+ }
+
+ @Override
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testNotMissedCall() throws Exception {
+ IdPair testCall = startAndMakeActiveIncomingCall(
+ TEST_NUMBER,
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+
+ mConnectionServiceFixtureA.
+ sendSetDisconnected(testCall.mConnectionId, DisconnectCause.LOCAL);
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
+ assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics.missedReason);
+ assertEquals(MISSED_REASON_NOT_MISSED, (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ @Test
+ public void testEmergencyCallPlacing() throws Exception {
+ Analytics.dumpToParcelableAnalytics();
+ setUpEmergencyCall();
+ mCallsManager.addCall(mEmergencyCall);
+ assertTrue(mCallsManager.isInEmergencyCall());
+
+ Intent intent = new Intent();
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ mPhoneAccountA0.getAccountHandle());
+ mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ for (Analytics.CallInfoImpl ci : analyticsMap.values()) {
+ assertEquals(AUTO_MISSED_EMERGENCY_CALL, ci.missedReason);
+ }
+ assertEquals(AUTO_MISSED_EMERGENCY_CALL,
+ (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ @Test
+ public void testMaximumDialingCalls() throws Exception {
+ Analytics.dumpToParcelableAnalytics();
+ IdPair testDialingCall = startAndMakeDialingOutgoingCall(
+ TEST_NUMBER,
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+
+ Intent intent = new Intent();
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ mPhoneAccountA0.getAccountHandle());
+ mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ for (String callId : analyticsMap.keySet()) {
+ if (callId.equals(testDialingCall.mCallId)) {
+ continue;
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_DIALING, analyticsMap.get(callId).missedReason);
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_DIALING,
+ (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ @Test
+ public void testMaximumRingingCalls() throws Exception {
+ Analytics.dumpToParcelableAnalytics();
+ IdPair testRingingCall = startAndMakeRingingIncomingCall(
+ TEST_NUMBER,
+ mPhoneAccountA0.getAccountHandle(),
+ mConnectionServiceFixtureA);
+
+ Intent intent = new Intent();
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ mPhoneAccountA0.getAccountHandle());
+ mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+ ContentValues values = verifyInsertionWithCapture();
+
+ Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+ for (String callId : analyticsMap.keySet()) {
+ if (callId.equals(testRingingCall.mCallId)) {
+ continue;
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_RINGING, analyticsMap.get(callId).missedReason);
+ }
+ assertEquals(AUTO_MISSED_MAXIMUM_RINGING,
+ (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+ }
+
+ private ContentValues verifyInsertionWithCapture() {
+ ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
+ verify(mContentResolver, timeout(TEST_TIMEOUT_MILLIS))
+ .insert(any(Uri.class), captor.capture());
+ return captor.getValue();
+ }
+
+ private void setUpEmergencyCall() {
+ when(mEmergencyCall.isEmergencyCall()).thenReturn(true);
+ when(mEmergencyCall.getIntentExtras()).thenReturn(new Bundle());
+ when(mEmergencyCall.getAnalytics()).thenReturn(mCallInfo);
+ when(mEmergencyCall.getState()).thenReturn(CallState.ACTIVE);
+ when(mEmergencyCall.getContext()).thenReturn(mSpyContext);
+ when(mEmergencyCall.getHandle()).thenReturn(Uri.parse("tel:" + TEST_NUMBER));
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/NewCallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/NewCallScreeningServiceFilterTest.java
deleted file mode 100644
index 3c6552d..0000000
--- a/tests/src/com/android/server/telecom/tests/NewCallScreeningServiceFilterTest.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * 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.tests;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-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.content.pm.ServiceInfo;
-import android.os.IBinder;
-import android.os.UserHandle;
-import android.provider.CallLog;
-import android.telecom.CallScreeningService;
-import android.telecom.ParcelableCall;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.internal.telecom.ICallScreeningAdapter;
-import com.android.internal.telecom.ICallScreeningService;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.CallScreeningServiceHelper;
-import com.android.server.telecom.CallsManager;
-import com.android.server.telecom.ParcelableCallUtils;
-import com.android.server.telecom.PhoneAccountRegistrar;
-import com.android.server.telecom.callfiltering.CallFilteringResult;
-import com.android.server.telecom.callfiltering.NewCallScreeningServiceFilter;
-
-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 java.util.Collections;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(JUnit4.class)
-public class NewCallScreeningServiceFilterTest extends TelecomTestCase {
- //TODO: Change the name of this class to CallScreeningServiceFilterTest
- static @Mock Call mCall;
- @Mock Context mContext;
- @Mock PackageManager mPackageManager;
- @Mock CallsManager mCallsManager;
- @Mock CallScreeningServiceHelper.AppLabelProxy mAppLabelProxy;
- @Mock ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
- @Mock PhoneAccountRegistrar mPhoneAccountRegistrar;
- @Mock ICallScreeningService mCallScreeningService;
- @Mock IBinder mBinder;
-
- private static final String CALL_ID = "u89prgt9ps78y5";
- private static final String PKG_NAME = "com.android.services.telecom.tests";
- private static final String APP_NAME = "TeleTestApp";
- private static final String CLS_NAME = "CallScreeningService";
- private static final ComponentName COMPONENT_NAME = new ComponentName(PKG_NAME, CLS_NAME);
- private ResolveInfo mResolveInfo;
- private CallFilteringResult inputResult;
-
- private static final CallFilteringResult PASS_RESULT = new CallFilteringResult.Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
-
- mResolveInfo = new ResolveInfo() {{
- serviceInfo = new ServiceInfo();
- serviceInfo.packageName = PKG_NAME;
- serviceInfo.name = CLS_NAME;
- serviceInfo.permission = Manifest.permission.BIND_SCREENING_SERVICE;
- }};
- inputResult = new CallFilteringResult.Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
-
- when(mCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
- when(mCall.getId()).thenReturn(CALL_ID);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mAppLabelProxy.getAppLabel(PKG_NAME)).thenReturn(APP_NAME);
- when(mParcelableCallUtilsConverter.toParcelableCall(
- eq(mCall), anyBoolean(), eq(mPhoneAccountRegistrar))).thenReturn(null);
- when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
- anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
- when(mPackageManager.queryIntentServicesAsUser(nullable(Intent.class), anyInt(), anyInt()))
- .thenReturn(Collections.singletonList(mResolveInfo));
- doReturn(mCallScreeningService).when(mBinder).queryLocalInterface(anyString());
- }
-
- @SmallTest
- @Test
- public void testNoPackageName() throws Exception {
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, null,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- assertEquals(PASS_RESULT,
- filter.startFilterLookup(inputResult).toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
- }
-
- @SmallTest
- @Test
- public void testContextFailToBind() throws Exception {
- when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
- anyInt(), eq(UserHandle.CURRENT))).thenReturn(false);
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- assertEquals(PASS_RESULT,
- filter.startFilterLookup(inputResult).toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
- }
-
- @SmallTest
- @Test
- public void testNoResolveEntries() throws Exception {
- when(mPackageManager.queryIntentServicesAsUser(nullable(Intent.class), anyInt(), anyInt()))
- .thenReturn(Collections.emptyList());
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- assertEquals(PASS_RESULT,
- filter.startFilterLookup(inputResult).toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
- }
-
- @SmallTest
- @Test
- public void testBadResolveEntry() throws Exception {
- mResolveInfo.serviceInfo = null;
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- assertEquals(PASS_RESULT,
- filter.startFilterLookup(inputResult).toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
- }
-
- @SmallTest
- @Test
- public void testNoBindingCondition() {
- // Make sure there will be no binding if the package has no READ_CONTACT permission and
- // contact exist.
- when(mPackageManager.checkPermission(Manifest.permission.READ_CONTACTS, PKG_NAME))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
- anyInt(), eq(UserHandle.CURRENT))).thenThrow(new SecurityException());
- inputResult.contactExists = true;
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_USER_CHOSEN, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- filter.startFilterLookup(inputResult);
- }
-
- @SmallTest
- @Test
- public void testBindingCondition() {
- // Make sure there will be binding if the package has READ_CONTACT permission and contact
- // exist.
- inputResult.contactExists = true;
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- filter.startFilterLookup(inputResult);
- ServiceConnection connection = verifyBindingIntent();
- connection.onServiceDisconnected(COMPONENT_NAME);
- }
-
- @SmallTest
- @Test
- public void testAllowCall() throws Exception {
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
-
- ServiceConnection serviceConnection = verifyBindingIntent();
-
- serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
- ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.allowCall(CALL_ID);
- assertEquals(PASS_RESULT,
- resultFuture.toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
- serviceConnection.onServiceDisconnected(COMPONENT_NAME);
- }
-
- @SmallTest
- @Test
- public void testDisallowCall() throws Exception {
- CallFilteringResult expectedResult = new CallFilteringResult.Builder()
- .setShouldAllowCall(false)
- .setShouldReject(true)
- .setShouldSilence(false)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
- .setCallScreeningAppName(APP_NAME)
- .setCallScreeningComponentName(COMPONENT_NAME.flattenToString())
- .build();
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
-
- ServiceConnection serviceConnection = verifyBindingIntent();
-
- serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
- ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.disallowCall(CALL_ID,
- true, // shouldReject
- true, //shouldAddToCallLog
- true, // shouldShowNotification
- COMPONENT_NAME);
- assertEquals(expectedResult,
- resultFuture.toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
- serviceConnection.onServiceDisconnected(COMPONENT_NAME);
- }
-
- @SmallTest
- @Test
- public void testSilenceCall() throws Exception {
- CallFilteringResult expectedResult = new CallFilteringResult.Builder()
- .setShouldAllowCall(true)
- .setShouldReject(false)
- .setShouldSilence(true)
- .setShouldAddToCallLog(true)
- .setShouldShowNotification(true)
- .build();
- NewCallScreeningServiceFilter filter = new NewCallScreeningServiceFilter(mCall, PKG_NAME,
- NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
- mAppLabelProxy, mParcelableCallUtilsConverter);
- CompletionStage<CallFilteringResult> resultFuture = filter.startFilterLookup(inputResult);
-
- ServiceConnection serviceConnection = verifyBindingIntent();
-
- serviceConnection.onServiceConnected(COMPONENT_NAME, mBinder);
- ICallScreeningAdapter csAdapter = getCallScreeningAdapter();
- csAdapter.silenceCall(CALL_ID);
- assertEquals(expectedResult,
- resultFuture.toCompletableFuture().get(
- NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT,
- TimeUnit.MILLISECONDS));
-
- serviceConnection.onServiceDisconnected(COMPONENT_NAME);
- }
-
- private ServiceConnection verifyBindingIntent() {
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- ArgumentCaptor<ServiceConnection> serviceCaptor = ArgumentCaptor
- .forClass(ServiceConnection.class);
- verify(mContext, timeout(NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT))
- .bindServiceAsUser(intentCaptor.capture(), serviceCaptor.capture(),
- eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
- eq(UserHandle.CURRENT));
-
- Intent capturedIntent = intentCaptor.getValue();
- assertEquals(CallScreeningService.SERVICE_INTERFACE, capturedIntent.getAction());
- assertEquals(mResolveInfo.serviceInfo.packageName, capturedIntent.getPackage());
- assertEquals(new ComponentName(mResolveInfo.serviceInfo.packageName,
- mResolveInfo.serviceInfo.name), capturedIntent.getComponent());
-
- return serviceCaptor.getValue();
- }
-
- private ICallScreeningAdapter getCallScreeningAdapter() throws Exception {
- ArgumentCaptor<ICallScreeningAdapter> captor =
- ArgumentCaptor.forClass(ICallScreeningAdapter.class);
- verify(mCallScreeningService,
- timeout(NewCallScreeningServiceFilter.CALL_SCREENING_FILTER_TIMEOUT))
- .screenCall(captor.capture(), nullable(ParcelableCall.class));
- return captor.getValue();
- }
-}
diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
index a966ffc..a5b78b7 100644
--- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
+++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
@@ -229,7 +229,7 @@
mComponentContextFixture.putResource(R.string.dialer_default_class,
dialer_default_class_string);
when(mDefaultDialerCache.getSystemDialerApplication()).thenReturn(ui_package_string);
- when(mDefaultDialerCache.getSystemDialerComponent()).thenReturn(
+ when(mDefaultDialerCache.getDialtactsSystemDialerComponent()).thenReturn(
new ComponentName(ui_package_string, dialer_default_class_string));
int result = processIntent(intent, false).disconnectCause;
@@ -474,11 +474,11 @@
private NewOutgoingCallIntentBroadcaster.CallDisposition processIntent(Intent intent,
boolean isDefaultPhoneApp) {
NewOutgoingCallIntentBroadcaster b = new NewOutgoingCallIntentBroadcaster(
- mContext, mCallsManager, mCall, intent, mPhoneNumberUtilsAdapter,
+ mContext, mCallsManager, intent, mPhoneNumberUtilsAdapter,
isDefaultPhoneApp, mDefaultDialerCache);
NewOutgoingCallIntentBroadcaster.CallDisposition cd = b.evaluateCall();
if (cd.disconnectCause == DisconnectCause.NOT_DISCONNECTED) {
- b.processCall(cd);
+ b.processCall(mCall, cd);
}
return cd;
}
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index e9efacd..a56036a 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -49,6 +49,7 @@
import com.android.internal.telecom.IConnectionService;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.telecom.AppLabelProxy;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneAccountRegistrar.DefaultPhoneAccountHandle;
@@ -84,7 +85,7 @@
private PhoneAccountRegistrar mRegistrar;
@Mock private TelecomManager mTelecomManager;
@Mock private DefaultDialerCache mDefaultDialerCache;
- @Mock private PhoneAccountRegistrar.AppLabelProxy mAppLabelProxy;
+ @Mock private AppLabelProxy mAppLabelProxy;
@Override
@Before
@@ -724,16 +725,20 @@
mComponentContextFixture.addConnectionService(componentC,
Mockito.mock(IConnectionService.class));
+ Bundle account1Extras = new Bundle();
+ account1Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 1);
PhoneAccount account1 = new PhoneAccount.Builder(
makeQuickAccountHandle(componentA, "c"), "c")
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
- .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "A"))
+ .setExtras(account1Extras)
.build();
+ Bundle account2Extras = new Bundle();
+ account2Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 2);
PhoneAccount account2 = new PhoneAccount.Builder(
makeQuickAccountHandle(componentB, "b"), "b")
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
- .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "B"))
+ .setExtras(account2Extras)
.build();
PhoneAccount account3 = new PhoneAccount.Builder(
@@ -813,18 +818,23 @@
Mockito.mock(IConnectionService.class));
mComponentContextFixture.addConnectionService(componentZ,
Mockito.mock(IConnectionService.class));
+
+ Bundle account1Extras = new Bundle();
+ account1Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 2);
PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle(
makeQuickConnectionServiceComponentName(), "y"), "y")
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
- .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "2"))
+ .setExtras(account1Extras)
.build();
+ Bundle account2Extras = new Bundle();
+ account2Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 1);
PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle(
makeQuickConnectionServiceComponentName(), "z"), "z")
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
- .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "1"))
+ .setExtras(account2Extras)
.build();
PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle(
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 53ddd93..38f63d2 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -374,7 +374,6 @@
mRingerUnderTest.startCallWaiting(mockCall1);
ensureRingerIsAudible();
enableRampingRinger();
- enableRampingRingerFromDeviceConfig();
mFuture.complete(false); // not using audio coupled haptics
enableVibrationWhenRinging();
assertTrue(mRingerUnderTest.startRinging(mockCall2, false));
@@ -442,8 +441,4 @@
private void enableRampingRinger() {
when(mockSystemSettingsUtil.applyRampingRinger(any(Context.class))).thenReturn(true);
}
-
- private void enableRampingRingerFromDeviceConfig() {
- when(mockSystemSettingsUtil.enableRampingRingerFromDeviceConfig()).thenReturn(true);
- }
}
diff --git a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
index 2de3c83..893ae3d 100644
--- a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
@@ -16,6 +16,8 @@
package com.android.server.telecom.tests;
+import static junit.framework.Assert.fail;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -23,9 +25,11 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -39,6 +43,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.telecom.SystemStateHelper;
@@ -53,11 +58,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.internal.util.reflection.FieldSetter;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Unit tests for SystemStateHelper
@@ -128,16 +132,53 @@
@SmallTest
@Test
- public void testReceiverAndIntentFilter() {
- ArgumentCaptor<IntentFilter> intentFilter = ArgumentCaptor.forClass(IntentFilter.class);
- new SystemStateHelper(mContext);
- verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
+ public void testPackageRemoved() {
+ ArgumentCaptor<BroadcastReceiver> receiver =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ new SystemStateHelper(mContext).addListener(mSystemStateListener);
+ verify(mContext, atLeastOnce())
+ .registerReceiver(receiver.capture(), any(IntentFilter.class));
+ Intent packageRemovedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+ packageRemovedIntent.setData(Uri.fromParts("package", "com.android.test", null));
+ receiver.getValue().onReceive(mContext, packageRemovedIntent);
+ verify(mSystemStateListener).onPackageUninstalled("com.android.test");
+ }
- assertEquals(2, intentFilter.getValue().countActions());
- assertEquals(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED,
- intentFilter.getValue().getAction(0));
- assertEquals(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED,
- intentFilter.getValue().getAction(1));
+ @SmallTest
+ @Test
+ public void testReceiverAndIntentFilter() {
+ ArgumentCaptor<IntentFilter> intentFilterCaptor =
+ ArgumentCaptor.forClass(IntentFilter.class);
+ new SystemStateHelper(mContext);
+ verify(mContext, times(2)).registerReceiver(
+ any(BroadcastReceiver.class), intentFilterCaptor.capture());
+
+ Predicate<IntentFilter> carModeFilterTest = (intentFilter) ->
+ 2 == intentFilter.countActions()
+ && intentFilter.hasAction(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED)
+ && intentFilter.hasAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+
+ Predicate<IntentFilter> packageRemovedFilterTest = (intentFilter) ->
+ 1 == intentFilter.countActions()
+ && intentFilter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+ && intentFilter.hasDataScheme("package");
+
+ List<IntentFilter> capturedFilters = intentFilterCaptor.getAllValues();
+ assertEquals(2, capturedFilters.size());
+ for (IntentFilter filter : capturedFilters) {
+ if (carModeFilterTest.test(filter)) {
+ carModeFilterTest = (i) -> false;
+ continue;
+ }
+ if (packageRemovedFilterTest.test(filter)) {
+ packageRemovedFilterTest = (i) -> false;
+ continue;
+ }
+ String failString = String.format("Registered intent filters not correct. Got %s",
+ capturedFilters.stream().map(IntentFilter::toString)
+ .collect(Collectors.joining("\n")));
+ fail(failString);
+ }
}
@SmallTest
@@ -147,7 +188,8 @@
ArgumentCaptor.forClass(BroadcastReceiver.class);
new SystemStateHelper(mContext).addListener(mSystemStateListener);
- verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class));
+ verify(mContext, atLeastOnce())
+ .registerReceiver(receiver.capture(), any(IntentFilter.class));
when(mIntentEnter.getAction()).thenReturn(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
receiver.getValue().onReceive(mContext, mIntentEnter);
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 324bca2..0dfe29a 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.CALL_PHONE;
import static android.Manifest.permission.CALL_PRIVILEGED;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_NUMBERS;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
@@ -32,6 +33,7 @@
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -70,6 +72,7 @@
import java.util.concurrent.Executor;
import java.util.function.IntConsumer;
+import static android.Manifest.permission.READ_SMS;
import static android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static org.junit.Assert.assertEquals;
@@ -168,6 +171,8 @@
private TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter =
spy(new SettingsSecureAdapterFake());
@Mock private UserCallIntentProcessor mUserCallIntentProcessor;
+ private PackageManager mPackageManager;
+ @Mock private ApplicationInfo mApplicationInfo;
private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
@@ -230,6 +235,8 @@
.thenReturn(DEFAULT_DIALER_PACKAGE);
when(mDefaultDialerCache.isDefaultOrSystemDialer(eq(DEFAULT_DIALER_PACKAGE), anyInt()))
.thenReturn(true);
+
+ mPackageManager = mContext.getPackageManager();
}
@Override
@@ -248,13 +255,50 @@
.getOutgoingPhoneAccountForScheme(eq("sip"), any(UserHandle.class)))
.thenReturn(SIP_PA_HANDLE_17);
makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
+ PhoneAccount phoneAccount = makePhoneAccount(TEL_PA_HANDLE_CURRENT).build();
+ phoneAccount.setIsEnabled(true);
+ doReturn(phoneAccount).when(mFakePhoneAccountRegistrar).getPhoneAccount(
+ eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
+ doNothing().when(mAppOpsManager).checkPackage(anyInt(), anyString());
PhoneAccountHandle returnedHandleTel
- = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", DEFAULT_DIALER_PACKAGE);
+ = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", DEFAULT_DIALER_PACKAGE, null);
assertEquals(TEL_PA_HANDLE_16, returnedHandleTel);
PhoneAccountHandle returnedHandleSip
- = mTSIBinder.getDefaultOutgoingPhoneAccount("sip", DEFAULT_DIALER_PACKAGE);
+ = mTSIBinder.getDefaultOutgoingPhoneAccount("sip", DEFAULT_DIALER_PACKAGE, null);
+ assertEquals(SIP_PA_HANDLE_17, returnedHandleSip);
+ }
+
+ @SmallTest
+ @Test
+ public void testGetDefaultOutgoingPhoneAccountSucceedsIfCallerIsSimCallManager()
+ throws RemoteException {
+ when(mFakePhoneAccountRegistrar
+ .getOutgoingPhoneAccountForScheme(eq("tel"), any(UserHandle.class)))
+ .thenReturn(TEL_PA_HANDLE_16);
+ when(mFakePhoneAccountRegistrar
+ .getOutgoingPhoneAccountForScheme(eq("sip"), any(UserHandle.class)))
+ .thenReturn(SIP_PA_HANDLE_17);
+ makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
+ PhoneAccount phoneAccount = makePhoneAccount(TEL_PA_HANDLE_CURRENT).build();
+ phoneAccount.setIsEnabled(true);
+ doReturn(phoneAccount).when(mFakePhoneAccountRegistrar).getPhoneAccount(
+ eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
+ doReturn(TEL_PA_HANDLE_CURRENT).when(mFakePhoneAccountRegistrar)
+ .getSimCallManagerFromHandle(
+ eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
+ // doNothing will make #isCallerSimCallManager return true
+ doNothing().when(mAppOpsManager).checkPackage(anyInt(), anyString());
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(READ_PRIVILEGED_PHONE_STATE), anyString());
+
+ PhoneAccountHandle returnedHandleTel
+ = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", DEFAULT_DIALER_PACKAGE, null);
+ assertEquals(TEL_PA_HANDLE_16, returnedHandleTel);
+
+ PhoneAccountHandle returnedHandleSip
+ = mTSIBinder.getDefaultOutgoingPhoneAccount("sip", DEFAULT_DIALER_PACKAGE, null);
assertEquals(SIP_PA_HANDLE_17, returnedHandleSip);
}
@@ -269,13 +313,21 @@
.thenReturn(TEL_PA_HANDLE_16);
when(mFakePhoneAccountRegistrar.getPhoneAccountUnchecked(TEL_PA_HANDLE_16)).thenReturn(
makePhoneAccount(TEL_PA_HANDLE_16).build());
- when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_READ_PHONE_STATE), anyInt(), anyString()))
+ when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_READ_PHONE_STATE), anyInt(), anyString(),
+ nullable(String.class), nullable(String.class)))
.thenReturn(AppOpsManager.MODE_IGNORED);
+ PhoneAccount phoneAccount = makePhoneAccount(TEL_PA_HANDLE_CURRENT).build();
+ phoneAccount.setIsEnabled(true);
+ doReturn(phoneAccount).when(mFakePhoneAccountRegistrar).getPhoneAccount(
+ eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
+ doReturn(TEL_PA_HANDLE_16).when(mFakePhoneAccountRegistrar).getSimCallManagerFromHandle(
+ eq(TEL_PA_HANDLE_CURRENT), any(UserHandle.class));
+ doNothing().when(mAppOpsManager).checkPackage(anyInt(), anyString());
doThrow(new SecurityException()).when(mContext)
.enforceCallingOrSelfPermission(eq(READ_PRIVILEGED_PHONE_STATE), anyString());
PhoneAccountHandle returnedHandleTel
- = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", "");
+ = mTSIBinder.getDefaultOutgoingPhoneAccount("tel", "", null);
assertNull(returnedHandleTel);
}
@@ -338,9 +390,9 @@
makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
assertEquals(fullPHList,
- mTSIBinder.getCallCapablePhoneAccounts(true, DEFAULT_DIALER_PACKAGE));
+ mTSIBinder.getCallCapablePhoneAccounts(true, DEFAULT_DIALER_PACKAGE, null));
assertEquals(smallPHList,
- mTSIBinder.getCallCapablePhoneAccounts(false, DEFAULT_DIALER_PACKAGE));
+ mTSIBinder.getCallCapablePhoneAccounts(false, DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@@ -355,7 +407,7 @@
List<PhoneAccountHandle> result = null;
try {
- result = mTSIBinder.getCallCapablePhoneAccounts(true, "");
+ result = mTSIBinder.getCallCapablePhoneAccounts(true, "", null);
} catch (SecurityException e) {
// intended behavior
}
@@ -684,14 +736,15 @@
Uri handle = Uri.parse("tel:6505551234");
Bundle extras = createSampleExtras();
- when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString()))
+ when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
+ nullable(String.class), nullable(String.class)))
.thenReturn(AppOpsManager.MODE_ALLOWED);
doReturn(PackageManager.PERMISSION_GRANTED)
.when(mContext).checkCallingPermission(CALL_PHONE);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mContext).checkCallingPermission(CALL_PRIVILEGED);
- mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
+ mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
placeCallTestHelper(handle, extras, true);
}
@@ -701,14 +754,15 @@
Uri handle = Uri.parse("tel:6505551234");
Bundle extras = createSampleExtras();
- when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString()))
+ when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
+ nullable(String.class), nullable(String.class)))
.thenReturn(AppOpsManager.MODE_IGNORED);
doReturn(PackageManager.PERMISSION_GRANTED)
.when(mContext).checkCallingPermission(CALL_PHONE);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mContext).checkCallingPermission(CALL_PRIVILEGED);
- mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
+ mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
placeCallTestHelper(handle, extras, false);
}
@@ -718,14 +772,15 @@
Uri handle = Uri.parse("tel:6505551234");
Bundle extras = createSampleExtras();
- when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString()))
+ when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
+ nullable(String.class), nullable(String.class)))
.thenReturn(AppOpsManager.MODE_ALLOWED);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mContext).checkCallingPermission(CALL_PHONE);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mContext).checkCallingPermission(CALL_PRIVILEGED);
- mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
+ mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
placeCallTestHelper(handle, extras, false);
}
@@ -750,7 +805,7 @@
.when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
try {
- mTSIBinder.placeCall(handle, extras, "arbitrary_package_name");
+ mTSIBinder.placeCall(handle, extras, "arbitrary_package_name", null);
} catch (SecurityException e) {
// expected
}
@@ -823,7 +878,7 @@
doReturn(true).when(mFakePhoneAccountRegistrar).isVoiceMailNumber(TEL_PA_HANDLE_CURRENT,
vmNumber);
assertTrue(mTSIBinder.isVoiceMailNumber(TEL_PA_HANDLE_CURRENT,
- vmNumber, DEFAULT_DIALER_PACKAGE));
+ vmNumber, DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@@ -837,7 +892,7 @@
when(mFakePhoneAccountRegistrar.getPhoneAccount(TEL_PA_HANDLE_CURRENT,
Binder.getCallingUserHandle())).thenReturn(null);
assertFalse(mTSIBinder
- .isVoiceMailNumber(TEL_PA_HANDLE_CURRENT, vmNumber, DEFAULT_DIALER_PACKAGE));
+ .isVoiceMailNumber(TEL_PA_HANDLE_CURRENT, vmNumber, DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@@ -854,7 +909,7 @@
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
when(mockTelephonyManager.getVoiceMailNumber()).thenReturn(vmNumber);
- assertEquals(vmNumber, mTSIBinder.getVoiceMailNumber(null, DEFAULT_DIALER_PACKAGE));
+ assertEquals(vmNumber, mTSIBinder.getVoiceMailNumber(null, DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@@ -873,23 +928,147 @@
.thenReturn(subId);
assertEquals(vmNumber,
- mTSIBinder.getVoiceMailNumber(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE));
+ mTSIBinder.getVoiceMailNumber(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@Test
- public void testGetLine1Number() throws Exception {
+ public void testGetLine1NumberWithNoPermissionTargetPreR() throws Exception {
+ setupGetLine1NumberTest();
+ setTargetSdkVersion(Build.VERSION_CODES.Q);
+
+ try {
+ String line1Number = mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT,
+ DEFAULT_DIALER_PACKAGE, null);
+ fail("Should have thrown a SecurityException when invoking getLine1Number without "
+ + "permission, received "
+ + line1Number);
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberWithNoPermissionTargetR() throws Exception {
+ setupGetLine1NumberTest();
+
+ try {
+ String line1Number = mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT,
+ DEFAULT_DIALER_PACKAGE, null);
+ fail("Should have thrown a SecurityException when invoking getLine1Number without "
+ + "permission, received "
+ + line1Number);
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberWithReadPhoneStateTargetPreR() throws Exception {
+ String line1Number = setupGetLine1NumberTest();
+ setTargetSdkVersion(Build.VERSION_CODES.Q);
+ grantPermissionAndAppOp(READ_PHONE_STATE, AppOpsManager.OPSTR_READ_PHONE_STATE);
+
+ assertEquals(line1Number,
+ mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE, null));
+ }
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberWithReadPhoneStateTargetR() throws Exception {
+ setupGetLine1NumberTest();
+ grantPermissionAndAppOp(READ_PHONE_STATE, AppOpsManager.OPSTR_READ_PHONE_STATE);
+
+ try {
+ String line1Number = mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT,
+ DEFAULT_DIALER_PACKAGE, null);
+ fail("Should have thrown a SecurityException when invoking getLine1Number on target R"
+ + " with READ_PHONE_STATE permission, received "
+ + line1Number);
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberWithReadPhoneNumbersTargetR() throws Exception {
+ String line1Number = setupGetLine1NumberTest();
+ grantPermissionAndAppOp(READ_PHONE_NUMBERS, AppOpsManager.OPSTR_READ_PHONE_NUMBERS);
+
+ assertEquals(line1Number,
+ mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE, null));
+ }
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberWithReadSmsTargetR() throws Exception {
+ String line1Number = setupGetLine1NumberTest();
+ grantPermissionAndAppOp(READ_SMS, AppOpsManager.OPSTR_READ_SMS);
+
+ assertEquals(line1Number,
+ mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE, null));
+ }
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberWithWriteSmsTargetR() throws Exception {
+ String line1Number = setupGetLine1NumberTest();
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).noteOpNoThrow(
+ eq(AppOpsManager.OPSTR_WRITE_SMS), anyInt(), eq(DEFAULT_DIALER_PACKAGE), any(),
+ any());
+
+ assertEquals(line1Number,
+ mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE, null));
+ }
+
+
+ @SmallTest
+ @Test
+ public void testGetLine1NumberAsDefaultDialer() throws Exception {
+ String line1Number = setupGetLine1NumberTest();
+ doReturn(true).when(mDefaultDialerCache).isDefaultOrSystemDialer(
+ eq(DEFAULT_DIALER_PACKAGE), anyInt());
+
+ assertEquals(line1Number,
+ mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE, null));
+ }
+
+ private String setupGetLine1NumberTest() throws Exception {
int subId = 58374;
String line1Number = "9482752023479";
+
+ setTargetSdkVersion(Build.VERSION_CODES.R);
+ doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).noteOpNoThrow(anyString(),
+ anyInt(), eq(DEFAULT_DIALER_PACKAGE), any(), any());
makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_CURRENT);
when(mFakePhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(TEL_PA_HANDLE_CURRENT))
.thenReturn(subId);
TelephonyManager mockTelephonyManager =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
when(mockTelephonyManager.getLine1Number()).thenReturn(line1Number);
+ doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(anyString(),
+ anyString());
+ doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(
+ anyString());
+ doReturn(false).when(mDefaultDialerCache).isDefaultOrSystemDialer(
+ eq(DEFAULT_DIALER_PACKAGE), anyInt());
+ return line1Number;
+ }
- assertEquals(line1Number,
- mTSIBinder.getLine1Number(TEL_PA_HANDLE_CURRENT, DEFAULT_DIALER_PACKAGE));
+ private void grantPermissionAndAppOp(String permission, String appop) {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(
+ eq(permission));
+ doNothing().when(mContext).enforceCallingOrSelfPermission(eq(permission), anyString());
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).noteOp(eq(appop), anyInt(),
+ eq(DEFAULT_DIALER_PACKAGE), any(), any());
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).noteOpNoThrow(eq(appop), anyInt(),
+ eq(DEFAULT_DIALER_PACKAGE), any(), any());
+ }
+
+ private void setTargetSdkVersion(int targetSdkVersion) throws Exception {
+ mApplicationInfo.targetSdkVersion = targetSdkVersion;
+ doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfoAsUser(
+ eq(DEFAULT_DIALER_PACKAGE), anyInt(), any());
}
@SmallTest
@@ -899,7 +1078,17 @@
when(call.getState()).thenReturn(CallState.RINGING);
when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
- verify(call).reject(eq(false), isNull(), eq(TEST_PACKAGE));
+ verify(mFakeCallsManager).rejectCall(eq(call), eq(false), isNull());
+ }
+
+ @SmallTest
+ @Test
+ public void testEndCallWithSimulatedRingingForegroundCall() throws Exception {
+ Call call = mock(Call.class);
+ when(call.getState()).thenReturn(CallState.SIMULATED_RINGING);
+ when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
+ assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+ verify(mFakeCallsManager).rejectCall(eq(call), eq(false), isNull());
}
@SmallTest
@@ -909,7 +1098,7 @@
when(call.getState()).thenReturn(CallState.ACTIVE);
when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
- verify(call).disconnect(eq(0L), eq(TEST_PACKAGE));
+ verify(mFakeCallsManager).disconnectCall(eq(call));
}
@SmallTest
@@ -920,7 +1109,7 @@
when(mFakeCallsManager.getFirstCallWithState(any()))
.thenReturn(call);
assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
- verify(call).disconnect(eq(0L), eq(TEST_PACKAGE));
+ verify(mFakeCallsManager).disconnectCall(eq(call));
}
@SmallTest
@@ -933,41 +1122,41 @@
@Test
public void testAcceptRingingCall() throws Exception {
Call call = mock(Call.class);
- when(mFakeCallsManager.getFirstCallWithState(anyInt())).thenReturn(call);
+ when(mFakeCallsManager.getFirstCallWithState(anyInt(), anyInt())).thenReturn(call);
// Not intended to be a real video state. Here to ensure that the call will be answered
// with whatever video state it's currently in.
int fakeVideoState = 29578215;
when(call.getVideoState()).thenReturn(fakeVideoState);
mTSIBinder.acceptRingingCall("");
- verify(call).answer(eq(fakeVideoState));
+ verify(mFakeCallsManager).answerCall(eq(call), eq(fakeVideoState));
}
@SmallTest
@Test
public void testAcceptRingingCallWithValidVideoState() throws Exception {
Call call = mock(Call.class);
- when(mFakeCallsManager.getFirstCallWithState(anyInt())).thenReturn(call);
+ when(mFakeCallsManager.getFirstCallWithState(anyInt(), anyInt())).thenReturn(call);
// Not intended to be a real video state. Here to ensure that the call will be answered
// with the video state passed in to acceptRingingCallWithVideoState
int fakeVideoState = 29578215;
int realVideoState = VideoProfile.STATE_RX_ENABLED | VideoProfile.STATE_TX_ENABLED;
when(call.getVideoState()).thenReturn(fakeVideoState);
mTSIBinder.acceptRingingCallWithVideoState("", realVideoState);
- verify(call).answer(realVideoState);
+ verify(mFakeCallsManager).answerCall(eq(call), eq(realVideoState));
}
@SmallTest
@Test
public void testIsInCall() throws Exception {
when(mFakeCallsManager.hasOngoingCalls()).thenReturn(true);
- assertTrue(mTSIBinder.isInCall(DEFAULT_DIALER_PACKAGE));
+ assertTrue(mTSIBinder.isInCall(DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@Test
public void testNotIsInCall() throws Exception {
when(mFakeCallsManager.hasOngoingCalls()).thenReturn(false);
- assertFalse(mTSIBinder.isInCall(DEFAULT_DIALER_PACKAGE));
+ assertFalse(mTSIBinder.isInCall(DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@@ -976,7 +1165,7 @@
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
anyString(), any());
try {
- mTSIBinder.isInCall("blah");
+ mTSIBinder.isInCall("blah", null);
fail();
} catch (SecurityException e) {
// desired result
@@ -988,14 +1177,14 @@
@Test
public void testIsInManagedCall() throws Exception {
when(mFakeCallsManager.hasOngoingManagedCalls()).thenReturn(true);
- assertTrue(mTSIBinder.isInManagedCall(DEFAULT_DIALER_PACKAGE));
+ assertTrue(mTSIBinder.isInManagedCall(DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@Test
public void testNotIsInManagedCall() throws Exception {
when(mFakeCallsManager.hasOngoingManagedCalls()).thenReturn(false);
- assertFalse(mTSIBinder.isInManagedCall(DEFAULT_DIALER_PACKAGE));
+ assertFalse(mTSIBinder.isInManagedCall(DEFAULT_DIALER_PACKAGE, null));
}
@SmallTest
@@ -1004,7 +1193,7 @@
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
anyString(), any());
try {
- mTSIBinder.isInManagedCall("blah");
+ mTSIBinder.isInManagedCall("blah", null);
fail();
} catch (SecurityException e) {
// desired result
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 442c310..aeb68c5 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -78,6 +79,7 @@
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ContactsAsyncHelper;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
import com.android.server.telecom.HeadsetMediaButton;
import com.android.server.telecom.HeadsetMediaButtonFactory;
import com.android.server.telecom.InCallWakeLockController;
@@ -207,6 +209,7 @@
@Mock ClockProxy mClockProxy;
@Mock RoleManagerAdapter mRoleManagerAdapter;
@Mock ToneGenerator mToneGenerator;
+ @Mock DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
final ComponentName mInCallServiceComponentNameX =
new ComponentName(
@@ -348,6 +351,8 @@
doReturn(mSpyContext).when(mSpyContext).getApplicationContext();
doNothing().when(mSpyContext).sendBroadcastAsUser(any(), any(), any());
+ doReturn(mock(AppOpsManager.class)).when(mSpyContext).getSystemService(AppOpsManager.class);
+
mHandlerThread = new HandlerThread("TelecomHandlerThread");
mHandlerThread.start();
@@ -475,7 +480,8 @@
when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(null);
mTelecomSystem = new TelecomSystem(
mComponentContextFixture.getTestDouble(),
- (context, phoneAccountRegistrar, defaultDialerCache) -> mMissedCallNotifier,
+ (context, phoneAccountRegistrar, defaultDialerCache, mDeviceIdleControllerAdapter)
+ -> mMissedCallNotifier,
mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
headsetMediaButtonFactory,
proximitySensorManagerFactory,
@@ -535,7 +541,7 @@
ContactsAsyncHelper.ContentResolverAdapter adapter) {
return new ContactsAsyncHelper(adapter, mHandlerThread.getLooper());
}
- });
+ }, mDeviceIdleControllerAdapter);
mComponentContextFixture.setTelecomManager(new TelecomManager(
mComponentContextFixture.getTestDouble(),
@@ -925,7 +931,12 @@
// Wait for the handler to start the CallerInfo lookup
waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+ // Wait a few more times to address flakiness due to timing issues.
+ waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+ waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+
// Ensure callback to CS on successful creation happened.
+
verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
.createConnectionComplete(anyString(), any());
@@ -1111,6 +1122,54 @@
return ids;
}
+ protected IdPair startAndMakeDialingOutgoingCall(
+ String number,
+ PhoneAccountHandle phoneAccountHandle,
+ ConnectionServiceFixture connectionServiceFixture) throws Exception {
+ IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
+ Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
+
+ connectionServiceFixture.sendSetDialing(ids.mConnectionId);
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_DIALING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_DIALING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+ }
+
+ return ids;
+ }
+
+ protected IdPair startAndMakeRingingIncomingCall(
+ String number,
+ PhoneAccountHandle phoneAccountHandle,
+ ConnectionServiceFixture connectionServiceFixture) throws Exception {
+ IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
+
+ if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+ assertEquals(Call.STATE_RINGING,
+ mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+ assertEquals(Call.STATE_RINGING,
+ mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+ mInCallServiceFixtureX.mInCallAdapter
+ .answerCall(ids.mCallId, VideoProfile.STATE_AUDIO_ONLY);
+
+ waitForHandlerAction(mTelecomSystem.getCallsManager()
+ .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
+ if (!VideoProfile.isVideo(VideoProfile.STATE_AUDIO_ONLY)) {
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+ .answer(eq(ids.mConnectionId), any());
+ } else {
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+ .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_AUDIO_ONLY),
+ any());
+ }
+ }
+ return ids;
+ }
+
protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
int elapsed = 0;
while (elapsed < TEST_TIMEOUT) {
diff --git a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
index b0b1ec0..264e087 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
@@ -25,8 +25,10 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
public abstract class TelecomTestCase {
protected static final String TESTING_TAG = "Telecom-TEST";
@@ -75,4 +77,13 @@
}
}
}
+
+ protected static <T> int findFirstIndexMatching(List<T> items, Predicate<T> matcher) {
+ for (int i = 0; i < items.size(); i++) {
+ if (matcher.test(items.get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
}