בניית אפליקציית ברירת מחדל לטלפון

אפליקציית ברירת מחדל לטלפון מאפשרת ל-Android Telecom framework להודיע לאפליקציה על מצב השיחה באמצעות מנהל התפקידים ושירות השיחה כדי ליצור החלפה לאפליקציית ברירת המחדל לטלפון במכשיר Android, ולהטמיע את InCallService API. ההטמעה צריכה לעמוד בדרישות הבאות:

אסור שהיא תכלול יכולת לבצע קריאה, והיא צריכה להכיל רק את ממשק המשתמש לביצוע קריאה. היא צריכה לטפל בכל הקריאות שמסגרת הטלקום מודעת להן, ולא להניח הנחות לגבי אופי השיחות. לדוגמה, אסור להניח שהשיחות הן שיחות טלפוניה מבוססות-SIM, ולא להטמיע הגבלות על שיחות שמבוססות על שירות ConnectionService מסוים, כמו אכיפת הגבלות טלפוניה בשיחות וידאו.

אפליקציית שיחות מאפשרת למשתמשים לקבל או לבצע שיחות אודיו או וידאו במכשיר במכשיר. אפליקציות לשיחות משתמשות בממשק משתמש משלהן לשיחות במקום ממשק ברירת המחדל של אפליקציית 'טלפון', כמו שמוצג בצילום המסך הבא.

דוגמה לאפליקציית שיחות
דוגמה לאפליקציית שיחות שמשתמשת בממשק משתמש משלה

המסגרת של Android כוללת את החבילה android.telecom, שכולל שיעורים שעוזרים לפתח אפליקציית שיחות בהתאם לתקשורת . בניית האפליקציה בהתאם למסגרת הטלקום מספקת היתרונות הבאים:

  • האפליקציה שלך פועלת באופן הדדי עם מערכת המשנה המקורית של תקשורת סלולרית במכשיר.
  • האפליקציה פועלת באופן תקין עם אפליקציות אחרות לשיחות שעומדות גם בדרישות של את המסגרת.
  • ה-framework עוזר לאפליקציה לנהל את הניתוב של האודיו והווידאו.
  • תוכנת ה-framework עוזרת לאפליקציה לקבוע אם מתמקדים בשיחות שלה.

הצהרות והרשאות במניפסט

בקובץ המניפסט של האפליקציה, יש להצהיר שהאפליקציה משתמשת ב MANAGE_OWN_CALLS בהרשאה, כפי שמוצג בדוגמה הבאה:

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

למידע נוסף בנושא הצהרה על הרשאות הניתנות לאפליקציה: הרשאות.

עליכם להצהיר על שירות שמציין את המחלקה שמממשת את כיתה אחת (ConnectionService) באפליקציה שלך. תקשורת מערכת המשנה דורשת שהשירות מצהיר על ההרשאה BIND_TELECOM_CONNECTION_SERVICE שאפשר לקשר אליו. בדוגמה הבאה מוסבר איך להצהיר על השירות ב: קובץ המניפסט של האפליקציה:

<service android:name="com.example.MyConnectionService"
    android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.ConnectionService" />
    </intent-filter>
</service>

למידע נוסף בנושא הצהרה על רכיבי אפליקציה, כולל שירותים: רכיבי האפליקציה.

הטמעת שירות החיבור

אפליקציית השיחות צריכה לספק הטמעה של המחלקה ConnectionService שאליה מערכת המשנה לתקשורת טלקומוניקציה יכולה לקשר אליה. ההטמעה של ConnectionService צריכה לעקוף את באמצעות השיטות הבאות:

onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)

תת-מערכת הטלקומוניקציה קוראת לשיטה הזו בתגובה ל האפליקציה שלך מתקשרת אל placeCall(Uri, Bundle) כדי ליצור שיחה יוצאת חדשה. האפליקציה שלך מחזירה מופע חדש של הטמעת המחלקה Connection (מידע נוסף זמין במאמר הבא: מטמיעים את החיבור) כדי לייצג את שיחה יוצאת. אפשר להתאים אישית עוד יותר את החיבור היוצא על ידי ביצוע את הפעולות הבאות:

onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

