Android Telecom 架構 (也稱為「Telecom」) 可管理音訊和
以及透過 Android 裝置進行視訊通話包括使用 SIM 卡的通話,例如
通話
,以及採用
ConnectionService
API。
Telecom 管理的主要元件為 ConnectionService
InCallService
。
ConnectionService
實作項目會使用 VoIP 等技術進行連線
呼叫其他方。最常見的 ConnectionService
實作
電話是 ConnectionService
。用於連結電信業者電話。
InCallService
實作提供使用者介面,以便呼叫由
電信,可讓使用者控制通話及進行互動。最常出現
InCallService
是預先安裝的手機應用程式
裝置。
電信可以做為開關機,並轉送 ConnectionService
的呼叫
實作項目為 InCallService
呼叫的使用者介面
實作方式
您可能會基於下列原因實作 Telecom API:
- 如何建立替代品 安裝在系統手機應用程式中
- 為了整合通話解決方案 導入 Android 通話體驗
建立替代手機應用程式
如要在 Android 裝置上取代預設的手機應用程式,請按照下列步驟操作:
實作 InCallService
API。實作項目必須符合下列條件:
規定:
- 應用程式不得具有任何通話功能,且只能由使用者組成 呼叫介面。
- 它必須處理電信架構知道的所有呼叫,且不得發出
所做出的假設。舉例來說,不得假設
通話是以 SIM 卡式的電話服務進行,且會導入通話限制,
依據任何
ConnectionService
(例如強制執行電話服務) 為依據 視訊通話限制。
詳情請參閱 InCallService
。
整合通話解決方案
如要將呼叫解決方案整合到 Android 中,您必須遵守 以下選項:
實作自行管理的 ConnectionService API: 如果開發人員不想使用獨立的通話應用程式,就很適合使用這個選項 顯示其通話在預設電話應用程式中,而不會顯示其他通話 使用者介面
使用自行管理的
ConnectionService
時,您可以協助應用程式: 與裝置上原生電話通訊的互通性 與其他獨立呼叫應用程式 (實作此 API) 搭配使用。自行管理ConnectionService
API 也會管理音訊轉送和焦點。詳情請參閱 建構通話應用程式。實作 Managed ConnectionService API: 這個選項有助於開發依賴於 可為通話功能提供使用者介面。 例如:第三方實作 SIP 通話和 VoIP 通話功能 免費 Google Cloud 服務詳情請參閱
getDefaultDialerPackage()
。單獨使用
ConnectionService
只能提供連線呼叫。這項服務 沒有相關聯的使用者介面實作 InCallService 和 ConnectionService API: 如果您要
ConnectionService
的通話解決方案,由專屬使用者完成 介面,並在同一個使用者介面中顯示所有其他 Android 呼叫。 使用這個方法時,不得導入InCallService
對顯示的呼叫來源做出任何假設。此外, 實作ConnectionService
必須在沒有 設為您的自訂InCallService
。
過濾電話
搭載 Android 10 (API 級別 29) 以上版本的裝置可讓應用程式識別
撥打不屬於使用者通訊錄的電話,可能是騷擾電話
呼叫。使用者可以選擇讓系統拒絕騷擾電話,為了提供
針對錯過來電的使用者提供公開透明的資訊;對於已封鎖的來電相關資訊
通話記錄。使用 Android 10 API 時,系統不會顯示
以便取得
READ_CALL_LOG
敬上
使用者授權,以便提供來電過濾和來電顯示功能
功能。
您使用
CallScreeningService
敬上
。在
onScreenCall()
敬上
功能。
使用者的聯絡人清單。如要查看
Call.Details
物件資訊
有關通話的內容具體而言,
getCallerNumberVerificationStatus()
敬上
函式包含網路供應商提供的另一個號碼相關資訊。
如果驗證狀態失敗,表示此呼叫:
。
Kotlin
class ScreeningService : CallScreeningService() { // This function is called when an ingoing or outgoing call // is from a number not in the user's contacts list override fun onScreenCall(callDetails: Call.Details) { // Can check the direction of the call val isIncoming = callDetails.callDirection == Call.Details.DIRECTION_INCOMING if (isIncoming) { // the handle (e.g. phone number) that the Call is currently connected to val handle: Uri = callDetails.handle // determine if you want to allow or reject the call when (callDetails.callerNumberVerificationStatus) { Connection.VERIFICATION_STATUS_FAILED -> { // Network verification failed, likely an invalid/spam call. } Connection.VERIFICATION_STATUS_PASSED -> { // Network verification passed, likely a valid call. } else -> { // Network could not perform verification. // This branch matches Connection.VERIFICATION_STATUS_NOT_VERIFIED. } } } } }
Java
class ScreeningService extends CallScreeningService { @Override public void onScreenCall(@NonNull Call.Details callDetails) { boolean isIncoming = callDetails.getCallDirection() == Call.Details.DIRECTION_INCOMING; if (isIncoming) { Uri handle = callDetails.getHandle(); switch (callDetails.getCallerNumberVerificationStatus()) { case Connection.VERIFICATION_STATUS_FAILED: // Network verification failed, likely an invalid/spam call. break; case Connection.VERIFICATION_STATUS_PASSED: // Network verification passed, likely a valid call. break; default: // Network could not perform verification. // This branch matches Connection.VERIFICATION_STATUS_NOT_VERIFIED } } } }
設定要呼叫的 onScreenCall()
函式
respondToCall()
通知系統如何回應新的呼叫這個函式採用
CallResponse
敬上
參數,可用來指示系統封鎖呼叫,就像
使用者手動操作或關閉通知。您也可以指示系統略過新增這個指令碼
自動打回裝置的通話記錄。
Kotlin
// Tell the system how to respond to the incoming call // and if it should notify the user of the call. val response = CallResponse.Builder() // Sets whether the incoming call should be blocked. .setDisallowCall(false) // Sets whether the incoming call should be rejected as if the user did so manually. .setRejectCall(false) // Sets whether ringing should be silenced for the incoming call. .setSilenceCall(false) // Sets whether the incoming call should not be displayed in the call log. .setSkipCallLog(false) // Sets whether a missed call notification should not be shown for the incoming call. .setSkipNotification(false) .build() // Call this function to provide your screening response. respondToCall(callDetails, response)
Java
// Tell the system how to respond to the incoming call // and if it should notify the user of the call. CallResponse.Builder response = new CallResponse.Builder(); // Sets whether the incoming call should be blocked. response.setDisallowCall(false); // Sets whether the incoming call should be rejected as if the user did so manually. response.setRejectCall(false); // Sets whether ringing should be silenced for the incoming call. response.setSilenceCall(false); // Sets whether the incoming call should not be displayed in the call log. response.setSkipCallLog(false); // Sets whether a missed call notification should not be shown for the incoming call. response.setSkipNotification(false); // Call this function to provide your screening response. respondToCall(callDetails, response.build());
您必須在資訊清單中註冊 CallScreeningService
實作項目
檔案含有適當意圖篩選器和權限,以利系統觸發
但事實並非如此
<service
android:name=".ScreeningService"
android:permission="android.permission.BIND_SCREENING_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallScreeningService" />
</intent-filter>
</service>
轉接來電
搭載 Android 10 以上版本的裝置管理呼叫意圖的方式與管理方式有所不同
搭載 Android 9 以下版本的裝置。在 Android 10 以上版本中,
ACTION_NEW_OUTGOING_CALL
敬上
應以
CallRedirectionService
也能使用 Google Cloud CLI 或
Compute Engine APICallRedirectionService
提供的介面可用於
修改 Android 平台撥出的電話。例如,第三方
應用程式可能會取消通話,並透過 IP 網路語音傳遞技術重新轉送。
Kotlin
class RedirectionService : CallRedirectionService() { override fun onPlaceCall( handle: Uri, initialPhoneAccount: PhoneAccountHandle, allowInteractiveResponse: Boolean ) { // Determine if the call should proceed, be redirected, or cancelled. val callShouldProceed = true val callShouldRedirect = false when { callShouldProceed -> { placeCallUnmodified() } callShouldRedirect -> { // Update the URI to point to a different phone number or modify the // PhoneAccountHandle and redirect. redirectCall(handle, initialPhoneAccount, true) } else -> { cancelCall() } } } }
Java
class RedirectionService extends CallRedirectionService { @Override public void onPlaceCall( @NonNull Uri handle, @NonNull PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse ) { // Determine if the call should proceed, be redirected, or cancelled. // Your app should implement this logic to determine the redirection. boolean callShouldProceed = true; boolean callShouldRedirect = false; if (callShouldProceed) { placeCallUnmodified(); } else if (callShouldRedirect) { // Update the URI to point to a different phone number or modify the // PhoneAccountHandle and redirect. redirectCall(handle, initialPhoneAccount, true); } else { cancelCall(); } } }
您必須在資訊清單中註冊這項服務,系統才能啟動服務 正確。
<service
android:name=".RedirectionService"
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService"/>
</intent-filter>
</service>
如要使用重新導向服務,應用程式必須要求來電轉接角色
來自 RoleManager
。這麼做會要求
使用者,如果想允許應用程式處理呼叫重新導向。如果您的應用程式
未獲授予這個角色,系統就不會使用重新導向服務。
您應該檢查使用者啟動應用程式時,應用程式是否具備上述角色,以便
但你可視需求提出申請啟動由 RoleManager
建立的意圖時,
因此,請務必覆寫
onActivityResult()
處理使用者選擇的函式。
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Tell the system that you want your app to handle call redirects. This // is done by using the RoleManager to register your app to handle redirects. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { val roleManager = getSystemService(Context.ROLE_SERVICE) as RoleManager // Check if the app needs to register call redirection role. val shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_CALL_REDIRECTION) && !roleManager.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION) if (shouldRequestRole) { val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION) startActivityForResult(intent, REDIRECT_ROLE_REQUEST_CODE) } } } companion object { private const val REDIRECT_ROLE_REQUEST_CODE = 1 } }
Java
class MainActivity extends AppCompatActivity { private static final int REDIRECT_ROLE_REQUEST_CODE = 0; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Tell the system that you want your app to handle call redirects. This // is done by using the RoleManager to register your app to handle redirects. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { RoleManager roleManager = (RoleManager) getSystemService(Context.ROLE_SERVICE); // Check if the app needs to register call redirection role. boolean shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_CALL_REDIRECTION) && !roleManager.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION); if (shouldRequestRole) { Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION); startActivityForResult(intent, REDIRECT_ROLE_REQUEST_CODE); } } } }