Telecom

Library Jetpack Android Telecom yang baru memudahkan Anda memberi tahu platform tentang status panggilan Anda. Anda dapat menemukan kode sumber dan aplikasi contoh di GitHub.

Dependensi dan izin

Pertama, buka file build.gradle modul aplikasi Anda, lalu tambahkan dependensi untuk modul androidx Telecom:

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

Di manifes aplikasi, deklarasikan bahwa aplikasi Anda menggunakan izin MANAGE_OWN_CALLS`:

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

Mendaftarkan aplikasi

Untuk memberi tahu Android tentang aplikasi Anda, Anda harus mendaftarkannya dan kemampuannya. Atribut ini memberi tahu Android fitur yang didukung aplikasi Anda, seperti panggilan video, streaming panggilan, dan menahan panggilan. Info ini penting agar Android dapat mengonfigurasi dirinya sendiri agar berfungsi dengan fitur aplikasi Anda.

 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)

Integrasi platform

Dua skenario panggilan yang paling umum untuk aplikasi panggilan adalah panggilan masuk dan keluar. Untuk mendaftarkan arah panggilan dengan benar dan memberi tahu pengguna melalui notifikasi dengan benar, gunakan API di bawah ini.

Daftarkan panggilan

Contoh ini menunjukkan cara mendaftarkan panggilan masuk:

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)
}

Objek callAttributes dapat memiliki properti berikut:

  • displayName: Nama penelepon, rapat, atau sesi.
  • address: Alamat panggilan. Perlu diingat bahwa, fitur ini dapat diperluas ke link rapat.
  • direction: Arah panggilan, seperti masuk atau keluar.
  • callType: Informasi yang terkait dengan data yang dikirim, seperti video dan audio.
  • callCapabilities: Objek yang menentukan kemampuan panggilan.

Objek callCapabilities dapat memiliki properti berikut:

  • streaming: Menunjukkan apakah panggilan mendukung streaming audio ke perangkat lain yang didukung Android.
  • transfer: Menunjukkan apakah panggilan dapat ditransfer.
  • hold: Menunjukkan apakah panggilan dapat ditahan.

Tambahkan panggilan

Metode addCall() menampilkan pengecualian jika perangkat tidak mendukung telekomunikasi, atau jika terjadi error saat menyiapkan panggilan.

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

Menjawab telepon

Setelah melakukan panggilan masuk, Anda harus menjawab atau menolak panggilan tersebut. Ujian ini menunjukkan cara menjawab panggilan:

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

    }

    is CallControlResult.Error -> {

    }
}

Jika panggilan lain sedang berlangsung, answer() akan menampilkan CallControlResult.Error, yang menunjukkan alasan panggilan tidak dapat dijawab. Dalam hal ini, pengguna harus menahan panggilan lainnya.

Menolak panggilan

Untuk menolak panggilan, putuskan panggilan dengan DisconnectCause.Rejected.

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

Panggilan keluar

Saat melakukan panggilan keluar, setelah pihak jarak jauh menjawab, Anda harus menyetel panggilan ke aktif agar platform mengetahui bahwa panggilan sedang berlangsung:

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

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

Membekukan panggilan

Jika aplikasi panggilan Anda mendukung penahanan panggilan, gunakan setInActive untuk memberi tahu platform bahwa panggilan Anda tidak aktif dan mikrofon serta kamera bebas digunakan oleh aplikasi lain:

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

    }

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

Putuskan koneksi

Untuk memutuskan sambungan panggilan, beri tahu stack Telecom untuk memutuskan sambungan dengan memberikan penyebab yang valid:

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

Rutekan audio

Selama panggilan, pengguna terkadang beralih antar-perangkat, seperti speaker, earphone, atau perangkat Bluetooth. Gunakan API availableEndpoints dan currentCallEndpoint untuk mendapatkan daftar semua perangkat yang tersedia bagi pengguna dan perangkat mana yang aktif.

Contoh ini menggabungkan kedua alur tersebut untuk membuat objek UI yang akan ditampilkan kepada pengguna daftar perangkat dan perangkat mana yang aktif:

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

Untuk mengubah perangkat aktif, gunakan requestEndpointChange dengan CallEndpoint yang ingin Anda ubah.

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

Dukungan latar depan

Library Telecom dilengkapi dengan dukungan latar depan. Library ini menggunakan ConnectionService untuk perangkat yang menjalankan Android 13 dan yang lebih lama. Untuk Android 14 dan yang lebih tinggi, perangkat ini menggunakan mikrofon dan kamera jenis latar depan untuk mendukung layanan latar depan dengan benar. Pelajari layanan latar depan lebih lanjut.

Sebagai bagian dari persyaratan latar depan, aplikasi harus memposting notifikasi agar pengguna mengetahui bahwa aplikasi berjalan di latar depan.

Untuk memastikan aplikasi Anda mendapatkan prioritas eksekusi latar depan, buat notifikasi setelah Anda mendaftarkan panggilan ke platform. Prioritas latar depan dihapus saat aplikasi menghentikan panggilan atau notifikasi Anda tidak lagi valid.

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

Dukungan platform

Smartwatch memiliki aplikasi penerima endpoint generik. Aplikasi ini menyediakan antarmuka dasar kepada pengguna seperti menjawab, menolak, dan memutuskan panggilan. Aplikasi mendukung tindakan ini dengan menerapkan fungsi lambda yang menginformasikan platform bahwa Anda telah melakukan tindakan di perangkat.

Setiap fungsi lambda akan berakhir setelah 5 detik dengan transaksi yang gagal jika aplikasi Anda tidak merespons.

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 = {}