מערכת המשנה של תקשורת סלולרית מפעילה את השיטה הזו כשהאפליקציה מבצעת קריאה לשיטה placeCall(Uri, Bundle) והשיחה היוצאת לא יכולה להציב. בתגובה למצב הזה, האפליקציה צריכה להודיע למשתמש (עבור לדוגמה, באמצעות תיבת התראות או הודעה מוקדמת על כך שהשיחה היוצאת לא יכולה להיות ממוקם. ייתכן שהאפליקציה לא תוכל לבצע שיחה אם או במקרה שיש שיחה פעילה באפליקציה אחרת, שאי אפשר להתקשר אליה להמתין לפני ביצוע השיחה.

onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)

מערכת המשנה של תקשורת סלולרית מפעילה את השיטה הזו כשהאפליקציה שולחת קריאה ל-method addNewIncomingCall(PhoneAccountHandle, Bundle) כדי להודיע למערכת על שיחה נכנסת חדשה באפליקציה. האפליקציה שלך מחזירה מופע חדש של ההטמעה של Connection (עבור מידע נוסף זמין במאמר הטמעת החיבור). כדי לייצג את השיחה הנכנסת החדשה. אפשר לבצע התאמה אישית נוספת של הנתונים הנכנסים על ידי ביצוע הפעולות הבאות:

onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

תת-המערכת של הטלקום קוראת לשיטה הזו כשהאפליקציה קוראת לשיטה addNewIncomingCall(PhoneAccountHandle, Bundle) כדי לעדכן את Telecom שיחה נכנסת חדשה, אבל השיחה הנכנסת לא מותרת (לכן מידע נוסף, ראו מגבלות קריאה). האפליקציה שלך צריכה דחייה שקטה של השיחה הנכנסת, ואם רוצים, אפשר לפרסם הודעה כדי ליידע את המשתמש בשיחה שלא נענתה.

הטמעת החיבור

האפליקציה שלך צריכה ליצור מחלקה משנית של Connection כדי שמייצגים את השיחות באפליקציה. יש לשנות את השיטות הבאות ב: על ההטמעה שלך:

onShowIncomingCallUi()

תת-מערכת הטלקום קוראת לשיטה הזו כאשר מוסיפים שיחה נכנסת חדשה האפליקציה אמורה להציג את ממשק המשתמש של השיחה הנכנסת.

onCallAudioStateChanged(CallAudioState)

תת-המערכת של הטלקום קוראת לשיטה הזו כדי ליידע את האפליקציה שהאודיו הנוכחי המסלול או המצב השתנו. הקריאה הזו מתרחשת בתגובה לאפליקציה שלך שמשנה את מצב אודיו באמצעות setAudioRoute(int) . אפשר לקרוא לשיטה הזו גם אם המערכת משנה את נתיב האודיו (לדוגמה, כשאוזניות Bluetooth מתנתקות).

onHold()

מערכת המשנה לתקשורת סלולרית קוראת לשיטה הזו כשהיא רוצה להעביר שיחה למצב המתנה. בתגובה לבקשה הזו, האפליקציה צריכה להחזיק את השיחה ואז להפעיל את שיטה אחת (setOnHold()) לעדכון המערכת שהשיחה מתבצעת. מערכת המשנה של התקשורת עשויה לקרוא לשיטה הזו כאשר שירות בתוך השיחה, כמו Android Auto, שמציג את הבקשה להעביר בקשה מהמשתמש להעברת השיחה למצב המתנה. מערכת המשנה לטלקומוניקציה גם קוראת זוהי השיטה אם המשתמש מבצע שיחה כפעילה באפליקציה אחרת. לקבלת מידע נוסף מידע על שירותים בתוך השיחה: InCallService.

onUnhold()

תת-מערכת הטלקום קורא לשיטה הזו כאשר הוא רוצה להמשיך שיחה שבהמתנה. אחרי שהאפליקציה תופעל מחדש את השיחה, היא צריכה להפעיל את setActive() כדי להודיע למערכת שהשיחה כבר לא בהמתנה. תקשורת עשויה להפעיל את השיטה הזו כששירות בשיחה, כמו Android Auto, שמציג את השיחה שלך רוצה להעביר בקשה להמשך השיחה. עבור מידע נוסף על שירותים בתוך השיחה זמין בInCallService.

onAnswer()

