یک برنامه پیش فرض تلفن بسازید

یک برنامه پیش‌فرض تلفن به چارچوب Android Telecom اجازه می‌دهد تا با استفاده از مدیر نقش و سرویس در تماس، برنامه شما را از وضعیت تماس مطلع کند تا جایگزینی برای برنامه پیش‌فرض تلفن در دستگاه Android ایجاد کند، InCallService API را پیاده‌سازی کند. پیاده سازی شما باید شرایط زیر را برآورده کند:

نباید قابلیت تماس داشته باشد و باید فقط از رابط کاربری برای تماس تشکیل شده باشد. باید تمام تماس‌هایی را که چارچوب مخابراتی از آن‌ها مطلع است رسیدگی کند و در مورد ماهیت تماس‌ها فرضیاتی ایجاد نکند. به عنوان مثال، نباید تماس‌ها را تماس‌های تلفنی مبتنی بر سیم‌کارت فرض کند، یا محدودیت‌های تماسی را که مبتنی بر یک ConnectionService است، مانند اعمال محدودیت‌های تلفنی برای تماس‌های ویدیویی، اعمال نکند.

یک برنامه تماس به کاربران امکان می دهد تماس های صوتی یا تصویری را روی دستگاه خود دریافت یا برقرار کنند. همانطور که در تصویر زیر نشان داده شده است، برنامه های تماس گیرنده به جای استفاده از رابط پیش فرض برنامه تلفن، از رابط کاربری خود برای تماس ها استفاده می کنند.

نمونه ای از برنامه تماس
نمونه ای از یک برنامه تماس با استفاده از رابط کاربری خود

فریم ورک اندروید شامل بسته android.telecom است که شامل کلاس هایی است که به شما کمک می کند تا یک برنامه تماس را مطابق چارچوب مخابراتی بسازید. ساخت اپلیکیشن خود بر اساس چارچوب مخابراتی مزایای زیر را به همراه دارد:

  • برنامه شما به درستی با زیرسیستم مخابراتی بومی در دستگاه کار می کند.
  • برنامه شما به درستی با سایر برنامه‌های تماس برقرار می‌کند که از چارچوب پیروی می‌کنند.
  • این چارچوب به برنامه شما کمک می کند تا مسیریابی صوتی و تصویری را مدیریت کند.
  • این چارچوب به برنامه شما کمک می‌کند تا تشخیص دهد که آیا تماس‌هایش فوکوس دارند یا خیر.

اعلامیه ها و مجوزهای آشکار

همانطور که در مثال زیر نشان داده شده است، در مانیفست برنامه خود، اعلام کنید که برنامه شما از مجوز 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 شما را برمی گرداند (برای اطلاعات بیشتر، به پیاده سازی اتصال مراجعه کنید) تا تماس خروجی جدید را نشان دهد. با انجام اقدامات زیر می توانید اتصال خروجی را بیشتر سفارشی کنید:

  • برنامه شما باید متد setConnectionProperties(int) را با ثابت PROPERTY_SELF_MANAGED به عنوان آرگومان فراخوانی کند تا نشان دهد که اتصال از یک برنامه تماس گرفته شده است.
  • اگر برنامه شما از قرار دادن تماس‌ها در حالت انتظار پشتیبانی می‌کند، متد setConnectionCapabilities(int) را فراخوانی کنید و آرگومان را روی مقدار بیت ماسک ثابت‌های CAPABILITY_HOLD و CAPABILITY_SUPPORT_HOLD تنظیم کنید.
  • برای تنظیم نام تماس گیرنده، از متد setCallerDisplayName(String, int) استفاده کنید و ثابت PRESENTATION_ALLOWED به عنوان پارامتر int ارسال کنید تا نشان دهید که نام تماس گیرنده باید نشان داده شود.
  • برای اطمینان از اینکه تماس خروجی دارای وضعیت ویدئویی مناسب است، متد setVideoState(int) شی Connection را فراخوانی کنید و مقدار بازگشتی توسط متد getVideoState() شی ConnectionRequest ارسال کنید.
onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

هنگامی که برنامه شما با روش placeCall(Uri, Bundle) تماس می گیرد و تماس خروجی نمی تواند برقرار شود، زیرسیستم مخابرات این روش را فراخوانی می کند. در پاسخ به این وضعیت، برنامه شما باید به کاربر اطلاع دهد (مثلاً با استفاده از جعبه هشدار یا نان تست) که تماس خروجی برقرار نیست. اگر یک تماس اضطراری مداوم وجود داشته باشد، یا اگر یک تماس در حال انجام در برنامه دیگری وجود داشته باشد که نمی تواند قبل از برقراری تماس شما متوقف شود، ممکن است برنامه شما نتواند تماسی برقرار کند.

onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)

هنگامی که برنامه شما روش addNewIncomingCall(PhoneAccountHandle, Bundle) را فراخوانی می کند تا سیستم را از تماس ورودی جدید در برنامه شما مطلع کند، زیرسیستم مخابرات این روش را فراخوانی می کند. برنامه شما نمونه جدیدی از اجرای Connection شما را برمی گرداند (برای اطلاعات بیشتر، به اجرای اتصال مراجعه کنید) تا تماس ورودی جدید را نشان دهد. با انجام اقدامات زیر می توانید اتصال ورودی را بیشتر سفارشی کنید:

  • برنامه شما باید متد setConnectionProperties(int) را با ثابت PROPERTY_SELF_MANAGED به عنوان آرگومان فراخوانی کند تا نشان دهد که اتصال از یک برنامه تماس گرفته شده است.
  • اگر برنامه شما از قرار دادن تماس‌ها در حالت انتظار پشتیبانی می‌کند، متد setConnectionCapabilities(int) را فراخوانی کنید و آرگومان را روی مقدار بیت ماسک ثابت‌های CAPABILITY_HOLD و CAPABILITY_SUPPORT_HOLD تنظیم کنید.
  • برای تنظیم نام تماس گیرنده، از متد setCallerDisplayName(String, int) استفاده کنید و ثابت PRESENTATION_ALLOWED به عنوان پارامتر int ارسال کنید تا نشان دهید که نام تماس گیرنده باید نشان داده شود.
  • برای تعیین شماره تلفن یا آدرس تماس ورودی، از روش setAddress(Uri, int) شی Connection استفاده کنید.
  • برای اطمینان از اینکه تماس خروجی دارای وضعیت ویدئویی مناسب است، متد setVideoState(int) شی Connection را فراخوانی کنید و مقدار بازگشتی توسط متد getVideoState() شی ConnectionRequest ارسال کنید.
onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

هنگامی که برنامه شما برای اطلاع از تماس ورودی جدید، از روش addNewIncomingCall(PhoneAccountHandle, Bundle) استفاده می‌کند، زیرسیستم مخابرات این روش را فراخوانی می‌کند، اما تماس ورودی مجاز نیست (برای اطلاعات بیشتر، محدودیت‌های تماس را ببینید). برنامه شما باید بی سر و صدا تماس دریافتی را رد کند و در صورت تمایل یک اعلان برای اطلاع کاربر از تماس از دست رفته ارسال کند.

اتصال را پیاده سازی کنید

برنامه شما باید یک زیر کلاس از Connection ایجاد کند تا تماس های موجود در برنامه شما را نشان دهد. در اجرای خود باید روش های زیر را نادیده بگیرید:

onShowIncomingCallUi()

هنگامی که یک تماس ورودی جدید اضافه می کنید و برنامه شما باید رابط کاربری تماس ورودی خود را نشان دهد، زیرسیستم مخابرات این روش را فراخوانی می کند.

onCallAudioStateChanged(CallAudioState)

زیرسیستم مخابرات این روش را فراخوانی می کند تا به برنامه شما اطلاع دهد که مسیر یا حالت فعلی صدا تغییر کرده است. این در پاسخ به تغییر حالت صوتی برنامه شما با استفاده از روش setAudioRoute(int) فراخوانی می شود. اگر سیستم مسیر صوتی را تغییر دهد (مثلاً وقتی هدست بلوتوث قطع می شود) ممکن است این روش فراخوانی شود.

