ภาพรวมเฟรมเวิร์กโทรคมนาคม

เฟรมเวิร์ก Android Telecom (หรือเรียกง่ายๆ ว่า "Telecom") จะจัดการการโทรด้วยเสียงและวิดีโอคอลในอุปกรณ์ที่ใช้ Android ซึ่งรวมถึงการโทรผ่านซิม เช่น การโทรที่ใช้เฟรมเวิร์กโทรศัพท์ และการโทรผ่าน VoIP ที่ใช้ไลบรารี Core-Telecom Jetpack

คอมโพเนนต์หลักที่ Telecom จัดการคือ ConnectionService และ InCallService

การติดตั้งใช้งาน ConnectionService สร้างขึ้นจากเทคโนโลยีต่างๆ เช่น PSTN เพื่อเชื่อมต่อการโทรไปยังบุคคลอื่น การใช้งาน ConnectionService ที่พบบ่อยที่สุดในโทรศัพท์คือ ConnectionService โทรศัพท์ ซึ่งจะเชื่อมต่อการโทรผ่านเครือข่ายของผู้ให้บริการ

การติดตั้งใช้งาน InCallService จะมีอินเทอร์เฟซผู้ใช้สำหรับการโทรที่จัดการโดย Telecom และช่วยให้ผู้ใช้ควบคุมและโต้ตอบกับการโทรเหล่านี้ได้ การใช้งาน InCallService ที่พบบ่อยที่สุดคือแอปโทรศัพท์ที่มาพร้อมกับอุปกรณ์

เทเลคอมจะทำหน้าที่เป็นแผงควบคุม โดยจะกำหนดเส้นทางการโทรที่ConnectionService การติดตั้งใช้งานมีให้ไปยังอินเทอร์เฟซผู้ใช้ที่เรียกให้InCallService การติดตั้งใช้งานมีให้

คุณอาจต้องติดตั้งใช้งาน Telecom API ด้วยเหตุผลต่อไปนี้

สร้างแอปโทรศัพท์เปลี่ยนทดแทน

หากต้องการสร้างแอปโทรศัพท์เริ่มต้นทดแทนในอุปกรณ์ 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);             }         }     } }