תת-המערכת של הטלקום קוראת לשיטה הזו כדי לאפליקציה שלך. אחרי שהאפליקציה תענה את השיחה, היא צריכה להפעיל את setActive() כדי להודיע למערכת שהשיחה נענתה. תקשורת מערכת המשנה עשויה להפעיל את השיטה הזו כשהאפליקציה תוסיף שיחה נכנסת חדשה, קיימת שיחה פעילה באפליקציה אחרת שאי אפשר להעביר להמתנה. תת-המערכת של הטלקום מציגה את ממשק המשתמש של השיחה הנכנסת מטעם האפליקציה שלך במקרים האלה. ה-framework מספק שיטה של עומס יתר כדי לציין את מצב הווידאו שבו תענו לשיחה. לקבלת מידע נוסף מידע נוסף: onAnswer(int).

onReject()

תת-המערכת של הטלקום קוראת לשיטה הזו כשהיא רוצה לדחות שיחה. אחרי שהאפליקציה דחתה את הקריאה, היא צריכה לקרוא ל-setDisconnected(DisconnectCause) ולציין את REJECTED כפרמטר. האפליקציה שלך צריכה מפעילים את השיטה destroy() כדי ליידע אתכם למערכת שהאפליקציה עיבדה את הקריאה. מתת-מערכת הטלקומוניקציה קריאות השיטה הזו כשהמשתמש דחה שיחה נכנסת מהאפליקציה.

onDisconnect()

מערכת המשנה לתקשורת סלולרית מפעילה את השיטה הזו כשהיא רוצה לנתק שיחה. בסיום השיחה, האפליקציה צריכה להפעיל את השיטה setDisconnected(DisconnectCause) ולציין את LOCAL כפרמטר כדי לציין בעקבות בקשת המשתמש, השיחה התנתקה. האפליקציה אמורה לקרוא ל- שיטה destroy() לעדכון לתקשורת בתת-מערכת שבה האפליקציה עיבדה את הקריאה. המערכת עשויה לקרוא לשיטה הזו כשהמשתמש ניתק שיחה דרך שירות שיחה אחר, כמו Android Auto. המערכת קוראת לשיטה הזו גם כשהקריאה חייבת להיות מנותק כדי לאפשר ביצוע שיחות אחרות, לדוגמה, אם המשתמש רוצה כדי לבצע שיחת חירום. למידע נוסף על שירותים בתוך השיחה: InCallService

איך מתמודדים עם תרחישים נפוצים של שיחות

שימוש ב-API של ConnectionService בשיחה שלך כולל אינטראקציה עם הכיתות האחרות בandroid.telecom חבילה. בקטעים הבאים מתוארים תרחישים נפוצים של שיחות והאופן שבו צריך להשתמש בממשקי ה-API כדי לטפל בהם.

מענה לשיחות נכנסות

התהליך לטיפול בשיחות נכנסות משתנה אם מתקיימות שיחות באפליקציות אחרות או לא. הסיבה להבדל בתהליכים זו היא שמסגרת התקשורת עליך לקבוע מגבלות מסוימות כאשר יש קריאות פעילות באפליקציות אחרות להבטיח סביבה יציבה לכל אפליקציות השיחות במכשיר. לקבלת מידע נוסף אפשר לקרוא מידע נוסף במאמר אילוצי שיחות.

אין שיחות פעילות באפליקציות אחרות

כדי לענות לשיחות נכנסות כשאין שיחות פעילות באפליקציות אחרות, צריך לפעול לפי השלבים הבאים: את השלבים הבאים:

  1. האפליקציה שלך מקבלת שיחה נכנסת חדשה באמצעות המנגנונים הרגילים שלה.
  2. אפשר להשתמש בשיטה addNewIncomingCall(PhoneAccountHandle, Bundle) כדי להודיע למערכת המשנה של התקשורת הסלולרית על השיחה הנכנסת החדשה.
  3. מערכת המשנה לתקשורת מקשרת להטמעה של ConnectionService באפליקציה ומבקשת מופע חדש של המחלקה Connection שמייצגת את באמצעות השיטה onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. מערכת המשנה טלקום מודיעה לאפליקציה שלך שהיא צריכה להציג את השיחה הנכנסת שלה בממשק משתמש באמצעות השיטה onShowIncomingCallUi().
  5. האפליקציה שלך מציגה את ממשק המשתמש הנכנס שלה באמצעות התראה עם Intent במסך מלא. מידע נוסף זמין כאן: onShowIncomingCallUi().
  6. מפעילים את השיטה setActive() אם המשתמש מקבל את השיחה הנכנסת, או setDisconnected(DisconnectCause) שמציין את REJECTED כפרמטר ואחריו קוראים ל-method destroy() אם המשתמש דוחה את השיחה הנכנסת.