onHold()

زیرسیستم مخابرات زمانی این روش را فراخوانی می کند که می خواهد تماسی را در حالت انتظار قرار دهد. در پاسخ به این درخواست، برنامه شما باید تماس را نگه دارد و سپس متد setOnHold() را فراخوانی کند تا به سیستم اطلاع دهد که تماس در حال برگزاری است. زمانی که یک سرویس حین تماس، مانند Android Auto که تماس شما را نشان می‌دهد، می‌خواهد درخواست کاربر را برای متوقف کردن تماس ارسال کند، زیرسیستم مخابراتی ممکن است این روش را فراخوانی کند. اگر کاربر تماسی را در اپلیکیشن دیگری فعال کند، زیرسیستم مخابرات نیز این روش را فراخوانی می‌کند. برای اطلاعات بیشتر در مورد خدمات در تماس، به InCallService مراجعه کنید.

onUnhold()

زیرسیستم مخابرات زمانی این روش را فراخوانی می کند که بخواهد تماسی را که در حالت انتظار قرار داده شده است، از سر بگیرد. هنگامی که برنامه شما تماس را از سر گرفت، باید متد setActive() را فراخوانی کند تا به سیستم اطلاع دهد که تماس دیگر در حالت انتظار نیست. هنگامی که یک سرویس حین تماس، مانند Android Auto که تماس شما را نشان می‌دهد، می‌خواهد درخواستی برای ازسرگیری تماس ارسال کند، زیرسیستم مخابراتی ممکن است این روش را فراخوانی کند. برای اطلاعات بیشتر در مورد خدمات در تماس، به InCallService مراجعه کنید.

onAnswer()

زیرسیستم مخابرات این روش را فراخوانی می کند تا به برنامه شما اطلاع دهد که باید به تماس ورودی پاسخ داده شود. هنگامی که برنامه شما به تماس پاسخ داد، باید متد setActive() را فراخوانی کند تا به سیستم اطلاع دهد که به تماس پاسخ داده شده است. هنگامی که برنامه شما یک تماس ورودی جدید اضافه می کند و در حال حاضر یک تماس در حال انجام در برنامه دیگری وجود دارد که نمی توان آن را در حالت انتظار قرار داد، زیرسیستم مخابراتی ممکن است این روش را فراخوانی کند. زیرسیستم مخابراتی در این موارد رابط کاربری تماس ورودی را از طرف برنامه شما نمایش می دهد. این چارچوب یک روش بیش از حد بارگذاری شده را ارائه می دهد که برای تعیین وضعیت ویدیویی که در آن به تماس پاسخ می دهد، پشتیبانی می کند. برای اطلاعات بیشتر، به onAnswer(int) مراجعه کنید.

onReject()

زیرسیستم مخابرات زمانی این روش را فراخوانی می کند که بخواهد تماس ورودی را رد کند. هنگامی که برنامه شما تماس را رد کرد، باید setDisconnected(DisconnectCause) را فراخوانی کند و REJECTED به عنوان پارامتر مشخص کند. سپس برنامه شما باید متد destroy() را فراخوانی کند تا به سیستم اطلاع دهد که برنامه تماس را پردازش کرده است. زیرسیستم مخابرات این روش را زمانی فراخوانی می کند که کاربر تماس دریافتی از برنامه شما را رد کرده باشد.

onDisconnect()

