Networking e telefonia

Le funzionalità di questa guida descrivono le funzionalità di gestione della rete e della telefonia che puoi implementare nella tua app controller dei criteri dei dispositivi (DPC). Questo documento contiene esempi di codice. Puoi anche utilizzare l'app DPC di test come sorgente di codice di esempio per le funzionalità aziendali di Android.

Un'app DPC può essere eseguita in modalità Proprietario del profilo su dispositivi personali o in modalità Proprietario del dispositivo su dispositivi completamente gestiti. Questa tabella indica le funzionalità disponibili quando il DPC viene eseguito in modalità proprietario profilo o proprietario dispositivo:

Funzionalità Proprietario del profilo Proprietario del dispositivo
Accedi ai contatti di lavoro su tutti i profili
Assicurati una connessione di rete sicura per il traffico di lavoro
Configura un singolo ID di rete wireless in più regioni
Specifica una tastiera separata per il profilo di lavoro

Accedi ai contatti di lavoro su tutti i profili

I provider EMM possono consentire al profilo personale di un utente di accedere ai suoi contatti di lavoro in modo che i contatti personali e di lavoro dell'utente siano accessibili tramite la ricerca locale e la ricerca nella directory remota. Sui dispositivi personali, un'unica tastiera nel profilo personale può effettuare e ricevere chiamate personali e di lavoro. Inoltre, i contatti di lavoro sono ben integrati nell'interfaccia utente del sistema. Se il profilo di lavoro è criptato, i relativi dati non sono disponibili per il profilo personale.

Integrazione con l'interfaccia utente di sistema

L'interfaccia utente di sistema indica le chiamate di lavoro in arrivo tramite l'icona di una valigetta. L'icona callLog mostra anche l'icona per indicare le chiamate di lavoro in arrivo e in uscita. Le app tastiera personale e contatti possono visualizzare le informazioni sull'ID chiamante di un contatto di lavoro utilizzando una ricerca della directory remota, quindi non è necessario che il contatto sia già sincronizzato sul dispositivo locale. L'app di messaggistica può eseguire ricerche e ID chiamante locali.

Il Documento di definizione di compatibilità Android (CDD) include requisiti per la visualizzazione dei contatti di lavoro nella tastiera predefinita, nonché requisiti per cui i contatti e le app di messaggistica sono badge per indicare che provengono dal profilo di lavoro.

I contatti di lavoro sono accessibili e disponibili per la ricerca

L'utente può accedere e chiamare i contatti di lavoro dal proprio profilo personale, che viene visualizzato nella schermata di ricerca dell'app Telefono. L'utente può cercare contatti di lavoro, utilizzando il completamento automatico, sincronizzati localmente con il dispositivo e elencati tramite una ricerca nella directory remota.

Controlla i contatti di lavoro nel profilo principale

Il DPC controlla l'autorizzazione per cercare i contatti di lavoro. Funzionando in modalità proprietario del profilo, il DPC gestisce la visibilità dei contatti di lavoro nel profilo personale. Per maggiori informazioni, consulta Creare un controller dei criteri dei dispositivi.

La ricerca dei contatti di lavoro in base al profilo personale è abilitata per impostazione predefinita.

Assicurati una connessione di rete sicura per il traffico di lavoro

Se viene eseguito in modalità Proprietario del dispositivo o Proprietario del profilo, un controller dei criteri dei dispositivi può utilizzare una connessione di rete privata virtuale (VPN) sempre attiva per forzare le applicazioni a passare il traffico attraverso un'app VPN specifica che non può essere ignorata. Utilizzando una connessione VPN sempre attiva, il DPC può garantire che il traffico di rete da un profilo di lavoro o da un dispositivo gestito passi attraverso un servizio VPN, senza l'intervento dell'utente. Questo processo crea una connessione di rete sicura per il traffico continuo all'interno di un profilo di lavoro.

Informazioni sulle connessioni VPN sempre attive

Come parte del framework di sistema, il routing della VPN viene gestito automaticamente in modo che l'utente non possa bypassare il servizio VPN. Se il servizio VPN viene disconnesso in modalità di blocco, il traffico non può infiltrarsi nella rete internet aperta. Per le applicazioni che implementano VpnService, la VPN sempre attiva fornisce un framework per la gestione e il mantenimento di una connessione VPN sicura tramite un server affidabile. Il servizio VPN riavvia automaticamente la connessione tra gli aggiornamenti dell'app, indipendentemente dal fatto che la connessione sia tramite Wi-Fi o cellulare. Se il dispositivo si riavvia, il framework riavvia la connessione VPN.