שיחות פעילות באפליקציות אחרות שלא ניתן להעביר להמתנה

כדי לענות לשיחות נכנסות כשיש שיחות פעילות באפליקציות אחרות שלא יכולות יושהה, צריך לבצע את השלבים הבאים:

  1. האפליקציה שלך מקבלת שיחה נכנסת חדשה באמצעות המנגנונים הרגילים שלה.
  2. אפשר להשתמש בשיטה addNewIncomingCall(PhoneAccountHandle, Bundle) כדי להודיע למערכת המשנה של התקשורת הסלולרית על השיחה הנכנסת החדשה.
  3. מערכת המשנה לתקשורת מקשרת להטמעה של ConnectionService באפליקציה ומבקשת מופע חדש של האובייקט Connection שמייצג שיחה נכנסת באמצעות השיטה onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. תת-מערכת הטלקום מציגה את ממשק המשתמש של השיחה הנכנסת עבור השיחה הנכנסת.
  5. אם המשתמש מקבל את השיחה, מערכת המשנה לתקשורת טלפוניה קוראת ל-method onAnswer(). יש להפעיל את השיטה setActive() כדי לציין לתקשורת תת-מערכת שהשיחה מחוברת עכשיו.
  6. אם המשתמש דוחה את השיחה, מערכת המשנה לתקשורת טלפוניה מפעילה את השיטה onReject(). צריך להפעיל את השיטה setDisconnected(DisconnectCause) ולציין את הערך REJECTED כפרמטר ואחריו את התו קריאה ל-method destroy().

ביצוע שיחות יוצאות

התהליך לביצוע שיחה יוצאת כולל טיפול באפשרות לא ניתן לבצע את הקריאה החוזרת בגלל מגבלות שקבעה מסגרת התקשורת. מידע נוסף על אילוצים של שיחות

כדי לבצע שיחה יוצאת, מבצעים את השלבים הבאים:

  1. המשתמש יוזם שיחה יוצאת בתוך האפליקציה.
  2. משתמשים בשיטה placeCall(Uri, Bundle) כדי לציין את של התקשורת היוצאת החדשה. צריך לקחת את הדברים הבאים לגבי הפרמטרים של השיטה:
    • הפרמטר Uri מייצג את הכתובת שבה נשלחת אליך שיחה. למספרי טלפון רגילים, יש להשתמש ב-URI tel: scheme.
    • הפרמטר Bundle מאפשר לספק מידע על אפליקציית השיחות שלך, על ידי הוספת האובייקט PhoneAccountHandle של האפליקציה לתוספת EXTRA_PHONE_ACCOUNT_HANDLE. שלך האפליקציה חייבת לספק את האובייקט PhoneAccountHandle לכל שיחה יוצאת.
    • באמצעות הפרמטר Bundle אפשר גם לציין אם שיחה יוצאת כוללת וידאו על ידי ציון הערך STATE_BIDIRECTIONAL בתוספת EXTRA_START_CALL_WITH_VIDEO_STATE. קח בחשבון שכברירת מחדל, תת-מערכת הטלקום מנתבת שיחות וידאו דיבורית.
  3. מערכת המשנה לתקשורת מקשרת ל-ConnectionService של האפליקציה יישום בפועל.
  4. אם באפליקציה אין אפשרות לבצע שיחה יוצאת, מערכת המשנה לתקשורת טלפוניה השיטה onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest) להודיע לאפליקציה שלא ניתן להתקשר כרגע. האפליקציה שלך צריך להודיע למשתמש שאי אפשר לבצע את השיחה.
  5. אם באפליקציה יכולה לבצע את השיחה היוצאת, תת-מערכת המשנה של התקשורת תתקשר onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest) . האפליקציה צריכה להחזיר מופע של הכיתה Connection כדי לייצג את השיחה היוצאת החדשה. עבור מידע נוסף על המאפיינים שצריך להגדיר בחיבור, למידע נוסף, ראו הטמעה של שירות החיבור.
  6. לאחר שהשיחה היוצאת מחוברת, צריך להפעיל את השיטה setActive() כדי להודיע למערכת המשנה של התקשורת היוצאת שהשיחה פעילה.

