Detectar eSIMs e chips
Como detectar cards
Dispositivos Android com chips e eSIMs usam os seguintes IDs nas APIs de telefonia, incluindo ["TelephonyManager"](/reference/android/telephony/TelephonyManager) e ["SubscriptionManager"](/reference/android/telephony/SubscriptionManager): * ID de assinatura: ID exclusivo de uma assinatura móvel. * Índice ou ID de slot lógico: índice exclusivo que se refere a um slot de chip lógico. Os IDs de slot lógicos começam em 0 e aumentam de acordo com o número de slots ativos com suporte em um dispositivo. Por exemplo, um dispositivo com dois chips normalmente tem os slots 0 e 1. Se um dispositivo tiver vários slots físicos, mas aceitar apenas um slot ativo, ele terá apenas o ID de slot lógico 0. * Índice ou ID do slot físico: índice exclusivo que se refere a um slot físico de chip. Os IDs de slot físico começam em 0 e aumentam de acordo com o número de slots físicos no dispositivo. Isso é diferente do número de slots lógicos que um dispositivo tem, que corresponde ao número de slots ativos que um dispositivo pode usar. Por exemplo, um dispositivo que alterna entre os modos dual chip e único chip pode sempre ter dois slots físicos, mas no modo de chip único terá apenas um slot lógico. * ID do cartão: ID exclusivo usado para identificar um UiccCard. ![Um diagrama de como os IDs são usados em um caso com dois slots lógicos e três slots físicos](/images/guide/topics/connectivity/tel-ids.png) No diagrama acima: * O dispositivo tem dois slots lógicos. * No slot físico 0, há um cartão UICC físico com um perfil ativo. * No slot físico 2, há um eUICC com um perfil ativo. * O slot físico 1 não está em uso no momento. ![Um diagrama de como os IDs são usados em um caso com três slots lógicos e dois slots físicos](/images/guide/topics/connectivity/tel-ids-2.png) No diagrama acima: * O dispositivo tem três slots lógicos. * No slot físico 0, há um cartão UICC físico com um perfil ativo. * No slot físico 1, há um eUICC com dois perfis transferidos por download, ambos ativos usando o MEP (Vários perfis ativados).
Visão geral do protocolo de início de sessão
O Android oferece uma API compatível com o Protocolo de início de sessão (SIP, na sigla em inglês). Isso permite que você adicione recursos de telefonia via Internet baseados em SIP aos seus aplicativos. O Android inclui uma pilha completa de protocolos SIP e serviços integrados de gerenciamento de chamadas que permitem que os aplicativos configurem facilmente chamadas de voz realizadas e recebidas, sem precisar gerenciar sessões, comunicação no nível de transporte ou gravação ou reprodução de áudio diretamente.
Veja alguns exemplos dos tipos de aplicativos que podem usar a API SIP:
- Videoconferência
- Mensagem instantânea
Requisitos e limitações
Veja os requisitos para desenvolver um aplicativo com SIP:
- Você precisa ter um dispositivo móvel com o Android 2.3 ou superior.
- O SIP é executado em uma conexão de dados sem fio. Portanto, seu dispositivo precisa ter uma conexão de dados (com um serviço de dados móveis ou Wi-Fi). Isso significa que não é possível testar no AVD. Só é possível testar em um dispositivo físico. Para ver detalhes, consulte Testar aplicativos com SIP.
- Cada participante da sessão de comunicação do aplicativo precisa ter uma conta SIP. Há muitos provedores SIP diferentes que oferecem contas SIP.
Observação:a biblioteca android.net.sip
não é compatível com videochamadas. Se você quiser implementar chamadas VoIP usando uma pilha SIP, como
android.net.sip
, considere uma das diversas alternativas modernas de código aberto
como base para qualquer implementação de chamada VOIP. Como alternativa,
você pode implementar a API
ConnectionService
para fornecer uma integração sólida dessas chamadas no app Telefone do
dispositivo.
Classes e interfaces da API SIP
Veja um resumo das classes e uma interface
(SipRegistrationListener
) incluídas na API SIP
do Android:
Classe/interface | Descrição |
---|---|
SipAudioCall |
Processa uma chamada de áudio de Internet por meio do SIP. |
SipAudioCall.Listener |
Listener para eventos relacionados a uma chamada SIP, como quando uma chamada é recebida ("tocando") ou realizada ("na chamada"). |
SipErrorCode |
Define os códigos de erro retornados durante ações SIP. |
SipManager |
Fornece APIs para tarefas SIP, como iniciar conexões SIP, e fornece acesso a serviços SIP relacionados. |
SipProfile |
Define um perfil SIP, incluindo uma conta SIP, informações de domínio e de servidor. |
SipProfile.Builder |
Classe auxiliar para a criação de um SipProfile. |
SipSession |
Representa uma sessão SIP associada a uma caixa de diálogo do SIP ou uma transação independente que não está em uma caixa de diálogo. |
SipSession.Listener |
Listener para eventos relacionados a uma sessão SIP, como quando uma sessão está sendo registrada ("no registro") ou quando uma chamada é realizada ("na chamada"). |
SipSession.State |
Define os estados de sessões SIP, como "registrando", "chamada realizada" e "em chamada". |
SipRegistrationListener |
Uma interface que é um listener para eventos de registro SIP. |
Criar um manifesto
Se você estiver desenvolvendo um aplicativo que usa a API SIP, lembre-se de que o recurso oferece suporte apenas ao Android 2.3 (nível 9 da API) e versões mais recentes da plataforma. Além disso, nem todos os dispositivos que executam o Android 2.3 (nível 9 da API) ou versões mais recentes oferecem suporte ao SIP.
Para usar o SIP, adicione as seguintes permissões ao manifesto do seu aplicativo:
android.permission.USE_SIP
android.permission.INTERNET
Para garantir que seu aplicativo só possa ser instalado em dispositivos compatíveis com o SIP, adicione o seguinte ao manifesto do aplicativo:
<uses-sdk android:minSdkVersion="9" />
Isso indica que o aplicativo requer o Android 2.3 ou posterior. Para
mais informações, consulte
Níveis de API
e a documentação do elemento
<uses-sdk>
.
Para controlar como o aplicativo é filtrado de dispositivos não compatíveis com SIP (por exemplo, no Google Play), adicione o seguinte ao manifesto do aplicativo:
<uses-feature android:name="android.software.sip.voip" />
Isso declara que seu aplicativo usa a API SIP. A declaração precisa
incluir um atributo android:required
que indica se você
quer que o aplicativo seja filtrado de dispositivos que não oferecem suporte ao SIP.
Outras declarações <uses-feature>
também podem ser necessárias,
dependendo da implementação. Para mais informações, consulte a documentação
do
elemento
<uses-feature>
.
Se o aplicativo for projetado para receber chamadas, também será necessário definir um destinatário (subclasse BroadcastReceiver
) no manifesto do aplicativo:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
Veja trechos do manifesto SipDemo:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.sip"> ... <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" /> ... <uses-sdk android:minSdkVersion="9" /> <uses-permission android:name="android.permission.USE_SIP" /> <uses-permission android:name="android.permission.INTERNET" /> ... <uses-feature android:name="android.software.sip.voip" android:required="true" /> <uses-feature android:name="android.hardware.wifi" android:required="true" /> <uses-feature android:name="android.hardware.microphone" android:required="true" /> </manifest>
Criar o SipManager
Para usar a API SIP, seu aplicativo precisa criar um objeto SipManager
. O SipManager
cuida
do seguinte no seu aplicativo:
- Iniciar sessões SIP.
- Iniciar e receber chamadas.
- Registrar e cancelar o registro com um provedor SIP.
- Verificar a conectividade da sessão.
Instancie um novo SipManager
da seguinte forma:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) }
Java
public SipManager sipManager = null; ... if (sipManager == null) { sipManager = SipManager.newInstance(this); }
Como registrar-se com um servidor SIP
Um aplicativo SIP típico do Android envolve um ou mais usuários, cada um
com uma conta SIP. Em um aplicativo SIP para Android, cada conta SIP é
representada por um objeto SipProfile
.
Um SipProfile
define um perfil SIP, incluindo uma conta
SIP e informações de domínio e servidor. O perfil associado à conta SIP no dispositivo que executa o aplicativo é chamado de perfil
local. O perfil ao qual a sessão é conectada é chamado de
perfil de apps semelhantes. Quando o aplicativo SIP faz login no servidor SIP com
o SipProfile
local, isso registra o
dispositivo como o local para onde enviar chamadas SIP para o endereço SIP.
Esta seção mostra como criar um SipProfile
,
registrá-lo com um servidor SIP e acompanhar eventos de registro.
Crie um objeto SipProfile
da seguinte forma:
Kotlin
private var sipProfile: SipProfile? = null ... val builder = SipProfile.Builder(username, domain) .setPassword(password) sipProfile = builder.build()
Java
public SipProfile sipProfile = null; ... SipProfile.Builder builder = new SipProfile.Builder(username, domain); builder.setPassword(password); sipProfile = builder.build();
O trecho de código a seguir abre o perfil local para fazer chamadas e/ou
receber chamadas SIP genéricas. O autor da chamada pode fazer chamadas subsequentes usando
mSipManager.makeAudioCall
. Esse trecho também define a ação
android.SipDemo.INCOMING_CALL
, que será usada por um filtro de
intent quando o dispositivo receber uma chamada. Consulte Como configurar
um filtro de intent para receber chamadas. Esta é a etapa de registro:
Kotlin
val intent = Intent("android.SipDemo.INCOMING_CALL") val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA) sipManager?.open(sipProfile, pendingIntent, null)
Java
Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); sipManager.open(sipProfile, pendingIntent, null);
Por fim, este código define um SipRegistrationListener
no SipManager
. Isso rastreia se o SipProfile
foi registrado no provedor de serviços
SIP:
Kotlin
sipManager?.setRegistrationListener(sipProfile?.uriString, object : SipRegistrationListener { override fun onRegistering(localProfileUri: String) { updateStatus("Registering with SIP Server...") } override fun onRegistrationDone(localProfileUri: String, expiryTime: Long) { updateStatus("Ready") } override fun onRegistrationFailed( localProfileUri: String, errorCode: Int, errorMessage: String ) { updateStatus("Registration failed. Please check settings.") } })
Java
sipManager.setRegistrationListener(sipProfile.getUriString(), new SipRegistrationListener() { public void onRegistering(String localProfileUri) { updateStatus("Registering with SIP Server..."); } public void onRegistrationDone(String localProfileUri, long expiryTime) { updateStatus("Ready"); } public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) { updateStatus("Registration failed. Please check settings."); } }
Quando o aplicativo terminar de usar um perfil, ele será fechado para liberar objetos associados na memória e cancelar o registro do dispositivo no servidor. Por exemplo:
Kotlin
fun closeLocalProfile() { try { sipManager?.close(sipProfile?.uriString) } catch (ee: Exception) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee) } }
Java
public void closeLocalProfile() { if (sipManager == null) { return; } try { if (sipProfile != null) { sipManager.close(sipProfile.getUriString()); } } catch (Exception ee) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee); } }
Fazer uma chamada de áudio
Para fazer uma chamada de áudio, é preciso ter o seguinte:
- Um
SipProfile
que esteja fazendo a chamada (o "perfil local") e um endereço SIP válido para receber a chamada (o "perfil de peering"). - Um objeto
SipManager
.
Para fazer uma chamada de áudio, configure um SipAudioCall.Listener
. Grande parte da interação do cliente com
a pilha do SIP acontece por meio de listeners. Neste snippet, você pode conferir como o SipAudioCall.Listener
faz as configurações depois que a chamada é
estabelecida:
Kotlin
var listener: SipAudioCall.Listener = object : SipAudioCall.Listener() { override fun onCallEstablished(call: SipAudioCall) { call.apply { startAudio() setSpeakerMode(true) toggleMute() } } override fun onCallEnded(call: SipAudioCall) { // Do something. } }
Java
SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onCallEstablished(SipAudioCall call) { call.startAudio(); call.setSpeakerMode(true); call.toggleMute(); ... } @Override public void onCallEnded(SipAudioCall call) { // Do something. } };
Depois de configurar o SipAudioCall.Listener
, é possível
fazer a chamada. O método makeAudioCall
do SipManager
usa estes parâmetros:
- Um perfil SIP local (o autor da chamada).
- Um perfil SIP semelhante (o usuário que recebe a chamada).
- Um
SipAudioCall.Listener
para detectar os eventos de chamada deSipAudioCall
. Pode sernull
, mas, como mostrado acima, o listener é usado para definir as configurações depois que a chamada é estabelecida. - O valor de tempo limite, em segundos.
Por exemplo:
Kotlin
val call: SipAudioCall? = sipManager?.makeAudioCall( sipProfile?.uriString, sipAddress, listener, 30 )
Java
call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);
Receber chamadas
Para receber chamadas, um aplicativo SIP precisa incluir uma subclasse de BroadcastReceiver
, que possa responder a uma intent
indicando que há uma chamada recebida. Portanto, faça o seguinte no seu aplicativo:
- Em
AndroidManifest.xml
, declare um<receiver>
. Em SipDemo, isso é<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
. - Implemente o destinatário, que é uma subclasse de
BroadcastReceiver
. Em SipDemo, isso éIncomingCallReceiver
. - Inicialize o perfil local (
SipProfile
) com uma intent pendente que dispara seu receptor quando alguém liga para o perfil local. - Configure um filtro de intent que filtre pela ação que representa uma
chamada recebida. Em SipDemo, essa ação é
android.SipDemo.INCOMING_CALL
.
Criar uma subclasse de BroadcastReceiver
Para receber chamadas, seu aplicativo SIP precisa ter a subclasse BroadcastReceiver
. O
sistema Android processa chamadas SIP recebidas e transmite uma intent
de "chamada recebida" (conforme definido pelo aplicativo) quando recebe
uma chamada. Veja o código
BroadcastReceiver
com subclasses do exemplo SipDemo.
Kotlin
/** * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. */ class IncomingCallReceiver : BroadcastReceiver() { /** * Processes the incoming call, answers it, and hands it over to the * WalkieTalkieActivity. * @param context The context under which the receiver is running. * @param intent The intent being received. */ override fun onReceive(context: Context, intent: Intent) { val wtActivity = context as WalkieTalkieActivity var incomingCall: SipAudioCall? = null try { incomingCall = wtActivity.sipManager?.takeAudioCall(intent, listener) incomingCall?.apply { answerCall(30) startAudio() setSpeakerMode(true) if (isMuted) { toggleMute() } wtActivity.call = this wtActivity.updateStatus(this) } } catch (e: Exception) { incomingCall?.close() } } private val listener = object : SipAudioCall.Listener() { override fun onRinging(call: SipAudioCall, caller: SipProfile) { try { call.answerCall(30) } catch (e: Exception) { e.printStackTrace() } } } }
Java
/** * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. */ public class IncomingCallReceiver extends BroadcastReceiver { /** * Processes the incoming call, answers it, and hands it over to the * WalkieTalkieActivity. * @param context The context under which the receiver is running. * @param intent The intent being received. */ @Override public void onReceive(Context context, Intent intent) { SipAudioCall incomingCall = null; try { SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onRinging(SipAudioCall call, SipProfile caller) { try { call.answerCall(30); } catch (Exception e) { e.printStackTrace(); } } }; WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context; incomingCall = wtActivity.sipManager.takeAudioCall(intent, listener); incomingCall.answerCall(30); incomingCall.startAudio(); incomingCall.setSpeakerMode(true); if(incomingCall.isMuted()) { incomingCall.toggleMute(); } wtActivity.call = incomingCall; wtActivity.updateStatus(incomingCall); } catch (Exception e) { if (incomingCall != null) { incomingCall.close(); } } } }
Como configurar um filtro de intent para receber chamadas
Quando o serviço SIP recebe uma nova chamada, ele envia uma intent com a
string de ação fornecida pelo aplicativo. No SipDemo, essa string de ação é
android.SipDemo.INCOMING_CALL
.
Este trecho de código de SipDemo mostra como o objeto SipProfile
é criado com uma intent pendente baseada na string de ação android.SipDemo.INCOMING_CALL
. O
objeto PendingIntent
realizará uma transmissão quando o SipProfile
receber uma chamada:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) } var sipProfile: SipProfile? = null ... val intent = Intent("android.SipDemo.INCOMING_CALL") val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA) sipManager?.open (sipProfile, pendingIntent, null)
Java
public SipManager sipManager = null; public SipProfile sipProfile = null; ... Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); sipManager.open(sipProfile, pendingIntent, null);
A transmissão será interceptada pelo filtro de intent, que acionará
o receptor (IncomingCallReceiver
). É possível especificar um filtro de
intent no arquivo de manifesto do app ou fazer isso no código, como no método
onCreate()
do aplicativo de exemplo
SipDemo do Activity
:
Kotlin
class WalkieTalkieActivity : Activity(), View.OnTouchListener { ... lateinit var callReceiver: IncomingCallReceiver ... override fun onCreate(savedInstanceState: Bundle) { val filter = IntentFilter().apply { addAction("android.SipDemo.INCOMING_CALL") } callReceiver = IncomingCallReceiver() this.registerReceiver(callReceiver, filter) ... } ... }
Java
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener { ... public IncomingCallReceiver callReceiver; ... @Override public void onCreate(Bundle savedInstanceState) { IntentFilter filter = new IntentFilter(); filter.addAction("android.SipDemo.INCOMING_CALL"); callReceiver = new IncomingCallReceiver(); this.registerReceiver(callReceiver, filter); ... } ... }
Testar aplicativos SIP
Para testar aplicativos SIP, você precisa do seguinte:
- Um dispositivo móvel com o Android 2.3 ou versões posteriores. O SIP é executado por Wi-Fi, portanto, você precisa testar em um dispositivo real. Não é possível realizar os testes no AVD.
- Uma conta SIP. Há muitos provedores SIP diferentes que oferecem contas SIP.
- Se você estiver fazendo uma chamada, ela também precisa ser para uma conta SIP válida.
Para testar um aplicativo SIP:
- No dispositivo, conecte-se a uma rede sem fio (Configurações > Redes sem fio e outras > Wi-Fi > Configurações de Wi-Fi).
- Configure seu dispositivo móvel para testes, conforme descrito em Executar apps em um dispositivo de hardware.
- Execute seu aplicativo no dispositivo móvel, conforme descrito em Executar apps em um dispositivo de hardware.
- Se você está usando o Android Studio, é possível conferir a saída do registro do aplicativo abrindo o console do log de eventos (View > Tool Windows > Event Log).
- Verifique se o aplicativo está configurado para iniciar o Logcat automaticamente quando ele for executado:
- Selecione Run > Edit Configurations.
- Selecione a guia Miscellaneous na janela Run/Debug Configurations.
- Em Logcat, selecione Show logcat automatically e, em seguida, OK.