ה-Android Telecom framework (מוכר גם בשם Telecom) מנהל את האודיו
שיחות וידאו במכשיר Android. כולל שיחות מבוססות-SIM, כמו
שיחות
שמשתמשות במסגרת טלפוניה ובקריאות VoIP שמטמיעות את
ConnectionService
API.
הרכיבים העיקריים שמנוהלים על ידי Telecom הם ConnectionService
וגם
InCallService
.
הטמעה של ConnectionService
משתמשת בטכנולוגיות כמו VoIP כדי להתחבר
שיחות לגורמים אחרים. ההטמעה של ConnectionService
הכי נפוצה
הטלפון הוא מכשיר הטלפוניה ConnectionService
. הוא מאפשר חיבור לשיחות דרך ספק הסלולר.
הטמעת InCallService
מספקת ממשק משתמש לשיחות שמנוהלות על ידי
טלקומוניקציה ומאפשרת למשתמש לשלוט בשיחות האלה ולקיים איתן אינטראקציה. במידה הרבה ביותר
הטמעה נפוצה של InCallService
היא האפליקציה לטלפון שבחבילה
מכשיר.
הטלקום משמש כלוח בקרה. מתבצע ניתוב של שיחות ש-ConnectionService
וההטמעות מספקים לממשקי המשתמש ששולחים קריאה שInCallService
מספקים.
ייתכן שתרצו להטמיע את ממשקי ה-API של Telecom מהסיבות הבאות:
- כדי ליצור החלפה לאפליקציית המערכת לטלפון.
- כדי לשלב פתרון לשיחות לחוויית השיחה ב-Android.
יצירת אפליקציה חלופית לטלפון
כדי ליצור החלפה של אפליקציית ברירת המחדל לטלפון במכשיר Android:
להטמיע את ה-API של InCallService
. ההטמעה צריכה לעמוד בדרישות הבאות:
דרישות:
- אסור שיהיה לו היכולת לבצע שיחות והוא צריך להיות מורכב אך ורק מהמשתמש לשיחות.
- עליה לטפל בכל הקריאות שמסגרת הטלקום מודעת לקיומן, ולא לבצע
הנחות לגבי אופי השיחות. לדוגמה, אסור להניח
השיחות הן שיחות טלפוניה מבוססות-SIM, והשיחות לא כוללות הגבלות על השיחות
מבוססים על כל
ConnectionService
, כמו אכיפת נתוני טלפוניה הגבלות על שיחות וידאו.
מידע נוסף זמין במאמר הבא:
InCallService
איך משלבים פתרון לשיחות
כדי לשלב את פתרון השיחות ב-Android, צריך האפשרויות הבאות:
מטמיעים את ממשק ה-API של ConnectionService בניהול עצמי: האפשרות הזאת מתאימה במיוחד למפתחים של אפליקציות לשיחות עצמאיות שלא רוצים כדי להציג את השיחות שלהם באפליקציית הטלפון שמוגדרת כברירת מחדל, וגם לא יוצגו שיחות אחרות. בממשק המשתמש שלהם.
השימוש ב
ConnectionService
בניהול עצמי עוזר לאפליקציה: לפעול באופן הדדי לא רק עם שיחות טלפוניה מקומיות מהמכשיר, אלא גם בשילוב עם אפליקציות קריאה עצמאיות אחרות שמטמיעות את ה-API הזה. בניהול עצמי ה-API שלConnectionService
מנהל גם את הניתוב והמיקוד של האודיו. פרטים נוספים זמינים במאמר איך מפתחים אפליקציית שיחותמטמיעים את ממשק ה-API המנוהל של ConnectionService: האפשרות הזו מאפשרת לפתח פתרון לשיחות שמסתמך על את אפליקציית הטלפון הקיימת במכשיר כדי לספק את ממשק המשתמש לשיחות. לדוגמה: הטמעת צד שלישי של שיחות SIP ושיחות VoIP שירותים שונים. פרטים נוספים זמינים במאמר
getDefaultDialerPackage()
ConnectionService
לבדו מאפשר רק להתקשר. הוא לא משויך ממשק משתמש.מטמיעים את ה-API של InCallService ואת ConnectionService: האפשרות הזו מתאימה אם רוצים ליצור פתרון לשיחות מבוסס
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
במניפסט
עם הרשאה ומסנן 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 10 ואילך
מכשירים עם Android מגרסה 9 ומטה. ב-Android מגרסה 10 ואילך,
ACTION_NEW_OUTGOING_CALL
הוצא משימוש והוחלף
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(); } } }
יש לרשום את השירות הזה במניפסט כדי שהמערכת תוכל להפעיל אותו בצורה נכונה.
<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); } } } }