Un'app per chiamate consente agli utenti di ricevere o effettuare chiamate audio o videochiamate sul proprio dispositivo. Le app per le chiamate utilizzano la propria interfaccia utente per le chiamate anziché l'interfaccia predefinita dell'app Telefono, come mostrato nello screenshot seguente.
Il framework Android include il pacchetto android.telecom
, che
contiene classi che consentono di creare un'app per le chiamate in base al framework
di telecomunicazione. La creazione di un'app in base al framework delle telecomunicazioni offre i seguenti vantaggi:
- La tua app interagisce correttamente con il sottosistema di telecomunicazione nativo nel dispositivo.
- L'app interagisce correttamente con altre app di chiamata conformi al framework.
- Il framework aiuta la tua app a gestire il routing audio e video.
- Il framework aiuta la tua app a determinare se le sue chiamate sono mirate.
Dichiarazioni e autorizzazioni del file manifest
Nel file manifest dell'app, dichiara che la tua app utilizza l'autorizzazione MANAGE_OWN_CALLS
, come mostrato nell'esempio seguente:
<manifest … >
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
</manifest>
Per ulteriori informazioni sulla dichiarazione delle autorizzazioni app, consulta Autorizzazioni.
Devi dichiarare un servizio che specifica la classe che implementa la classe ConnectionService
nella tua app. Il sottosistema di telecomunicazione richiede che il servizio dichiari l'autorizzazione BIND_TELECOM_CONNECTION_SERVICE
da poter associare al servizio. L'esempio seguente mostra come dichiarare il servizio nel file manifest dell'app:
<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>
Per ulteriori informazioni sulla dichiarazione dei componenti dell'app, inclusi i servizi, consulta Componenti dell'app.
Implementare il servizio di connessione
L'app per le chiamate deve fornire un'implementazione della classe ConnectionService
a cui può essere associato il sottosistema di telecomunicazioni.
L'implementazione di ConnectionService
dovrebbe sostituire
i seguenti metodi:
onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
Il sottosistema di telecomunicazioni chiama questo metodo in risposta alla tua app che chiama
placeCall(Uri, Bundle)
per creare una nuova chiamata in uscita. La tua app restituisce una nuova istanza dell'implementazione della classeConnection
(per ulteriori informazioni, vedi Implementare la connessione) per rappresentare la nuova chiamata in uscita. Puoi personalizzare ulteriormente la connessione in uscita eseguendo le seguenti azioni:- L'app deve chiamare il metodo
setConnectionProperties(int)
con la costantePROPERTY_SELF_MANAGED
come argomento per indicare che la connessione ha avuto origine da un'app chiamante. - Se la tua app supporta la messa in attesa delle chiamate, chiama il metodo
setConnectionCapabilities(int)
e imposta l'argomento sul valore della maschera di bit delle costantiCAPABILITY_HOLD
eCAPABILITY_SUPPORT_HOLD
. - Per impostare il nome del chiamante, utilizza il metodo
setCallerDisplayName(String, int)
che passa la costantePRESENTATION_ALLOWED
come parametroint
per indicare che deve essere mostrato il nome del chiamante. - Per assicurarti che la chiamata in uscita abbia lo stato video appropriato, chiama il metodo
setVideoState(int)
dell'oggettoConnection
e invia il valore restituito dal metodogetVideoState()
dell'oggettoConnectionRequest
.
- L'app deve chiamare il metodo
onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)
Il sottosistema di telecomunicazioni chiama questo metodo quando la tua app chiama il metodo
placeCall(Uri, Bundle)
e la chiamata in uscita non può essere effettuata. In risposta a questa situazione, l'app deve informare l'utente (ad esempio, utilizzando una casella di avviso o un avviso popup) che non è stato possibile effettuare la chiamata in uscita. La tua app potrebbe non riuscire a effettuare una chiamata se è in corso una chiamata di emergenza o se è in corso una chiamata in un'altra app che non può essere messa in attesa prima di effettuare la chiamata.onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)
Il sottosistema delle telecomunicazioni chiama questo metodo quando l'app chiama il metodo
addNewIncomingCall(PhoneAccountHandle, Bundle)
per informare il sistema di una nuova chiamata in arrivo nell'app. L'app restituisce una nuova istanza della tua implementazioneConnection
(per ulteriori informazioni, consulta Implementare la connessione) per rappresentare la nuova chiamata in arrivo. Puoi personalizzare ulteriormente la connessione in entrata eseguendo le seguenti azioni:- L'app deve chiamare il metodo
setConnectionProperties(int)
con la costantePROPERTY_SELF_MANAGED
come argomento per indicare che la connessione ha avuto origine da un'app chiamante. - Se la tua app supporta la messa in attesa delle chiamate, chiama il metodo
setConnectionCapabilities(int)
e imposta l'argomento sul valore della maschera di bit delle costantiCAPABILITY_HOLD
eCAPABILITY_SUPPORT_HOLD
. - Per impostare il nome del chiamante, utilizza il metodo
setCallerDisplayName(String, int)
che passa la costantePRESENTATION_ALLOWED
come parametroint
per indicare che deve essere mostrato il nome del chiamante. - Per specificare il numero di telefono o l'indirizzo della chiamata in arrivo, utilizza il
metodo
setAddress(Uri, int)
dell'oggettoConnection
. - Per assicurarti che la chiamata in uscita abbia lo stato video appropriato, chiama il metodo
setVideoState(int)
dell'oggettoConnection
e invia il valore restituito dal metodogetVideoState()
dell'oggettoConnectionRequest
.
- L'app deve chiamare il metodo
onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)
Il sottosistema delle telecomunicazioni chiama questo metodo quando l'app chiama il metodo
addNewIncomingCall(PhoneAccountHandle, Bundle)
per informare Telecom di una nuova chiamata in arrivo, ma la chiamata in arrivo non è consentita. Per saperne di più, consulta la sezione sui limiti relativi alle chiamate. L'app dovrebbe rifiutare in silenzio la chiamata in arrivo, facoltativamente pubblicando una notifica per informare l'utente della chiamata persa.
Implementa la connessione
La tua app deve creare una sottoclasse di Connection
per rappresentare le chiamate nell'app. Devi eseguire l'override dei seguenti metodi nell'implementazione:
onShowIncomingCallUi()
Il sottosistema delle telecomunicazioni chiama questo metodo quando aggiungi una nuova chiamata in arrivo e la tua app dovrebbe mostrare la relativa UI.
onCallAudioStateChanged(CallAudioState)
Il sottosistema delle telecomunicazioni chiama questo metodo per informare la tua app che il percorso o la modalità audio corrente è cambiato. Questo comando viene chiamato in risposta alla modifica della modalità audio da parte dell'app usando il metodo
setAudioRoute(int)
. Questo metodo può essere richiamato anche se il sistema cambia la route audio (ad esempio, quando si disconnettono le cuffie Bluetooth).onHold()
Il sottosistema delle telecomunicazioni chiama questo metodo quando vuole mettere una chiamata in attesa. In risposta a questa richiesta, la tua app deve sospendere la chiamata e poi richiamare il metodo
setOnHold()
per informare il sistema che la chiamata è in attesa. Il sottosistema delle telecomunicazioni potrebbe chiamare questo metodo quando un servizio in chiamata, come Android Auto, che mostra che la tua chiamata vuole rimandare la richiesta di un utente di mettere la chiamata in attesa. Il sottosistema delle telecomunicazioni chiama questo metodo anche se l'utente effettua una chiamata in un'altra app. Per ulteriori informazioni sui servizi disponibili, vediInCallService
.onUnhold()
Il sottosistema delle telecomunicazioni chiama questo metodo quando vuole riprendere una chiamata messa in attesa. Una volta che l'app ha ripreso la chiamata, dovrebbe richiamare il metodo
setActive()
per comunicare al sistema che la chiamata non è più in attesa. Il sottosistema di telecomunicazioni potrebbe chiamare questo metodo quando un servizio in chiamata, come Android Auto, che mostra che la tua chiamata vuole inoltrare una richiesta per riprendere la chiamata. Per ulteriori informazioni sui servizi disponibili nelle chiamate, vediInCallService
.onAnswer()
Il sottosistema di telecomunicazioni chiama questo metodo per informare l'app che una chiamata in arrivo deve ricevere una risposta. Dopo aver risposto alla chiamata, l'app dovrebbe richiamare il metodo
setActive()
per informare il sistema che la chiamata ha ricevuto una risposta. Il sottosistema delle telecomunicazioni potrebbe chiamare questo metodo quando la tua app aggiunge una nuova chiamata in arrivo ed è già in corso una chiamata in corso in un'altra app che non può essere messa in attesa. Il sottosistema delle telecomunicazioni mostra l'UI delle chiamate in arrivo per conto della tua app in queste istanze. Il framework fornisce un metodo di sovraccarico che fornisce supporto per specificare lo stato del video in cui rispondere alla chiamata. Per ulteriori informazioni, consulta la paginaonAnswer(int)
.onReject()
Il sottosistema di telecomunicazioni chiama questo metodo quando vuole rifiutare una chiamata in arrivo. Una volta che l'app ha rifiutato la chiamata, deve chiamare
setDisconnected(DisconnectCause)
e specificareREJECTED
come parametro. L'app deve quindi chiamare il metododestroy()
per informare il sistema che l'app ha elaborato la chiamata. Il sottosistema di telecomunicazioni chiama questo metodo quando l'utente ha rifiutato una chiamata in arrivo dalla tua app.onDisconnect()
Il sottosistema delle telecomunicazioni chiama questo metodo quando vuole disconnettere una chiamata. Al termine della chiamata, l'app deve chiamare il metodo
setDisconnected(DisconnectCause)
e specificareLOCAL
come parametro per indicare che una richiesta dell'utente ha causato la disconnessione della chiamata. L'app deve quindi chiamare il metododestroy()
per informare il sottosistema di telecomunicazioni che ha elaborato la chiamata. Il sistema può chiamare questo metodo quando l'utente ha disconnesso una chiamata attraverso un altro servizio disponibile, come Android Auto. Il sistema chiama questo metodo anche quando la chiamata deve essere disconnessa per consentire l'esecuzione di altre chiamate, ad esempio se l'utente vuole effettuare una chiamata di emergenza. Per ulteriori informazioni sui servizi disponibili nelle chiamate, vediInCallService
.
Gestire scenari di chiamata comuni
L'utilizzo dell'API ConnectionService
nel flusso di chiamata comporta l'interazione con le altre classi nel pacchetto android.telecom
. Le seguenti sezioni descrivono gli scenari più comuni relativi alle chiamate e
come l'app deve utilizzare le API per gestirli.
Risposta alle chiamate in arrivo
Il flusso per gestire le chiamate in arrivo cambia se ci sono o meno chiamate in altre app. Il motivo della differenza nei flussi è che il framework per le telecomunicazioni deve stabilire alcuni vincoli quando ci sono chiamate attive in altre app per garantire un ambiente stabile per tutte le app per le chiamate sul dispositivo. Per ulteriori informazioni, consulta la sezione Vincoli per le chiamate.
Nessuna chiamata attiva in altre app
Per rispondere alle chiamate in arrivo quando non ci sono chiamate attive in altre app, procedi nel seguente modo:
- L'app riceve una nuova chiamata in arrivo usando i meccanismi abituali.
- Utilizza il metodo
addNewIncomingCall(PhoneAccountHandle, Bundle)
per informare il sottosistema di telecomunicazioni della nuova chiamata in arrivo. - Il sottosistema di telecomunicazioni si associa all'implementazione
ConnectionService
dell'app e richiede una nuova istanza della classeConnection
che rappresenti la nuova chiamata in entrata utilizzando il metodoonCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)
. - Il sottosistema delle telecomunicazioni informa la tua app che deve mostrare l'interfaccia utente delle chiamate in arrivo utilizzando il metodo
onShowIncomingCallUi()
. - La tua app mostra la UI in arrivo utilizzando una notifica con un intent a schermo intero associato. Per ulteriori informazioni, vedi
onShowIncomingCallUi()
. - Richiama il metodo
setActive()
se l'utente accetta la chiamata in arrivo oppuresetDisconnected(DisconnectCause)
specificandoREJECTED
come parametro seguito da una chiamata al metododestroy()
se l'utente rifiuta la chiamata in arrivo.
Chiamate attive in altre app che non possono essere messe in attesa
Per rispondere alle chiamate in arrivo quando ci sono chiamate attive in altre app che non è possibile mettere in attesa, procedi nel seguente modo:
- L'app riceve una nuova chiamata in arrivo usando i meccanismi abituali.
- Utilizza il metodo
addNewIncomingCall(PhoneAccountHandle, Bundle)
per informare il sottosistema di telecomunicazioni della nuova chiamata in arrivo. - Il sottosistema di telecomunicazione si associa all'implementazione
ConnectionService
dell'app e richiede una nuova istanza dell'oggettoConnection
che rappresenti la nuova chiamata in arrivo utilizzando il metodoonCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)
. - Il sottosistema delle telecomunicazioni visualizza l'UI delle chiamate in arrivo per la chiamata in arrivo.
- Se l'utente accetta la chiamata, il sottosistema di telecomunicazione chiama il metodo
onAnswer()
. Dovresti chiamare il metodosetActive()
per indicare al sottosistema di telecomunicazioni che la chiamata è ora connessa. - Se l'utente rifiuta la chiamata, il sottosistema di telecomunicazione chiama il metodo
onReject()
. Devi chiamare il metodosetDisconnected(DisconnectCause)
specificandoREJECTED
come parametro seguito da una chiamata al metododestroy()
.
Effettua chiamate in uscita
Il flusso per effettuare una chiamata in uscita comporta la gestione della possibilità che la chiamata non possa essere effettuata a causa dei vincoli imposti dal framework di telecomunicazione. Per ulteriori informazioni, consulta la sezione Vincoli relativi alle chiamate.
Per effettuare una chiamata in uscita, procedi nel seguente modo:
- L'utente avvia una chiamata in uscita all'interno dell'app.
- Utilizza il metodo
placeCall(Uri, Bundle)
per informare il sottosistema delle telecomunicazioni della nuova chiamata in uscita. Prendi in considerazione le seguenti considerazioni per i parametri del metodo:- Il parametro
Uri
rappresenta l'indirizzo in cui viene effettuata la chiamata. Per i numeri di telefono normali, utilizza lo schema URItel:
. - Il parametro
Bundle
ti consente di fornire informazioni sulla tua app per le chiamate aggiungendo l'oggettoPhoneAccountHandle
dell'app al extraEXTRA_PHONE_ACCOUNT_HANDLE
. La tua app deve fornire l'oggettoPhoneAccountHandle
a ogni chiamata in uscita. - Il parametro
Bundle
ti consente inoltre di specificare se la chiamata in uscita include video specificando il valoreSTATE_BIDIRECTIONAL
nel campoEXTRA_START_CALL_WITH_VIDEO_STATE
aggiuntivo. Tieni presente che, per impostazione predefinita, il sottosistema delle telecomunicazioni indirizza le videochiamate al telefono vivavoce.
- Il parametro
- Il sottosistema di telecomunicazioni si associa all'implementazione
ConnectionService
della tua app. - Se la tua app non è in grado di effettuare una chiamata in uscita, il sottosistema di telecomunicazione chiama il metodo
onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)
per informare l'app che al momento non è possibile effettuare la chiamata. L'app deve comunicare all'utente che non è possibile effettuare la chiamata. - Se la tua app è in grado di effettuare la chiamata in uscita, il sottosistema di telecomunicazioni chiama
il
metodo
onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
. L'app deve restituire un'istanza della classeConnection
per rappresentare la nuova chiamata in uscita. Per ulteriori informazioni sulle proprietà da impostare per la connessione, consulta Implementare il servizio di connessione. - Una volta connessa la chiamata in uscita, chiama il metodo
setActive()
per comunicare al sottosistema di telecomunicazioni che la chiamata è attiva.
Terminare una chiamata
Per terminare una chiamata:
- Richiama
setDisconnected(DisconnectCause)
che inviaLOCAL
come parametro se l'utente ha terminato la chiamata oppure inviaREMOTE
come parametro se l'altra parte ha terminato la chiamata. - Chiama il metodo
destroy()
.
Vincoli per le chiamate
Per garantire agli utenti un'esperienza di chiamata semplice e coerente, il framework di telecomunicazione applica alcuni vincoli per la gestione delle chiamate sul dispositivo. Ad esempio, considera che l'utente abbia installato due app di chiamata che implementano l'API ConnectionService
autogestita, FooTalk e BarTalk. In questo caso, si applicano i seguenti vincoli:
Sui dispositivi con livello API 27 o precedente, solo un'app può mantenere una chiamata in corso in un determinato momento. Questo vincolo significa che, mentre un utente ha una chiamata in corso che utilizza l'app FooTalk, l'app BarTalk non può avviare o ricevere una nuova chiamata.
Sui dispositivi con livello API 28 o successivo, se FooTalk e BarTalk dichiarano
CAPABILITY_SUPPORT_HOLD
e autorizzazioniCAPABILITY_HOLD
, l'utente può mantenere più di una chiamata in corso passando da un'app all'altra per avviare o rispondere a un'altra chiamata.Se l'utente è impegnato in chiamate gestite regolari (ad esempio, utilizzando l'app Telefono o Telefono integrata), l'utente non può partecipare a chiamate provenienti da app di chiamata. Ciò significa che se l'utente sta partecipando a una normale chiamata utilizzando il proprio operatore di telefonia mobile, non può partecipare contemporaneamente a una chiamata FooTalk o BarTalk.
Il sottosistema di telecomunicazioni disconnette le chiamate della tua app se l'utente compone una chiamata di emergenza.
L'app non può ricevere o effettuare chiamate mentre l'utente si trova in una chiamata di emergenza.
Se c'è una chiamata in corso in un'altra app per chiamate quando la tua app riceve una chiamata in arrivo, rispondendo alla chiamata in arrivo vengono terminate tutte le chiamate in corso nell'altra app. L'app non deve mostrare la normale interfaccia utente delle chiamate in arrivo. Il framework di telecomunicazione mostra l'interfaccia utente delle chiamate in arrivo e informa l'utente che, rispondendo alla nuova chiamata, le chiamate in corso verranno terminate. Ciò significa che se l'utente sta partecipando a una chiamata FooTalk e l'app BarTalk riceve una chiamata in arrivo, il framework di telecomunicazione informa l'utente che ha una nuova chiamata BarTalk in arrivo e che rispondendo alla chiamata BarTalk terminerà la chiamata FooTalk.