زیرسیستم مخابرات وقتی می خواهد تماسی را قطع کند این روش را فراخوانی می کند. پس از پایان تماس، برنامه شما باید متد setDisconnected(DisconnectCause) را فراخوانی کند و LOCAL به عنوان پارامتر مشخص کند تا نشان دهد که درخواست کاربر باعث قطع تماس شده است. سپس برنامه شما باید متد destroy() را فراخوانی کند تا به زیرسیستم مخابراتی اطلاع دهد که برنامه تماس را پردازش کرده است. سیستم ممکن است این روش را زمانی فراخوانی کند که کاربر تماس خود را از طریق سرویس دیگری مانند Android Auto قطع کرده باشد. سیستم همچنین زمانی این روش را فراخوانی می‌کند که تماس شما باید قطع شود تا امکان برقراری تماس دیگر وجود داشته باشد، مثلاً اگر کاربر بخواهد تماس اضطراری برقرار کند. برای اطلاعات بیشتر در مورد خدمات در تماس، به InCallService مراجعه کنید.

سناریوهای تماس رایج را مدیریت کنید

استفاده از ConnectionService API در جریان تماس شامل تعامل با کلاس‌های دیگر در بسته android.telecom است. بخش‌های زیر سناریوهای تماس رایج و نحوه استفاده برنامه شما از APIها برای مدیریت آنها را شرح می‌دهند.

به تماس های دریافتی پاسخ دهید

جریان رسیدگی به تماس‌های دریافتی تغییر می‌کند که آیا تماس‌هایی در برنامه‌های دیگر وجود دارد یا خیر. دلیل تفاوت در جریان ها این است که چارچوب مخابراتی باید محدودیت هایی را در زمانی که تماس های فعال در سایر برنامه ها وجود دارد ایجاد کند تا از یک محیط پایدار برای همه برنامه های تماس در دستگاه اطمینان حاصل شود. برای اطلاعات بیشتر، محدودیت‌های تماس را ببینید.

بدون تماس فعال در برنامه های دیگر

برای پاسخ دادن به تماس‌های دریافتی زمانی که هیچ تماس فعالی در برنامه‌های دیگر وجود ندارد، این مراحل را دنبال کنید:

  1. برنامه شما با استفاده از مکانیسم های معمول خود تماس ورودی جدیدی دریافت می کند.
  2. از روش addNewIncomingCall(PhoneAccountHandle, Bundle) برای اطلاع رسانی به زیرسیستم مخابراتی در مورد تماس ورودی جدید استفاده کنید.
  3. زیرسیستم مخابراتی به اجرای ConnectionService برنامه شما متصل می شود و یک نمونه جدید از کلاس Connection را درخواست می کند که نشان دهنده تماس ورودی جدید با استفاده از روش onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest) .
  4. زیرسیستم مخابراتی به برنامه شما اطلاع می دهد که باید رابط کاربری تماس ورودی خود را با استفاده از روش onShowIncomingCallUi() نشان دهد.
  5. برنامه شما رابط کاربری ورودی خود را با استفاده از یک اعلان با هدف تمام صفحه مرتبط نشان می دهد. برای اطلاعات بیشتر، onShowIncomingCallUi() را ببینید.
  6. اگر کاربر تماس ورودی را قبول کرد، متد setActive() را فراخوانی کنید، یا setDisconnected(DisconnectCause) را به عنوان پارامتر REJECTED و سپس در صورتی که کاربر تماس ورودی را رد کرد، یک فراخوانی به متد destroy() را مشخص کنید.

تماس‌های فعال در سایر برنامه‌ها که نمی‌توان آنها را در حالت انتظار قرار داد

برای پاسخ دادن به تماس‌های دریافتی وقتی تماس‌های فعالی در برنامه‌های دیگر وجود دارد که نمی‌توان آن‌ها را در حالت انتظار قرار داد، این مراحل را دنبال کنید:

  1. برنامه شما با استفاده از مکانیسم های معمول خود تماس ورودی جدیدی دریافت می کند.
  2. از روش addNewIncomingCall(PhoneAccountHandle, Bundle) برای اطلاع رسانی به زیرسیستم مخابراتی در مورد تماس ورودی جدید استفاده کنید.
  3. زیرسیستم مخابراتی به اجرای ConnectionService برنامه شما متصل می شود و نمونه جدیدی از شی Connection را درخواست می کند که نشان دهنده تماس ورودی جدید با استفاده از روش onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest) .
  4. زیرسیستم مخابرات، رابط کاربری تماس ورودی را برای تماس ورودی شما نمایش می دهد.
  5. اگر کاربر تماس را بپذیرد، زیرسیستم مخابراتی متد onAnswer() فراخوانی می کند. شما باید متد setActive() فراخوانی کنید تا به زیرسیستم مخابراتی نشان دهید که تماس اکنون وصل شده است.
  6. اگر کاربر تماس را رد کند، زیرسیستم مخابراتی متد onReject() را فراخوانی می کند. شما باید متد setDisconnected(DisconnectCause) را فراخوانی کنید و REJECTED به عنوان پارامتر و به دنبال آن فراخوانی destroy() struct را مشخص کنید.