La connessione al servizio VPN è trasparente per l'utente. Per un dispositivo di proprietà dell'azienda, l'utente non è tenuto a confermare una finestra di dialogo per il consenso per una VPN in modalità sempre attiva. Le impostazioni di rete VPN dell'utente consentono di attivare manualmente una connessione sempre attiva.

Se DISALLOW_CONFIG_VPN è true, all'utente non è consentito configurare la VPN. Abilita DISALLOW_DEBUGGING_FEATURES per impedire agli utenti di eseguire l'override della VPN sempre attiva utilizzando il comando di debug adb. Per impedire a un utente di disinstallare la VPN, chiama DevicePolicyManager.setUninstallBlocked.

Configurare il servizio VPN

L'organizzazione che utilizza la tua soluzione aziendale per Android configura la VPN.

  1. Installa un'app VPN che implementi VpnService. Puoi trovare i servizi VPN attivi utilizzando un filtro per intent che corrisponde all'azione VpnService.SERVICE_INTERFACE.
  2. Dichiara un VpnService nel file manifest dell'app protetto dall'autorizzazione BIND_VPN_SERVICE.
  3. Configura la VpnService in modo che venga avviata dal sistema. Evita di impostare l'app VPN in modo che si avvii da sola ascoltando l'avvio di un sistema e controllando il proprio ciclo di vita.
  4. Imposta le configurazioni gestite per l'app VPN (vedi esempio di seguito).

Abilita la connessione VPN sempre attiva

Il DPC può configurare una connessione VPN sempre attiva tramite un'app specifica chiamando DevicePolicyManager.setAlwaysOnVpnPackage().

Questa connessione viene concessa automaticamente e persiste dopo il riavvio. Se lockdownEnabled è impostato su false, il traffico di rete potrebbe non essere protetto dal momento in cui il telefono viene riavviato e la VPN si connette. Ciò è utile se non vuoi interrompere la connettività di rete ogni volta che la VPN non funziona o se la VPN non è essenziale.

Verificare la connessione VPN sempre attiva

Il DPC può leggere il nome del pacchetto amministrando una connessione VPN sempre attiva per l'utente corrente con DevicePolicyManager.getAlwaysOnVpnPackage().

Se questo pacchetto non è presente o se la VPN è stata creata nell'app Impostazioni di sistema, viene restituito null.

Esempio

Nell'app TestDPC, AlwaysOnVpnFragment.java utilizza queste API per abilitare l'impostazione di una connessione VPN sempre attiva.

Nel seguente esempio:

  • Le configurazioni gestite del servizio VPN vengono impostate dal DevicePolicyManager utilizzando il suo metodo setApplicationRestrictions().
  • Le configurazioni gestite utilizzano coppie chiave-valore arbitrarie e questa app di esempio le utilizza altrove per configurare le impostazioni di rete della VPN (consulta la sezione Controllare le configurazioni gestite).
  • Nell'esempio il programma di installazione di pacchetti Android viene aggiunto a una lista bloccata in modo che i pacchetti di sistema non vengano aggiornati tramite la VPN. Tutto il traffico di rete dell'utente all'interno del profilo di lavoro o del dispositivo passa attraverso questa app VPN, ad eccezione del programma di installazione del pacchetto, e i relativi aggiornamenti utilizzano la rete internet aperta.
  • DevicePolicyManager abilita quindi la connessione VPN sempre attiva per il pacchetto VPN utilizzando setAlwaysOnVpnPackage() e abilitando la modalità di blocco.

Kotlin

// Set VPN's managed configurations
val config = Bundle().apply {
  putString(Extras.VpnApp.ADDRESS, "192.0.2.0")
  putString(Extras.VpnApp.IDENTITY, "vpn.account1")
  putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate")
  putStringArray(Extras.VpnApp.DENYLIST,
        arrayOf("com.android.packageinstaller"))
}

val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager

val admin = myDeviceAdminReceiver.getComponentName(this)

// Name of package to update managed configurations
val vpnPackageName = "com.example.vpnservice"

// Associate managed configurations with DeviceAdminReceiver
dpm.setApplicationRestrictions(admin, vpnPackageName, config)

// Enable always-on VPN connection through VPN package
try {
  val lockdownEnabled = true
  dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled)
} catch (ex: Exception) {
  throw PolicyException()
}

Java

// Set VPN's managed configurations
final Bundle config = new Bundle();
config.putString(Extras.VpnApp.ADDRESS, "192.0.2.0");
config.putString(Extras.VpnApp.IDENTITY, "vpn.account1");
config.putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate");
config.putStringArray(Extras.VpnApp.DENYLIST,
                      new String[]{"com.android.packageinstaller"});

DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

ComponentName admin = myDeviceAdminReceiver.getComponentName(this);

// Name of package to update managed configurations
final String vpnPackageName = "com.example.vpnservice";

// Associate managed configurations with DeviceAdminReceiver
dpm.setApplicationRestrictions(admin, vpnPackageName, config);

// Enable always-on VPN connection through VPN package
try {
  boolean lockdownEnabled = true;
  dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled));
} catch (Exception ex) {
  throw new PolicyException(...);
}

Configurazione di un singolo ID di rete wireless per più regioni

Se viene eseguito in modalità Proprietario del dispositivo o Proprietario del profilo, un controller dei criteri dei dispositivi (DPC) può associare più certificati dell'autorità di certificazione (CA) a un'unica configurazione di rete wireless. Con questa configurazione, un dispositivo può connettersi a punti di accesso wireless che hanno lo stesso nome di rete o lo stesso SSID (Service Set Identifier), ma sono configurati con certificati CA diversi. Ciò è utile se le reti wireless della tua organizzazione si trovano in più regioni geografiche e ogni regione richiede un'autorità di certificazione diversa. Ad esempio, per le firme legali può essere necessaria un'autorità locale che necessita di una CA regionale.

Nota: Android supporta setCaCertificate dall'API 18 (Jelly Bean), ma gli amministratori IT devono eseguire il provisioning delle reti separatamente con ogni CA per garantire che i dispositivi abbiano un'autenticazione perfetta in ogni punto di accesso, indipendentemente dalla regione.

Specifica i certificati CA per identificare il server

Per specificare un elenco di certificati X.509 che identificano il server utilizzando lo stesso SSID, includi tutte le CA pertinenti nella configurazione wireless utilizzando WifiEnterpriseConfig.setCaCertificates().

Il certificato di un server è valido se la relativa CA corrisponde a uno dei certificati forniti. I nomi predefiniti vengono assegnati automaticamente ai certificati e utilizzati all'interno della configurazione. WifiManager installa il certificato e salva automaticamente la configurazione quando la rete viene abilitata. Inoltre, rimuove il certificato quando la configurazione viene eliminata.

Per ottenere tutti i certificati CA associati alla configurazione wireless, utilizza WifiEnterpriseConfig.getCaCertificates() per restituire un elenco di oggetti X509Certificate.

Aggiunta di una configurazione wireless utilizzando più certificati CA

  1. Verifica l'identità del server:
    1. Carica i certificati CA X.509.
    2. Carica la chiave privata e il certificato del client. Per un esempio di come leggere il file di un certificato, vedi Sicurezza con HTTPS e SSL.
  2. Crea un nuovo WifiConfiguration e imposta il relativo SSID e la gestione delle chiavi.
  3. Configura l'istanza WifiEnterpriseConfig su questo WifiConfiguration.
    1. Identifica il server con un elenco di X509Certificate oggetti utilizzando setCaCertificates().
    2. Imposta le credenziali, l'identità e la password del client.
    3. Imposta il protocollo EAP (Extensible Authentication Protocol) e il metodo di fase 2 per stabilire la connessione.
  4. Aggiungi la rete con WifiManager.
  5. Attiva la rete. WifiManager salva automaticamente la configurazione durante la configurazione.

Questo esempio collega i passaggi:

Kotlin

// Verify the server's identity
val caCert0 = getCaCert("cert0.crt")
val caCert1 = getCaCert("cert1.crt")
val clientKey = getClientKey()
val clientCert = getClientCert()

// Create Wi-Fi configuration
val wifiConfig = WifiConfiguration().apply {
  SSID = "mynetwork"
  allowedKeyManagement.set(KeyMgmt.WPA_EAP)
  allowedKeyManagement.set(KeyMgmt.IEEE8021X)

  // Set up Wi-Fi enterprise configuration
  enterpriseConfig.setCaCertificates(arrayOf<X509Certificate>(caCert0, caCert1))
  enterpriseConfig.setClientKeyEntry(clientKey, clientCert)
  enterpriseConfig.setIdentity("myusername")
  enterpriseConfig.setEapMethod(Eap.TLS)
  enterpriseConfig.setPhase2Method(Phase2.NONE)
}


// Add network
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val netId = wifiManager.addNetwork(wifiConfig)

// Enable network
if (netId < 0) {
  // Error creating new network
} else {
  wifiManager.enableNetwork(netId, true)
}

Java

// Verify the server's identity
X509Certificate caCert0 = getCaCert("cert0.crt");
X509Certificate caCert1 = getCaCert("cert1.crt");
PrivateKey clientKey = getClientKey();
X509Certificate clientCert = getClientCert();

