הספרייה החדשה של Android Telecom Jetpack מאפשרת לספר לפלטפורמה בקלות המצב שבו נמצאת השיחה. תוכלו למצוא את קוד המקור ואפליקציה לדוגמה ב- GitHub.
יחסי תלות והרשאות
קודם כול, פותחים את הקובץ build.gradle של מודול האפליקציה ומוסיפים תלות מודול טלקום של androidx:
dependencies {
implementation ("androidx.core:core-telecom:1.0.0-alpha02")
}
בקובץ המניפסט של האפליקציה, צריך להצהיר שהאפליקציה שלך משתמשת ב-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)
שילוב פלטפורמה
שני התרחישים הנפוצים ביותר לביצוע שיחות בכל אפליקציה לשיחות הם ושיחות יוצאות. כדי לרשום בצורה נכונה את כיוון השיחה ליידע את המשתמש בהתאם לצורך. יש להשתמש בממשקי ה-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))
}
}
}
שיחה יוצאת
כשמבצעים שיחה יוצאת, ברגע שהצד המרוחק ישיב לשיחה, עליכם להגדיר את active (פעילה) כדי ליידע את הפלטפורמה שהשיחה מתבצעת:
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))
}
מסלול האודיו
במהלך שיחה, משתמשים עוברים לפעמים בין מכשירים, כמו רמקול,
אוזניה או מכשיר Bluetooth. שימוש בavailableEndpoints
וב
ממשקי ה-API של currentCallEndpoint
כדי לקבל רשימה של כל המכשירים הזמינים
של המשתמש ואיזה מכשיר פעיל.
הדוגמה הזו משלבת את שני התהליכים כדי ליצור אובייקט בממשק המשתמש שיוצג למשתמש רשימה של המכשירים והפעילים:
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)
}
תמיכה בחזית
ספריית Telecom כוללת תמיכה בחזית. הספרייה הזו משתמשת
ConnectionService
למכשירים עם Android מגרסה 13 ומטה. ב-Android מגרסה 14 ואילך
היא משתמשת במיקרופון ובמצלמה מהקדמה כדי
תמיכה בשירותים שפועלים בחזית. מידע נוסף על שירותים שפועלים בחזית
במסגרת דרישות החזית, האפליקציה חייבת לפרסם התראה כך שהמשתמשים ידעו שהאפליקציה פועלת בחזית.
כדי לוודא שהאפליקציה תקבל עדיפות לביצוע בחזית, צריך ליצור אחרי שתרשמו את השיחה בפלטפורמה. עדיפות בחזית מוסרת כשהאפליקציה מסיימת את השיחה או כשמפסיקים לקבל את ההתראה תקין.
is TelecomCall.Registered -> {
val notification = createNotification(call)
notificationManager.notify(TELECOM_NOTIFICATION_ID, notification)
}
תמיכה בממשק
לשעונים יש אפליקציה כללית של מקלט נקודות קצה. האפליקציה הזו מספקת את המשתמש בעזרת ממשק בסיסי כמו מענה, דחייה וניתוק שיחות. האפליקציה תומכת בפעולות האלה על ידי הטמעת פונקציות 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 = {}