איך מסיימים שיחות

כך מסיימים שיחות:

  1. קוראים ל-setDisconnected(DisconnectCause) ששולח את LOCAL כפרמטר, אם המשתמש סיימת את השיחה או שליחת המספר REMOTE בתור הפרמטר אם הצד השני סיים את הקריאה.
  2. מפעילים את השיטה destroy().

מגבלות שיחה

כדי להבטיח חוויית שיחה עקבית ופשוטה למשתמשים, תקשורת אוכפת מגבלות מסוימות על ניהול שיחות במכשיר. עבור נניח שהמשתמש התקין שתי אפליקציות לשיחות שמטמיעות ממשק ה-API של ConnectionService בניהול עצמי, FooTalk BarTalk. במקרה הזה, חלות המגבלות הבאות:

  • במכשירים עם רמת API 27 ומטה, רק אפליקציה אחת יכולה לנהל שיחה פעילה בכל זמן נתון. האילוץ הזה אומר שלמרות שלמשתמש יש שיחה פעילה באמצעות אפליקציית FooTalk, אפליקציית BarTalk לא יכולה ליזום או לקבל שיחה חדשה.

    במכשירים עם רמת API 28 ומעלה, אם גם FooTalk וגם BarTalk הצהרה CAPABILITY_SUPPORT_HOLD וגם CAPABILITY_HOLD הרשאות, המשתמש יכול לנהל יותר משיחה מתמשכת אחת באמצעות מעבר בין האפליקציות כדי להתחיל שיחה אחרת או לענות לה.

  • אם המשתמש מעורב בשיחות מנוהלות רגילות (לדוגמה, באמצעות אפליקציית 'טלפון' או 'חייגן' מובנית), המשתמש לא יכול להיות מחובר לשיחות לאפליקציות לשיחות. המשמעות היא שאם המשתמש נמצא בשיחה רגילה באמצעות ולכן הם לא יכולים להשתתף בשיחה של FooTalk או BarTalk בו-זמנית.

  • מערכת המשנה לטלקומוניקציה מנתקת את השיחות מהאפליקציה אם המשתמש מחייג שיחת חירום.

  • האפליקציה לא יכולה לקבל או לבצע שיחות בזמן שהמשתמש נמצא בשיחת חירום.

  • מה קורה אם יש שיחה פעילה באפליקציית שיחות אחרת כשהאפליקציה מקבלת שיחה נכנסת, מענה לשיחה הנכנסת יפסיק את כל השיחות הפעילות אפליקציה אחרת. האפליקציה לא תציג את ממשק המשתמש הרגיל שלה לשיחות נכנסות. מסגרת הטלקומוניקציה מציגה את ממשק המשתמש של השיחה הנכנסת ומודיעה המשתמש שיענה לשיחה החדשה יסיים את השיחות הנוכחיות שלו. הזה כלומר, אם המשתמש נמצא בשיחה ב-FooTalk ואפליקציית BarTalk מקבלת שיחה נכנסת, מסגרת הטלקומוניקציה מיידעת את המשתמש שיש לו שיחה נכנסת ב-BarTalk ומענה לשיחה ב-BarTalk יסיים את שיחת FooTalk.

להפוך לאפליקציית ברירת המחדל לטלפון

אפליקציית החייגן או אפליקציית הטלפון שמוגדרת כברירת מחדל היא אפליקציה שמספקת את ממשק המשתמש של השיחה כשהמכשיר בשיחה. הם גם מאפשרים למשתמש ליזום שיחות ולראות את היסטוריית השיחות במכשיר שלהם. המכשיר מגיע בחבילה עם אפליקציית חייגן או אפליקציית טלפון שהוגדרה כברירת מחדל על ידי המערכת. המשתמש/ת יכולים לבחור אפליקציה אחת שיקבל את התפקיד הזה מאפליקציית המערכת. אפליקציה שרוצה בתפקיד הזה, משתמשים בRoleManager כדי לבקש מהם למלא את RoleManager.ROLE_DIALER.