// Create Wi-Fi configuration
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "mynetwork";
wifiConfig.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
wifiConfig.allowedKeyManagement.set(KeyMgmt.IEEE8021X);

// Set up Wi-Fi enterprise configuration
wifiConfig.enterpriseConfig.setCaCertificates(new X509Certificate[] {caCert0, caCert1});
wifiConfig.enterpriseConfig.setClientKeyEntry(clientKey, clientCert);
wifiConfig.enterpriseConfig.setIdentity("myusername");
wifiConfig.enterpriseConfig.setEapMethod(Eap.TLS);
wifiConfig.enterpriseConfig.setPhase2Method(Phase2.NONE);

// Add network
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
int netId = wifiManager.addNetwork(wifiConfig);

// Enable network
if (netId < 0) {
  // Error creating new network
} else {
  wifiManager.enableNetwork(netId, true);
}

Specifica una tastiera separata per il profilo di lavoro

Puoi inserire nella lista consentita un'applicazione tastiera separata da utilizzare in un profilo di lavoro. Può trattarsi del telefono stesso o di un'app Voice over IP (VoIP) che implementa l'API ConnectionService per il backend di chiamata. Ciò fornisce la stessa esperienza di chiamata dell'interfaccia utente del sistema integrato alle applicazioni VoIP nel profilo di lavoro, rendendo di fatto la tastiera di lavoro una funzionalità principale. Le chiamate in arrivo agli account per le chiamate di lavoro vengono differenziate dalle chiamate in arrivo agli account per le chiamate personali.

L'utente può scegliere di effettuare e ricevere chiamate dalla tastiera di lavoro inclusa nella lista consentita su un account telefonico. Tutte le chiamate effettuate da quella tastiera, o in arrivo all'account telefonico di lavoro, vengono registrate nel providerCallLog del profilo di lavoro. La tastiera di lavoro gestisce un registro chiamate solo di lavoro con accesso solo ai contatti di lavoro. Le chiamate con interruttore di circuito in entrata vengono gestite dalla tastiera principale e memorizzate in un registro chiamate personale. Se un profilo di lavoro viene eliminato, viene eliminato anche il registro chiamate associato a quel profilo, insieme a tutti i dati del profilo di lavoro.

Le app di terze parti devono implementare ConnectionService

Le app VoIP di terze parti che devono effettuare telefonate e integrarle nell'app per telefono integrata possono implementare l'APIConnectionService. Questo passaggio è obbligatorio per tutti i servizi VoIP utilizzati per le chiamate di lavoro. Queste app traggono vantaggio dal fatto che le chiamate vengono gestite come le tradizionali chiamate da rete mobile; ad esempio, vengono visualizzate nella tastiera di sistema integrata e nel registro chiamate. Se l'app che implementa ConnectionService è installata nel profilo di lavoro, è accessibile solo da una tastiera installata in quel profilo di lavoro.

Una volta che lo sviluppatore ha implementato ConnectionService, deve aggiungerlo al file manifest dell'app e registrare una PhoneAccount in TelecomManager. Un account telefonico rappresenta un metodo distinto per effettuare o ricevere telefonate e possono esserci più PhoneAccounts per ogni ConnectionService. Dopo aver registrato l'account del telefono, l'utente può abilitarlo tramite le impostazioni della tastiera.

Integrazione dell'interfaccia utente di sistema e notifiche

L'interfaccia utente di sistema offre agli utenti un'esperienza di chiamata coerente e integrata per le app di terze parti che utilizzano l'API ConnectionService come backend per effettuare chiamate. Se utilizzi l'app in un profilo di lavoro, nella barra di stato viene visualizzata l'icona a forma di valigetta per le chiamate in arrivo. Un'app che implementa l'app ConnectionService installata nel profilo di lavoro può utilizzare la tastiera di sistema o crearne una separata. Può trattarsi di una singola app o di app separate.

L'applicazione tastiera determina se sta effettuando o ricevendo una chiamata di lavoro verificando il flag android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL. Se si tratta di una chiamata di lavoro, la tastiera indica all'utente questo messaggio aggiungendo un badge di lavoro (l'icona a forma di valigetta):

Kotlin

// Call placed through a work phone account. getCurrentCall() is defined by the
// dialer.
val call = getCurrentCall()
if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) {
  // Set briefcase icon
}

Java

// Call placed through a work phone account. getCurrentCall() is defined by the
// dialer.
Call call = getCurrentCall();
if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) {
  // Set briefcase icon
}