เทเลคอม

ไลบรารี Android Telecom Jetpack ใหม่ช่วยให้บอกแพลตฟอร์มได้อย่างง่ายดายว่า ระบุว่ามีการโทรของคุณแล้ว คุณค้นหาซอร์สโค้ดและแอปตัวอย่างได้ใน GitHub

การขึ้นต่อกันและสิทธิ์

ก่อนอื่น ให้เปิดไฟล์ build.gradle ของโมดูลแอป แล้วเพิ่มทรัพยากร Dependency สำหรับ โมดูล androidx Telecom:

dependencies {
    implementation ("androidx.core:core-telecom:1.0.0-alpha02")
}

ในไฟล์ Manifest ของแอป ให้ประกาศว่าแอปของคุณใช้ MANAGE_OWN_CALLS` สิทธิ์:

<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />

ลงทะเบียนแอปพลิเคชัน

คุณต้องลงทะเบียนแอปและความสามารถของแอปเพื่อให้ Android ทราบเกี่ยวกับแอปของคุณ ข้อมูลนี้จะบอก Android ว่าแอปของคุณรองรับฟีเจอร์ใดบ้าง เช่น วิดีโอคอล การโทร การสตรีม และการพักสาย ข้อมูลนี้สําคัญเพื่อให้ Android กําหนดค่าได้ ทำงานกับฟีเจอร์ของแอปได้

 private val callsManager = CallsManager(context)

var capabilities: @CallsManager.Companion.Capability Int =
    CallsManager.CAPABILITY_BASELINE or
          CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING or
          CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING

callsManager.registerAppWithTelecom(capabilities)

การผสานรวมแพลตฟอร์ม

สถานการณ์การโทรที่พบบ่อยที่สุด 2 แบบสำหรับแอปพลิเคชันการโทรคือสายเรียกเข้า และสายโทรออก เพื่อบันทึกทิศทางการโทรอย่างถูกต้องและ แจ้งเตือนผู้ใช้อย่างเหมาะสมโดยใช้ API ด้านล่าง

ลงทะเบียนการโทร

ตัวอย่างนี้แสดงวิธีลงทะเบียนสายเรียกเข้า

companion object {
  const val APP_SCHEME = "MyCustomScheme"
  const val ALL_CALL_CAPABILITIES = (CallAttributes.SUPPORTS_SET_INACTIVE
    or CallAttributes.SUPPORTS_STREAM or CallAttributes.SUPPORTS_TRANSFER)

  const val INCOMING_NAME = "Luke"
  val INCOMING_URI: Uri = Uri.fromParts(APP_SCHEME, "", "")
  // Define all possible properties for CallAttributes
  val INCOMING_CALL_ATTRIBUTES =
    CallAttributes(
      INCOMING_NAME,
      INCOMING_URI,
      DIRECTION_INCOMING,
      CALL_TYPE_VIDEO_CALL,
      ALL_CALL_CAPABILITIES)
}

ออบเจ็กต์ callAttributes อาจมีพร็อพเพอร์ตี้ต่อไปนี้

  • displayName: ชื่อของผู้โทร การประชุม หรือเซสชัน
  • address: ที่อยู่ของการโทร โปรดทราบว่าสามารถขยายระยะเวลานี้ไปยังการประชุมได้ ลิงก์
  • direction: ทิศทางการโทร เช่น สายเรียกเข้าหรือสายโทรออก
  • callType: รายละเอียดเกี่ยวกับข้อมูลที่ส่ง เช่น วิดีโอ และเสียง
  • callCapabilities: ออบเจ็กต์ที่ระบุความสามารถในการเรียกใช้

ออบเจ็กต์ callCapabilities อาจมีพร็อพเพอร์ตี้ต่อไปนี้

  • streaming: ระบุว่าการโทรรองรับการสตรีมเสียงไปยังอุปกรณ์อื่นหรือไม่ อุปกรณ์ที่ใช้ระบบ Android
  • transfer: ระบุว่าโอนสายได้หรือไม่
  • hold: ระบุว่าจะพักสายได้หรือไม่

เพิ่มสาย

เมธอด addCall() จะแสดงข้อยกเว้นหากอุปกรณ์ไม่รองรับ โทรคมนาคม หรือหากเกิดข้อผิดพลาดขณะตั้งค่าการโทร

try {
    callsManager.addCall(
        INCOMING_CALL_ATTRIBUTES,
        onIsCallAnswered, // Watch needs to know if it can answer the call
        onIsCallDisconnected,
        onIsCallActive,
        onIsCallInactive
    ) {
        callControlScope = this
    }
}

รับสาย

หลังจากโทรออกแล้ว คุณต้องรับสายหรือปฏิเสธสาย ช่วงเวลานี้ การสอบสาธิตวิธีการรับสาย:

when (answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
    is CallControlResult.Success -> {

    }

    is CallControlResult.Error -> {

    }
}

หากมีการโทรอื่นอีก answer() จะโทรกลับ CallControlResult.Error ซึ่งแจ้งสาเหตุที่ไม่สามารถรับสายได้ ใน ในกรณีนี้ ผู้ใช้ต้องพักสายอีกสายหนึ่ง

ปฏิเสธสาย

หากไม่ต้องการรับสาย ให้ยกเลิกการเชื่อมต่อกับ DisconnectCause.Rejected

fun onRejectCall(){
    coroutineScope.launch {
        callControlScope?.let {
            it.disconnect(DisconnectCause(DisconnectCause.REJECTED))
        }
    }
}

สายโทรออก

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

when (setActive()) {
    is CallControlResult.Success -> {
        onIsCallActive()
    }

    is CallControlResult.Error -> {
        updateCurrentCall {
            copy(errorCode = result.errorCode)
        }
    }
}

พักสาย

หากแอปโทรรองรับการพักสาย ให้ใช้ setInActive เพื่อบอก แพลตฟอร์มที่ไม่ได้ใช้งานการโทรของคุณ และการใช้ไมโครโฟนและกล้อง ใช้โดยแอปอื่นๆ:

when (setInActive()) {
    is CallControlResult.Success -> {

    }

    is CallControlResult.Error -> {
        updateCurrentCall {
            copy(errorCode = result.errorCode)
        }
    }
}

ยกเลิกการเชื่อมต่อ

หากต้องการยกเลิกการเชื่อมต่อ ให้แจ้งสแต็ก Telecom ให้ยกเลิกการเชื่อมต่อโดยการระบุ สาเหตุที่เป็นไปได้:

coroutineScope.launch {
    callControlScope?.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}

เสียงกำหนดเส้นทาง

ระหว่างการโทร บางครั้งผู้ใช้สลับไปมาระหว่างอุปกรณ์ต่างๆ เช่น ลําโพง หูฟังโทรศัพท์ หรืออุปกรณ์บลูทูธ ใช้ availableEndpoints และ currentCallEndpoint API เพื่อรับรายการอุปกรณ์ทั้งหมดที่ใช้ได้สำหรับ ผู้ใช้ และอุปกรณ์ที่ใช้งานอยู่

ตัวอย่างนี้ได้รวมทั้ง 2 ขั้นตอนเข้าด้วยกันเพื่อสร้างออบเจ็กต์ UI ที่จะแสดงให้ผู้ใช้เห็น รายชื่ออุปกรณ์และอุปกรณ์ที่ใช้งานอยู่

availableEndpoint = combine(callControlScope.availableEndpoints,
    callControlScope.currentCallEndpoint) {
    availableDevices: List<CallEndpoint>, activeDevice : CallEndpoint ->
    availableDevices.map {
        EndPointUI(
            isActive = activeDevice.endpointName == it.endpointName, it
        )
    }
}

หากต้องการเปลี่ยนอุปกรณ์ที่ใช้งานอยู่ ให้ใช้ requestEndpointChange ด้วย CallEndpointที่คุณต้องการเปลี่ยนไปใช้

coroutineScope.launch {
     callControlScope?.requestEndpointChange(callEndpoint)
}

การสนับสนุนในเบื้องหน้า

ไลบรารีโทรคมนาคมมาพร้อมการสนับสนุนในเบื้องหน้า ไลบรารีนี้ใช้ ConnectionService สำหรับอุปกรณ์ที่ใช้ Android 13 และต่ำกว่า สำหรับ Android 14 และ สูงจะใช้ไมโครโฟนและกล้องประเภทพื้นหน้าเพื่อ รองรับบริการที่ทำงานอยู่เบื้องหน้า ดูข้อมูลเพิ่มเติมเกี่ยวกับบริการที่ทำงานอยู่เบื้องหน้า

แอปพลิเคชันต้องโพสต์การแจ้งเตือนเป็นส่วนหนึ่งของข้อกำหนดเบื้องหน้า เพื่อให้ผู้ใช้ทราบว่าแอปพลิเคชันกำลังทำงานในเบื้องหน้า

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

is TelecomCall.Registered -> {
    val notification = createNotification(call)
    notificationManager.notify(TELECOM_NOTIFICATION_ID, notification)
}

การรองรับ Surface

นาฬิกามีแอปพลิเคชันตัวรับสัญญาณปลายทางทั่วไป แอปพลิเคชันนี้จะให้ ผู้ใช้ที่มีอินเทอร์เฟซพื้นฐาน เช่น การรับสาย การปฏิเสธ และการตัดการเชื่อมต่อ แอปพลิเคชันรองรับการดำเนินการเหล่านี้ด้วยการใช้ฟังก์ชัน lambda ซึ่งแจ้งแพลตฟอร์มที่คุณได้ดำเนินการบนอุปกรณ์แล้ว

ฟังก์ชัน lambda แต่ละรายการจะหมดเวลาหลังผ่านไป 5 วินาทีหากทำธุรกรรมไม่สำเร็จ แอปพลิเคชันไม่ตอบสนอง

callsManager.addCall(
        attributes,
        onIsCallAnswered, // Watch/Auto need to know if they can answer the call
        onIsCallDisconnected,
        onIsCallActive,
        onIsCallInactive
    ) {
//Call Scope
}
/**
  *  Can the call be successfully answered??
  *  TIP: Check the connection/call state to see if you can answer a call
  *  Example you may need to wait for another call to hold.
  **/
val onIsCallAnswered: suspend(type: Int) -> Unit = {}

/**
  * Can the call perform a disconnect
  */
val onIsCallDisconnected: suspend (cause: DisconnectCause) -> Unit = {}

/**
  *  Check is see if you can make the call active.
  *  Other calls and state might stop us from activating the call
  */
val onIsCallActive: suspend () -> Unit = {
    updateCurrentCall {
    }
}

/**
  * Check to see if you can make the call inactivate
  */
val onIsCallInactive: suspend () -> Unit = {}