באפליקציית ברירת המחדל לטלפון יש ממשק משתמש בזמן שהמכשיר בשיחה, והמכשיר לא במצב מכונית (כלומר, UiModeManager#getCurrentModeType() לא Configuration.UI_MODE_TYPE_CAR).

כדי למלא את התפקיד RoleManager.ROLE_DIALER, אפליקציה צריכה לעמוד מספר דרישות:

  • היא צריכה לטפל ב-Intent Intent#ACTION_DIAL. כלומר, האפליקציה צריכה לספק ממשק משתמש של לוח חיוג שבאמצעותו המשתמש יוכל ליזום שיחות יוצאות.
  • חובה להטמיע בו את ה-API של InCallService באופן מלא ולספק גם שיחה נכנסת ממשק משתמש וממשק משתמש פעיל עבור שיחה.

הערה: אם האפליקציה שממלאת את השדה RoleManager.ROLE_DIALER מחזירה null InCallService במהלך הקישור, מסגרת ה-Telecom תיכשל באופן אוטומטי חזרה לשימוש באפליקציית החייגן שנטענה מראש במכשיר. המערכת תציג התראה ל המשתמש ויידע אותו שהשיחה נמשכה באמצעות אפליקציית החייגן שנטענו מראש. שלך אפליקציה לעולם לא תחזיר קישור null; כלומר, היא לא ממלאת הדרישות של RoleManager.ROLE_DIALER.

הערה: אם האפליקציה ממלאת את RoleManager.ROLE_DIALER ומבצעת שינויים בכתובת ולכן הוא לא עומד יותר בדרישות של התפקיד הזה, RoleManager יסיר באופן אוטומטי את האפליקציה מהתפקיד ותיסגר באפליקציה שלך. לדוגמה, אם משתמשים PackageManager.setComponentEnabledSetting(ComponentName, int, int) עד השבתה פרוגרמטית של InCallService האפליקציה שלך מצהירה במניפסט שלה לא יענה עוד על הדרישות הצפויות RoleManager.ROLE_DIALER

החייגן שנטען מראש יהיה תמיד בשימוש כשהמשתמש יבצע שיחת חירום, גם אם האפליקציה ממלאת את התפקיד RoleManager.ROLE_DIALER. כדי להבטיח שימוש מיטבי בזמן ביצוע שיחת חירום, חייגן ברירת המחדל אמור תמיד להשתמש TelecomManager.placeCall(Uri, Bundle) לביצוע שיחות (כולל שיחות חירום). כך הפלטפורמה יכולה לאמת שהבקשה הגיעה חייגן ברירת המחדל. אם אפליקציית חייגן שלא נטענה מראש משתמשת ב-Intent#ACTION_CALL כדי להציב שיחת חירום, היא תועבר לאפליקציית החייגן שנטען מראש באמצעות Intent#ACTION_DIAL לאישור; זוהי חוויית משתמש לא אופטימלית.

בהמשך מוצגת דוגמה לרישום מניפסט של InCallService. המטא-נתונים TelecomManager#METADATA_IN_CALL_SERVICE_UI מציין שהפרמטר הזה ההטמעה של InCallService נועדה להחליף את ממשק המשתמש המובנה בשיחה. המטא-נתונים TelecomManager#METADATA_IN_CALL_SERVICE_RINGING מציין InCallService ישמיע את הרינגטון של השיחה הנכנסת. צפייה בהמשך לקבלת מידע נוסף על הצגת השיחה הנכנסת השמעת הרינגטון באפליקציה.

 <service android:name="your.package.YourInCallServiceImplementation"
          android:permission="android.permission.BIND_INCALL_SERVICE"
          android:exported="true">
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
          android:value="true" />
      <intent-filter>
          <action android:name="android.telecom.InCallService"/>
      </intent-filter>
 </service>

הערה: אין לסמן את InCallService באמצעות המאפיין android:exported="false"; פעולה כזו עלולה לגרום לכך שלא יתבצע קישור להטמעה במהלך שיחות.

בנוסף להטמעת ה-API של InCallService, עליך גם להצהיר על פעילות ב- המניפסט שמטפל ב-Intent Intent#ACTION_DIAL. הדוגמה הבאה ממחישה איך עושים את זה:

 <activity android:name="your.package.YourDialerActivity"
           android:label="@string/yourDialerActivityLabel">
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
           <data android:scheme="tel" />
      </intent-filter>
 </activity>

כשמשתמש מתקין את האפליקציה ומריץ אותה בפעם הראשונה, צריך להשתמש RoleManager כדי לבקש מהמשתמש לבדוק אם הוא רוצה שהאפליקציה שלך להיות אפליקציית ברירת המחדל החדשה לטלפון.

הקוד הבא מראה איך האפליקציה יכולה לבקש להפוך לאפליקציית ברירת המחדל לטלפון/לחייגן:

 private static final int REQUEST_ID = 1;

 public void requestRole() {
     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
     startActivityForResult(intent, REQUEST_ID);
 }

 public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ID) {
         if (resultCode == android.app.Activity.RESULT_OK) {
             // Your app is now the default dialer app
         } else {
             // Your app is not the default dialer app
         }
     }
 }