تماس های خروجی برقرار کنید

جریان برقراری تماس خروجی شامل رسیدگی به این امکان است که به دلیل محدودیت های تحمیل شده توسط چارچوب مخابراتی امکان برقراری تماس وجود نداشته باشد. برای اطلاعات بیشتر، محدودیت‌های تماس را ببینید.

برای برقراری تماس خروجی، مراحل زیر را دنبال کنید:

  1. کاربر یک تماس خروجی را در برنامه شما آغاز می کند.
  2. از روش placeCall(Uri, Bundle) برای اطلاع رسانی به زیرسیستم مخابراتی در مورد تماس خروجی جدید استفاده کنید. ملاحظات زیر را برای پارامترهای روش در نظر بگیرید:
    • پارامتر Uri نشان دهنده آدرسی است که تماس با آن انجام می شود. برای شماره تلفن های معمولی، از طرح tel: URI استفاده کنید.
    • پارامتر 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 نیست.UI_MODE_TYPE_CAR).

برای پر کردن نقش RoleManager.ROLE_DIALER ، یک برنامه باید تعدادی از شرایط را برآورده کند:

  • باید Intent#ACTION_DIAL مدیریت کند. این بدان معناست که برنامه باید یک رابط کاربری صفحه شماره گیری را برای کاربر فراهم کند تا بتواند تماس های خروجی را آغاز کند.
  • باید InCallService API را به طور کامل پیاده سازی کند و هم یک رابط تماس ورودی و هم یک رابط تماس مداوم ارائه دهد.

توجه: اگر برنامه‌ای که RoleManager.ROLE_DIALER را پر می‌کند، InCallService null را در حین اتصال بازگرداند، چارچوب 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 است. Meta-data TelecomManager#METADATA_IN_CALL_SERVICE_UI نشان می‌دهد که این پیاده‌سازی InCallService خاص قصد دارد تا جایگزین رابط کاربری داخلی در تماس شود. Meta-data 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" علامت گذاری کنید. انجام این کار می تواند منجر به عدم اتصال به پیاده سازی شما در طول تماس شود.

علاوه بر پیاده‌سازی InCallService API، باید فعالیتی را نیز در مانیفست خود اعلام کنید که هدف 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 برای دستگاه های پوشیدنی

    اگر برنامه شما یک برنامه همراه شخص ثالث است و می‌خواهد به InCallService API دسترسی داشته باشد، برنامه شما می‌تواند انجام دهد:

    1. مجوز MANAGE_ONGOING_CALLS را در مانیفست خود اعلام کنید
    2. از طریق CompanionDeviceManager API به عنوان یک برنامه همراه با یک دستگاه پوشیدنی فیزیکی مرتبط شوید. ببینید: https://developer.android.com/guide/topics/connectivity/companion-device-pairing
    3. این InCallService را با مجوز BIND_INCALL_SERVICE اجرا کنید

نمایش اعلان تماس ورودی

هنگامی که برنامه شما یک تماس ورودی جدید از طریق InCallService#onCallAdded(Call) دریافت می کند، مسئول نمایش رابط کاربری تماس ورودی برای تماس ورودی است. باید این کار را با استفاده از API های NotificationManager برای ارسال یک اعلان تماس ورودی جدید انجام دهد.

در جایی که برنامه شما Meta-data 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());
```