Android 17 introduce nuove fantastiche funzionalità e API per gli sviluppatori. Le sezioni seguenti riepilogano queste funzionalità per aiutarti a iniziare a utilizzare le API correlate.
Per un elenco dettagliato delle API nuove, modificate e rimosse, leggi il report diff API. Per informazioni dettagliate sulle nuove API, visita la documentazione di riferimento delle API Android. Le nuove API sono evidenziate per una maggiore visibilità.
Devi anche esaminare le aree in cui le modifiche alla piattaforma potrebbero influire sulle tue app. Per maggiori informazioni, consulta le seguenti pagine:
- Modifiche al comportamento che interessano le app quando hanno come target Android 17
- Modifiche al comportamento che interessano tutte le app indipendentemente da
targetSdkVersion.
Funzionalità di base
Android 17 aggiunge le seguenti nuove funzionalità relative alla funzionalità di base di Android.
Nuovi trigger ProfilingManager
Android 17 aggiunge diversi nuovi trigger di sistema a ProfilingManager per
aiutarti a raccogliere dati approfonditi per eseguire il debug dei problemi di rendimento.
I nuovi attivatori sono:
TRIGGER_TYPE_COLD_START: il trigger si verifica durante l'avvio a freddo dell'app. Fornisce sia un campione dello stack di chiamate sia una traccia di sistema nella risposta.TRIGGER_TYPE_OOM: il trigger si attiva quando un'app genera un erroreOutOfMemoryErrore fornisce un dump dell'heap Java in risposta.TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: il trigger si attiva quando un'app viene chiusa a causa di un utilizzo anomalo ed eccessivo della CPU e fornisce un esempio di call stack in risposta.
Per capire come configurare il trigger di sistema, consulta la documentazione sulla profilazione basata su trigger e su come recuperare e analizzare i dati di profilazione.
API JobDebugInfo
Android 17 introduce nuove API JobDebugInfo per aiutare gli sviluppatori a eseguire il debug
dei job JobScheduler: perché non vengono eseguiti, per quanto tempo sono stati eseguiti e
altre informazioni aggregate.
Il primo metodo delle API JobDebugInfo estese è
getPendingJobReasonStats(), che restituisce una mappa dei motivi per cui il job era in
uno stato di esecuzione in attesa e le rispettive durate cumulative in attesa. Questo metodo si unisce ai metodi getPendingJobReasonsHistory() e
getPendingJobReasons() per fornirti informazioni sul motivo per cui un job pianificato
non viene eseguito come previsto, ma semplifica il recupero delle informazioni rendendo
disponibili sia la durata che il motivo del job in un unico metodo.
Ad esempio, per un jobId specificato, il metodo potrebbe restituire
PENDING_JOB_REASON_CONSTRAINT_CHARGING e una durata di 60.000 ms, indicando
che il job è rimasto in attesa per 60.000 ms perché il vincolo di ricarica non è stato
soddisfatto.
Privacy
Android 17 include le seguenti nuove funzionalità per migliorare la privacy degli utenti.
Selettore contatti Android
Il selettore di contatti Android è un'interfaccia standardizzata e sfogliabile che consente agli utenti di
condividere i contatti con la tua app. Disponibile sui dispositivi con
Android 17 o versioni successive, il selettore offre un'alternativa che tutela la privacy
all'autorizzazione READ_CONTACTS. Anziché richiedere
l'accesso all'intera rubrica dell'utente, la tua app specifica i campi di dati di cui ha
bisogno, ad esempio numeri di telefono o indirizzi email, e l'utente seleziona i contatti
specifici da condividere. In questo modo, la tua app ottiene l'accesso in lettura solo ai dati selezionati,
garantendo un controllo granulare e fornendo al contempo un'esperienza utente coerente con
funzionalità di ricerca, cambio di profilo e selezione multipla integrate, senza
dover creare o gestire l'interfaccia utente.
Per saperne di più, consulta la documentazione del selettore di contatti.
Sicurezza
Android 17 aggiunge le seguenti nuove funzionalità per migliorare la sicurezza di dispositivi e app.
Modalità di protezione avanzata di Android (AAPM)
La modalità di protezione avanzata di Android offre agli utenti Android un nuovo e potente insieme di funzionalità di sicurezza, segnando un passo significativo nella salvaguardia degli utenti, in particolare di quelli a rischio più elevato, da attacchi sofisticati. Progettato come funzionalità di attivazione, AAPM viene attivato con una singola impostazione di configurazione che gli utenti possono attivare in qualsiasi momento per applicare un insieme di protezioni di sicurezza.
Queste configurazioni di base includono il blocco dell'installazione di app da origini sconosciute
(sideloading), la limitazione della segnalazione dei dati USB e l'obbligo di scansione di Google Play Protect, che riduce notevolmente la superficie di attacco del dispositivo.
Gli sviluppatori possono integrarsi con questa funzionalità utilizzando l'API
AdvancedProtectionManager per rilevare lo stato della modalità, consentendo
alle applicazioni di adottare automaticamente una postura di sicurezza rafforzata o limitare
le funzionalità ad alto rischio quando un utente ha attivato la funzionalità.
Connettività
Android 17 aggiunge le seguenti funzionalità per migliorare la connettività di dispositivi e app.
Reti satellitari con limitazioni
Implementa ottimizzazioni per consentire alle app di funzionare in modo efficace su reti satellitari a bassa larghezza di banda.
Esperienza utente e UI di sistema
Android 17 include le seguenti modifiche per migliorare l'esperienza utente.
Handoff
Handoff è una nuova funzionalità e API in arrivo su Android 17 che gli sviluppatori di app possono integrare per fornire continuità cross-device ai propri utenti. Consente all'utente di avviare un'attività dell'app su un dispositivo Android e trasferirla su un altro dispositivo Android. Handoff viene eseguito in background sul dispositivo di un utente e mostra le attività disponibili dagli altri dispositivi vicini dell'utente tramite vari punti di accesso, come il launcher e la barra delle app, sul dispositivo di ricezione.
Le app possono designare Handoff per avviare la stessa app Android nativa, se è installata e disponibile sul dispositivo di ricezione. In questo flusso da app ad app, l'utente viene indirizzato tramite link diretto all'attività designata. In alternativa, il trasferimento da app a web può essere offerto come opzione di riserva o implementato direttamente con il trasferimento di URL.
Il supporto del trasferimento è implementato in base all'attività. Per attivare Handoff, chiama
il metodo setHandoffEnabled() per l'attività. Potrebbe essere necessario trasmettere dati aggiuntivi
insieme al trasferimento, in modo che l'attività ricreata sul dispositivo di ricezione
possa ripristinare lo stato appropriato. Implementa il
callback onHandoffActivityRequested() per restituire un oggetto HandoffActivityData
che contiene i dettagli che specificano come Handoff deve gestire e ricreare
l'attività sul dispositivo di ricezione.
Aggiornamento in tempo reale - API dei colori semantici
Con Android 17, Aggiornamento in tempo reale lancia le API di colorazione semantica per supportare i colori con un significato universale.
Le seguenti classi supportano la colorazione semantica:
NotificationNotification.MetricNotification.ProgressStyle.PointNotification.ProgressStyle.Segment
Colorare
- Verde: associato alla sicurezza. Questo colore deve essere utilizzato nel caso in cui informi le persone che ti trovi in una situazione di sicurezza.
- Arancione: per indicare cautela e segnalare pericoli fisici. Questo colore deve essere utilizzato in situazione in cui gli utenti devono prestare attenzione per impostare una migliore protezione impostazione.
- Rosso: in genere indica pericolo, stop. Deve essere presentato nel caso in cui sia necessaria urgentemente l'attenzione delle persone.
- Blu: colore neutro per i contenuti che sono informativi e devono distinguersi dagli altri contenuti.
Il seguente esempio mostra come applicare stili semantici al testo in una notifica:
val ssb = SpannableStringBuilder()
.append("Colors: ")
.append("NONE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_UNSPECIFIED), 0)
.append(", ")
.append("INFO", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_INFO), 0)
.append(", ")
.append("SAFE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_SAFE), 0)
.append(", ")
.append("CAUTION", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_CAUTION), 0)
.append(", ")
.append("DANGER", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_DANGER), 0)
Notification.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_icon)
.setContentTitle("Hello World!")
.setContentText(ssb)
.setOngoing(true)
.setRequestPromotedOngoing(true)
API UWB Downlink-TDoA per Android 17
La misurazione della distanza tramite la differenza di tempo di arrivo del downlink (DL-TDoA) consente a un dispositivo di determinare la sua posizione rispetto a più punti di ancoraggio misurando i tempi di arrivo relativi dei segnali.
Il seguente snippet mostra come inizializzare Ranging Manager, verificare le funzionalità del dispositivo e avviare una sessione DL-TDoA:
Kotlin
class RangingApp {
fun initDlTdoa(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Register for device capabilities
val capabilitiesCallback = object : RangingManager.CapabilitiesCallback {
override fun onRangingCapabilities(capabilities: RangingCapabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.uwbCapabilities != null && capabilities.uwbCapabilities!!.isDlTdoaSupported) {
startDlTDoASession(context)
}
}
}
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback)
}
fun startDlTDoASession(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Create session and configure parameters
val executor = Executors.newSingleThreadExecutor()
val rangingSession = rangingManager.createRangingSession(executor, RangingSessionCallback())
val rangingRoundIndexes = intArrayOf(0)
val config: ByteArray = byteArrayOf() // OOB config data
val params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes)
val rangingDevice = RangingDevice.Builder().build()
val rawTagDevice = RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build()
val dtTagConfig = RawDtTagRangingConfig.Builder(rawTagDevice).build()
val preference = RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(SessionConfig.Builder().build())
.build()
// Start the ranging session
rangingSession.start(preference)
}
}
private class RangingSessionCallback : RangingSession.Callback {
override fun onDlTdoaResults(peer: RangingDevice, measurement: DlTdoaMeasurement) {
// Process measurement results here
}
}
Java
public class RangingApp {
public void initDlTdoa(Context context) {
// Initialize the Ranging Manager
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Register for device capabilities
RangingManager.CapabilitiesCallback capabilitiesCallback = new RangingManager.CapabilitiesCallback() {
@Override
public void onRangingCapabilities(RangingCapabilities capabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.getUwbCapabilities() != null && capabilities.getUwbCapabilities().isDlTdoaSupported) {
startDlTDoASession(context);
}
}
};
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback);
}
public void startDlTDoASession(Context context) {
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Create session and configure parameters
Executor executor = Executors.newSingleThreadExecutor();
RangingSession rangingSession = rangingManager.createRangingSession(executor, new RangingSessionCallback());
int[] rangingRoundIndexes = new int[] {0};
byte[] config = new byte[0]; // OOB config data
DlTdoaRangingParams params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes);
RangingDevice rangingDevice = new RangingDevice.Builder().build();
RawRangingDevice rawTagDevice = new RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build();
RawDtTagRangingConfig dtTagConfig = new RawDtTagRangingConfig.Builder(rawTagDevice).build();
RangingPreference preference = new RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(new SessionConfig.Builder().build())
.build();
// Start the ranging session
rangingSession.start(preference);
}
private static class RangingSessionCallback implements RangingSession.Callback {
@Override
public void onDlTdoaResults(RangingDevice peer, DlTdoaMeasurement measurement) {
// Process measurement results here
}
}
}
Configurazioni fuori banda (OOB)
Lo snippet seguente fornisce un esempio di dati di configurazione OOB DL-TDoA per Wi-Fi e BLE:
Java
// Wifi Configuration
byte[] wifiConfig = {
(byte) 0xDD, (byte) 0x2D, (byte) 0x5A, (byte) 0x18, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
// BLE Configuration
byte[] bleConfig = {
(byte) 0x2D, (byte) 0x16, (byte) 0xF4, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
Se non puoi utilizzare una configurazione OOB perché non è presente o se devi modificare i valori predefiniti che non sono presenti nella configurazione OOB, puoi creare parametri con DlTdoaRangingParams.Builder come mostrato nel seguente snippet. Puoi utilizzare
questi parametri al posto di DlTdoaRangingParams.createFromFiraConfigPacket():
Kotlin
val dlTdoaParams = DlTdoaRangingParams.Builder(1)
.setComplexChannel(UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(byteArrayOf(0x01, 0x02, 0x03, 0x04))
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(byteArrayOf(0x01, 0x05))
.build()
Java
DlTdoaRangingParams dlTdoaParams = new DlTdoaRangingParams.Builder(1)
.setComplexChannel(new UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(new byte[]{0x01, 0x02, 0x03, 0x04})
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(new byte[]{0x01, 0x05})
.build();