גישה ל-InCallService למכשירים לבישים

    אם האפליקציה היא אפליקציה נלווית של צד שלישי והיא רוצה לגשת לממשקי ה-API של InCallService, צריך אפליקציות יכולות:

    1. הצהרה על ההרשאה MANAGE_ONGOING_CALLS במניפסט
    2. שיוך למכשיר לביש פיזי דרך ממשק ה-API של CompanionDeviceManager כאפליקציה נלווית. קישורים להנחיות ולשיטות המומלצות: https://developer.android.com/guide/topics/connectivity/companion-device-pairing
    3. יישום של InCallService עם הרשאת BIND_INCALL_SERVICE

מוצגת ההתראה על השיחה הנכנסת

כשהאפליקציה שלך מקבלת שיחה נכנסת חדשה דרך InCallService#onCallAdded(Call), היא אחראי להצגת ממשק המשתמש של שיחה נכנסת עבור השיחה הנכנסת. צריך לעשות זאת באמצעות ממשקי API של NotificationManager לפרסום התראה חדשה על שיחה נכנסת.

כאשר האפליקציה מצהירה על המטא-נתונים TelecomManager#METADATA_IN_CALL_SERVICE_RINGING, היא אחראי להשמעת הרינגטון עבור שיחות נכנסות. האפליקציה צריכה ליצור NotificationChannel שמציין את הרינגטון הרצוי. לדוגמה:

 NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls",
          NotificationManager.IMPORTANCE_MAX);
 // other channel setup stuff goes here.

 // We'll use the default system ringtone for our incoming call notification channel.  You can
 // use your own audio resource here.
 Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
 channel.setSound(ringtoneUri, new AudioAttributes.Builder()
          // Setting the AudioAttributes is important as it identifies the purpose of your
          // notification sound.
          .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
          .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
      .build());

 NotificationManager mgr = getSystemService(NotificationManager.class);
 mgr.createNotificationChannel(channel);

כשהאפליקציה מקבלת שיחה נכנסת חדשה, היא יוצרת Notification עבור שיחה נכנסת ומשייך אותה לערוץ ההתראות על שיחות נכנסות. אפשר לציין PendingIntent בהתראה שתפעיל את המסך המלא שלך ממשק המשתמש של השיחה הנכנסת. במסגרת של מנהל ההתראות תוצג ההודעה שלכם בתור התראה של 'שימו לב' אם המשתמש משתמש בטלפון באופן פעיל. כשהמשתמש לא משתמש טלפון, ייעשה שימוש בממשק המשתמש של השיחה הנכנסת במסך מלא. לדוגמה:

 // Create an intent which triggers your fullscreen incoming call user interface.
 Intent intent = new Intent(Intent.ACTION_MAIN, null);
 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setClass(context, YourIncomingCallActivity.class);
 PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 // Build the notification as an ongoing high priority item; this ensures it will show as
 // a heads up notification which slides down over top of the current content.
 final Notification.Builder builder = new Notification.Builder(context);
 builder.setOngoing(true);
 builder.setPriority(Notification.PRIORITY_HIGH);
 // Set notification content intent to take user to the fullscreen UI if user taps on the
 // notification body.
 builder.setContentIntent(pendingIntent);
 // Set full screen intent to trigger display of the fullscreen UI when the notification
 // manager deems it appropriate.
 builder.setFullScreenIntent(pendingIntent, true);
 // Setup notification content.
 builder.setSmallIcon( yourIconResourceId );
 builder.setContentTitle("Your notification title");
 builder.setContentText("Your notification content.");
 // Use builder.addAction(..) to add buttons to answer or reject the call.
 NotificationManager notificationManager = mContext.getSystemService(
     NotificationManager.class);
 notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
```