เฟรมเวิร์ก Android Telecom (หรือเรียกง่ายๆ ว่า "Telecom") จะจัดการการโทรด้วยเสียงและวิดีโอคอลในอุปกรณ์ที่ใช้ Android ซึ่งรวมถึงการโทรผ่านซิม เช่น การโทรที่ใช้เฟรมเวิร์กโทรศัพท์ และการโทรผ่าน VoIP ที่ใช้ไลบรารี Core-Telecom
Jetpack
คอมโพเนนต์หลักที่ Telecom จัดการคือ ConnectionService
และ
InCallService
การติดตั้งใช้งาน ConnectionService
สร้างขึ้นจากเทคโนโลยีต่างๆ เช่น PSTN เพื่อเชื่อมต่อการโทรไปยังบุคคลอื่น การใช้งาน ConnectionService
ที่พบบ่อยที่สุดในโทรศัพท์คือ ConnectionService
โทรศัพท์ ซึ่งจะเชื่อมต่อการโทรผ่านเครือข่ายของผู้ให้บริการ
การติดตั้งใช้งาน InCallService
จะมีอินเทอร์เฟซผู้ใช้สำหรับการโทรที่จัดการโดย Telecom และช่วยให้ผู้ใช้ควบคุมและโต้ตอบกับการโทรเหล่านี้ได้ การใช้งาน InCallService
ที่พบบ่อยที่สุดคือแอปโทรศัพท์ที่มาพร้อมกับอุปกรณ์
เทเลคอมจะทำหน้าที่เป็นแผงควบคุม โดยจะกำหนดเส้นทางการโทรที่ConnectionService
การติดตั้งใช้งานมีให้ไปยังอินเทอร์เฟซผู้ใช้ที่เรียกให้InCallService
การติดตั้งใช้งานมีให้
คุณอาจต้องติดตั้งใช้งาน Telecom API ด้วยเหตุผลต่อไปนี้
- หากต้องการสร้างแอปโทรศัพท์ระบบทดแทน
- หากต้องการผสานรวมโซลูชันการโทรเข้ากับประสบการณ์การโทรของ Android
สร้างแอปโทรศัพท์เปลี่ยนทดแทน
หากต้องการสร้างแอปโทรศัพท์เริ่มต้นทดแทนในอุปกรณ์ Android ให้ติดตั้งใช้งาน InCallService
API การติดตั้งใช้งานต้องเป็นไปตามข้อกําหนดต่อไปนี้
- โดยต้องไม่มีความสามารถในการโทร และต้องมีเพียงอินเทอร์เฟซผู้ใช้สำหรับการโทรเท่านั้น
- โดยต้องจัดการการโทรทั้งหมดที่เฟรมเวิร์กโทรคมนาคมรับรู้ และไม่ควรคาดเดาลักษณะของการโทร ตัวอย่างเช่น ต้องไม่ถือว่าการโทรเป็นการโทรผ่านโทรศัพท์ที่ใช้ซิม หรือใช้ข้อจำกัดการโทรที่อิงตาม
ConnectionService
รายการใดรายการหนึ่ง เช่น การบังคับใช้ข้อจำกัดการโทรสำหรับวิดีโอคอล
ดูข้อมูลเพิ่มเติมได้ที่ InCallService
ผสานรวมโซลูชันการโทร
หากต้องการผสานรวมโซลูชันการโทรเข้ากับ Android คุณมีตัวเลือกต่อไปนี้
ใช้คลัง Core-Telecom Jetpack ที่จัดการด้วยตนเอง:ตัวเลือกนี้เหมาะสำหรับนักพัฒนาแอปการโทรแบบสแตนด์อโลนที่ไม่ต้องการแสดงการโทรภายในแอปโทรศัพท์เริ่มต้น และไม่ต้องการให้แสดงการโทรอื่นๆ ในอินเทอร์เฟซผู้ใช้
เมื่อผสานรวมกับไลบรารี
Core-Telecom
Jetpack คุณจะทําให้แอปทํางานร่วมกันได้ไม่เพียงกับการโทรผ่านระบบโทรศัพท์ในอุปกรณ์เท่านั้น แต่ยังรวมถึงแอปการโทรแบบสแตนด์อโลนอื่นๆ ที่ผสานรวมกับ Telecom ด้วย ไลบรารีCore-Telecom
ยังจัดการการกำหนดเส้นทางและโฟกัสเสียงด้วย โปรดดูรายละเอียดที่หัวข้อสร้างแอปการโทรใช้ ConnectionService API ที่มีการจัดการ:ตัวเลือกนี้ช่วยอำนวยความสะดวกในการพัฒนาโซลูชันการโทรที่ใช้แอปพลิเคชันโทรศัพท์ของอุปกรณ์ที่มีอยู่เพื่อแสดงอินเทอร์เฟซผู้ใช้สำหรับการโทร ตัวอย่างเช่น การใช้งานบริการโทรผ่าน SIP และ VoIP ของบุคคลที่สาม ดูรายละเอียดเพิ่มเติมได้ที่
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
ในไฟล์ Manifest ด้วยตัวกรอง Intent และสิทธิ์ที่เหมาะสมเพื่อให้ระบบทริกเกอร์ได้อย่างถูกต้อง
<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
broadcasting แล้วแทนที่ด้วย CallRedirectionService
API CallRedirectionService
มีอินเทอร์เฟซให้คุณใช้เพื่อแก้ไขการโทรออกที่แพลตฟอร์ม Android ดำเนินการ เช่น แอปของบุคคลที่สามอาจยกเลิกการโทรและเปลี่ยนเส้นทางการโทรผ่าน VoIP
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(); } } }
คุณต้องลงทะเบียนบริการนี้ในไฟล์ Manifest เพื่อให้ระบบเริ่มต้นบริการได้อย่างถูกต้อง
<service
android:name=".RedirectionService"
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService"/>
</intent-filter>
</service>
หากต้องการใช้บริการเปลี่ยนเส้นทาง แอปของคุณต้องขอบทบาทการเปลี่ยนเส้นทางการโทรจาก RoleManager
ซึ่งจะถามผู้ใช้ว่าต้องการอนุญาตให้แอปจัดการการเปลี่ยนเส้นทางการโทรหรือไม่ หากแอปไม่ได้รับบทบาทนี้ ระบบจะไม่ใช้บริการเปลี่ยนเส้นทาง
คุณควรตรวจสอบว่าแอปมีบทบาทนี้เมื่อผู้ใช้เปิดแอปของคุณหรือไม่ เพื่อให้ขอบทบาทดังกล่าวได้หากจำเป็น คุณเปิดใช้งาน Intent ที่ 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); } } } }