API per Android 4.2

Livello API: 17

Android 4.2 (JELLY_BEAN_MR1) è un aggiornamento della release Jelly Bean che offre nuove funzionalità a utenti e sviluppatori di app. Questo documento offre un'introduzione alle nuove API più importanti e utili per gli sviluppatori.

In qualità di sviluppatore di app, devi scaricare la piattaforma SDK e l'immagine di sistema Android 4.2 da SDK Manager il prima possibile. Se non hai un dispositivo con Android 4.2 su cui testare la tua app, utilizza l'immagine di sistema Android 4.2 per testare l'app con l'emulatore Android. Successivamente, crea le tue app sulla piattaforma Android 4.2 per iniziare a utilizzare le API più recenti.

Per ottimizzare meglio la tua app per i dispositivi con Android 4.2, devi impostare targetSdkVersion su "17", installarla su un'immagine di sistema Android 4.2, testarla e pubblicare un aggiornamento con questa modifica.

Puoi utilizzare le API in Android 4.2 e al contempo supportare le versioni precedenti aggiungendo al tuo codice condizioni che verificano il livello API di sistema prima di eseguire API non supportate da minSdkVersion. Per scoprire di più sul mantenimento della compatibilità con le versioni precedenti, consulta la sezione Creazione di UI compatibili con le versioni precedenti.

Per ulteriori informazioni su come funzionano i livelli API, consulta Che cos'è il livello API?

Importanti cambiamenti di comportamento

Se hai già pubblicato un'app per Android, tieni presente le seguenti modifiche che potrebbero influire sul comportamento della tua app:

  • I fornitori di contenuti non vengono più esportati per impostazione predefinita. In altre parole, il valore predefinito per l'attributo android:exported è ora “false". Se è importante che altre app possano accedere al tuo fornitore di contenuti, ora devi impostare esplicitamente android:exported="true".

    Questa modifica ha effetto solo se imposti android:targetSdkVersion o android:minSdkVersion su 17 o un valore superiore. In caso contrario, il valore predefinito è sempre “true" anche se il sistema operativo è Android 4.2 e versioni successive.

  • Rispetto alle versioni precedenti di Android, i risultati relativi alla posizione dell'utente potrebbero essere meno precisi se la tua app richiede l'autorizzazione ACCESS_COARSE_LOCATION, ma non l'autorizzazione ACCESS_FINE_LOCATION.

    Per soddisfare le aspettative degli utenti in materia di privacy quando la tua app richiede l'autorizzazione per la posizione approssimativa (e non precisa), il sistema non fornirà una stima della posizione dell'utente più precisa di un isolato.

  • Alcune impostazioni del dispositivo definite da Settings.System ora sono di sola lettura. Se la tua app tenta di scrivere modifiche alle impostazioni definite in Settings.System che sono state spostate in Settings.Global, l'operazione di scrittura non andrà a buon fine su Android 4.2 e versioni successive.

    Anche se il valore di android:targetSdkVersion e android:minSdkVersion è inferiore a 17, la tua app non è in grado di modificare le impostazioni che sono state spostate su Settings.Global se viene eseguita su Android 4.2 e versioni successive.

  • Se la tua app utilizza WebView, Android 4.2 aggiunge un ulteriore livello di sicurezza che ti consente di associare JavaScript al tuo codice Android in modo più sicuro. Se imposti targetSdkVersion su 17 o un numero superiore, ora devi aggiungere l'annotazione @JavascriptInterface a qualsiasi metodo che vuoi rendere disponibile a JavaScript (anche il metodo deve essere pubblico). Se non fornisci l'annotazione, il metodo non è accessibile da una pagina web in WebView su Android 4.2 o versioni successive. Se imposti targetSdkVersion su 16 o su un valore inferiore, l'annotazione non è obbligatoria, ma ti consigliamo di aggiornare la versione di destinazione e aggiungere l'annotazione per maggiore sicurezza.

    Scopri di più sull'associazione del codice JavaScript al codice Android.

Daydream

Daydream è una nuova modalità salvaschermo interattiva per dispositivi Android. Si attiva automaticamente quando il dispositivo viene inserito in un dock o quando il dispositivo rimane inattivo mentre è collegato a un caricabatterie (anziché spegnere lo schermo). Daydream mostra un sogno alla volta. Può trattarsi di un display passivo puramente visivo che si chiude al tocco o di essere interattivo e reattivo per tutta la gamma di eventi di input. I tuoi sogni vengono eseguiti nel processo della tua app e hanno accesso completo al toolkit dell'interfaccia utente di Android, incluse visualizzazioni, layout e animazioni, quindi sono più flessibili e potenti rispetto agli sfondi animati o ai widget delle app.

Puoi creare un sogno per Daydream implementando una sottoclasse di DreamService. Le API DreamService sono progettate per essere simili a quelle di Activity. Per specificare l'interfaccia utente per il tuo sogno, trasmetti un ID risorsa di layout o View a setContentView() in qualsiasi momento dopo aver creato una finestra, ad esempio dal callback onAttachedToWindow().

La classe DreamService fornisce altri importanti metodi di callback del ciclo di vita oltre alle API Service di base, come onDreamingStarted(), onDreamingStopped() e onDetachedFromWindow(). Non puoi avviare un'istanza DreamService dalla tua app, poiché viene avviata automaticamente dal sistema.

Se il tuo sogno è interattivo, puoi avviare un'attività dal sogno per indirizzare l'utente all'interfaccia utente completa dell'app per ottenere maggiori dettagli o controlli. Puoi utilizzare finish() per terminare il sogno e consentire all'utente di vedere la nuova attività.

Per rendere il tuo daydream disponibile al sistema, dichiara DreamService con un elemento <service> nel file manifest. Devi quindi includere un filtro per intent con l'azione "android.service.dreams.DreamService". Ecco alcuni esempi:

<service android:name=".MyDream" android:exported="true"
    android:icon="@drawable/dream_icon" android:label="@string/dream_label" >
    <intent-filter>
        <action android:name="android.service.dreams.DreamService" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

In DreamService, esistono altri metodi utili da tenere a mente:

  • setInteractive(boolean) controlla se il sogno riceve eventi di input o esce immediatamente dopo l'input dell'utente. Se il sogno è interattivo, l'utente può utilizzare i pulsanti Indietro o Home per uscire dal sogno oppure puoi chiamare finish() per interromperlo.
  • Se vuoi un display completamente immersivo, puoi chiamare setFullscreen() per nascondere la barra di stato.
  • Prima dell'avvio di Daydream, il display si attenua per segnalare all'utente che il timeout per inattività si sta avvicinando. La chiamata a setScreenBright(true) ti consente invece di impostare il display alla luminosità abituale.

Per saperne di più, consulta la documentazione di DreamService.

Display secondari

Android ora consente alla tua app di mostrare contenuti esclusivi su schermate aggiuntive collegate al dispositivo dell'utente tramite una connessione cablata o Wi-Fi. Per creare contenuti univoci per un display secondario, estendi la classe Presentation e implementa il callback onCreate(). All'interno di onCreate(), specifica la tua UI per il display secondario chiamando setContentView(). Come estensione della classe Dialog, la classe Presentation fornisce la regione in cui la tua app può visualizzare un'interfaccia utente univoca sul display secondario.

Per rilevare display secondari in cui puoi visualizzare il tuo Presentation, utilizza l'API DisplayManager o MediaRouter. Sebbene le API DisplayManager consentano di enumerare più display che possono essere connessi contemporaneamente, in genere è consigliabile usare MediaRouter per accedere rapidamente al display predefinito del sistema per le presentazioni.

Per ottenere la visualizzazione predefinita per la tua presentazione, chiama MediaRouter.getSelectedRoute() e passalo ROUTE_TYPE_LIVE_VIDEO. Viene restituito un oggetto MediaRouter.RouteInfo che descrive il percorso attualmente selezionato dal sistema per le presentazioni video. Se MediaRouter.RouteInfo non è null, chiama getPresentationDisplay() per ottenere il Display che rappresenta il display collegato.

Puoi quindi visualizzare la presentazione passando l'oggetto Display a un costruttore per la tua classe Presentation. La presentazione ora verrà visualizzata sul display secondario.

Per rilevare in fase di runtime quando è stato connesso un nuovo display, crea un'istanza di MediaRouter.SimpleCallback in cui implementi il metodo di callback onRoutePresentationDisplayChanged(), che il sistema chiamerà quando viene collegato un nuovo display di presentazione. Quindi registra MediaRouter.SimpleCallback passandolo a MediaRouter.addCallback() insieme al tipo di percorso ROUTE_TYPE_LIVE_VIDEO. Quando ricevi una chiamata al numero onRoutePresentationDisplayChanged(), chiama il numero MediaRouter.getSelectedRoute() come indicato sopra.

Per ottimizzare ulteriormente l'UI di Presentation per le schermate secondarie, puoi applicare un tema diverso specificando l'attributo android:presentationTheme nella sezione <style> che hai applicato alla tua applicazione o attività.

Tieni presente che gli schermi collegati al dispositivo dell'utente spesso hanno dimensioni maggiori e probabilmente una densità diversa. Poiché le caratteristiche dello schermo possono variare, dovresti fornire risorse ottimizzate specificamente per questi display. Se devi richiedere risorse aggiuntive da Presentation, chiama getContext().getResources() per ottenere l'oggetto Resources corrispondente al display. In questo modo vengono fornite le risorse dell'app appropriate per le dimensioni e la densità dello schermo del display secondario.

Per ulteriori informazioni e alcuni esempi di codice, consulta la documentazione della classe Presentation.

Widget schermata di blocco

Android ora consente agli utenti di aggiungere widget delle app alla schermata di blocco. Per rendere disponibile il widget per l'utilizzo nella schermata di blocco, aggiungi l'attributo android:widgetCategory al file XML che specifica AppWidgetProviderInfo. Questo attributo supporta due valori: home_screen e keyguard. Per impostazione predefinita, l'attributo è impostato su home_screen, pertanto gli utenti possono aggiungere il widget dell'app alla schermata Home. Se vuoi che il widget dell'app sia disponibile anche nella schermata di blocco, aggiungi il valore keyguard:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:widgetCategory="keyguard|home_screen">
</appwidget-provider>

Devi inoltre specificare un layout iniziale per il widget dell'app nella schermata di blocco utilizzando l'attributo android:initialKeyguardLayout. Funziona come android:initialLayout, in quanto fornisce un layout che può essere visualizzato immediatamente fino a quando il widget dell'app non viene inizializzato e può aggiornarlo.

Per ulteriori informazioni sulla creazione di widget delle app per la schermata di blocco, incluse le dimensioni corrette del widget dell'app nella schermata di blocco, consulta la guida Widget app.

Più utenti

Android ora consente più spazi utente sui dispositivi condivisibili come i tablet. Ogni utente di un dispositivo dispone del proprio insieme di account, app, impostazioni di sistema, file e qualsiasi altro dato associato all'utente.

In qualità di sviluppatore di app, non devi fare nulla per far sì che la tua app funzioni correttamente con più utenti su un singolo dispositivo. Indipendentemente dal numero di utenti presenti su un dispositivo, i dati salvati dalla tua app per un determinato utente vengono mantenuti separati da quelli salvati dall'app per altri utenti. Il sistema tiene traccia dei dati utente appartenenti al processo utente in cui è in esecuzione l'app e fornisce alla tua app l'accesso solo ai dati di quell'utente e non consente l'accesso ai dati di altri utenti.

Salvare i dati in un ambiente multiutente

Ogni volta che l'app salva le preferenze dell'utente, crea un database o scrive un file nello spazio di archiviazione interno o esterno dell'utente, questi dati sono accessibili solo quando l'utente è in esecuzione.

Per assicurarti che la tua app funzioni correttamente in un ambiente multiutente, non fare riferimento alla directory interna dell'app o alla posizione di archiviazione esterna utilizzando percorsi hardcoded e utilizza sempre le API appropriate:

Indipendentemente dall'API che utilizzi per salvare i dati di un determinato utente, i dati non saranno accessibili durante l'esecuzione con un utente diverso. Dal punto di vista dell'app, ogni utente utilizza un dispositivo completamente separato.

Identificazione degli utenti in un ambiente multiutente

Se la tua app vuole identificare utenti unici, ad esempio per raccogliere dati di analisi o creare altre associazioni di account, segui le best practice consigliate per identificare installazioni univoche. Creando un nuovo UUID quando la tua app viene avviata per la prima volta, hai la certezza di ottenere un ID univoco per il monitoraggio di ciascun utente, indipendentemente dal numero di utenti che installano la tua app su un singolo dispositivo. In alternativa, puoi salvare un token locale recuperato dal tuo server o utilizzare l'ID di registrazione fornito da Google Cloud Messaging.

Tieni presente che se la tua app richiede uno degli identificatori del dispositivo hardware (ad esempio l'indirizzo MAC Wi-Fi o il numero SERIAL), forniranno lo stesso valore per ogni utente perché questi identificatori sono associati all'hardware e non all'utente. Per non parlare degli altri problemi introdotti da questi identificatori, come discusso nel post del blog Identificazione delle installazioni di app.

Nuove impostazioni globali

Le impostazioni di sistema sono state aggiornate per supportare più utenti con l'aggiunta di Settings.Global. Questa raccolta di impostazioni è simile alle impostazioni di Settings.Secure in quanto sono di sola lettura, ma viene applicata globalmente a tutti gli spazi utente del dispositivo.

Diverse impostazioni esistenti sono state trasferite qui da Settings.System o Settings.Secure. Se l'app sta apportando modifiche a impostazioni precedentemente definite in Settings.System (ad esempio AIRPLANE_MODE_ON), ciò non dovrebbe più funzionare su un dispositivo con Android 4.2 o versioni successive se queste impostazioni sono state spostate su Settings.Global. Puoi continuare a leggere le impostazioni disponibili in Settings.Global. Tuttavia, poiché queste impostazioni non sono più considerate sicure per la modifica delle app, se tenti di farlo non verrà eseguita automaticamente e il sistema scriverà un avviso nel log di sistema quando esegui l'app su Android 4.2 o versioni successive.

Supporto layout RTL

Android ora offre diverse API che ti consentono di creare interfacce utente che trasformano agevolmente l'orientamento del layout per supportare le lingue che utilizzano UI da destra a sinistra (RTL) e direttive di lettura, come l'arabo e l'ebraico.

Per iniziare a supportare i layout RTL nella tua app, imposta l'attributo android:supportsRtl sull'elemento <application> nel file manifest e impostalo “true". Dopo l'attivazione, il sistema abiliterà varie API RTL per visualizzare la tua app con i layout RTL. Ad esempio, la barra delle azioni mostrerà l'icona e il titolo a destra e i pulsanti di azione a sinistra; inoltre, verranno invertiti tutti i layout che hai creato con le classi View fornite dal framework.

Se hai bisogno di ottimizzare ulteriormente l'aspetto dell'app quando viene visualizzata con un layout RTL, i livelli di base di ottimizzazione sono due:

  1. Converti le proprietà di layout orientate a sinistra e a destra in proprietà di layout con orientamento iniziale e finale.

    Ad esempio, utilizza android:layout_marginStart al posto di android:layout_marginLeft e android:layout_marginEnd al posto di android:layout_marginRight.

    La classe RelativeLayout fornisce anche gli attributi di layout corrispondenti per sostituire le posizioni a sinistra/destra, ad esempio android:layout_alignParentStart per sostituire android:layout_alignParentLeft e android:layout_toStartOf anziché android:layout_toLeftOf.

  2. In alternativa, per un'ottimizzazione completa dei layout RTL, puoi fornire file di layout completamente separati utilizzando il qualificatore delle risorse ldrtl (ldrtl sta per layout-direction-right-to-left}). Ad esempio, puoi salvare i file di layout predefiniti in res/layout/ e i layout ottimizzati RTL in res/layout-ldrtl/.

    Il qualificatore ldrtl è ottimo per le risorse disegnabili, in modo da poter fornire immagini orientate nella direzione corrispondente alla direzione di lettura.

Nel framework sono disponibili altre API per supportare i layout RTL, ad esempio nella classe View per implementare i comportamenti corretti per le viste personalizzate e in Configuration per eseguire query nella direzione attuale del layout.

Nota: se utilizzi SQlite e hai nomi di tabelle o colonne di tipo "solo numero", fai attenzione: l'utilizzo di String.format(String, Object...) può causare errori in cui i numeri sono stati convertiti negli equivalenti arabi se sul dispositivo è stata impostata la lingua araba. Devi utilizzare String.format(Locale,String,Object...) per assicurarti che i numeri vengano conservati come ASCII. Utilizza anche String.format("%d", int) anziché String.valueOf(int) per la formattazione dei numeri.

Frammenti nidificati

Ora puoi incorporare frammenti all'interno di questi ultimi. Ciò è utile per una serie di situazioni in cui vuoi posizionare componenti dell'interfaccia utente dinamici e riutilizzabili in un componente dell'interfaccia utente dinamico e riutilizzabile. Ad esempio, se utilizzi ViewPager per creare frammenti che scorrono verso sinistra e destra e occupano la maggior parte dello spazio sullo schermo, ora puoi inserire frammenti nella pagina di ogni frammento.

Per nidificare un frammento, basta chiamare getChildFragmentManager() sul Fragment in cui vuoi aggiungere un frammento. Questo restituisce un valore FragmentManager che puoi utilizzare come fai normalmente dall'attività di primo livello per creare transazioni con frammenti. Ad esempio, ecco alcuni codici che aggiungono un frammento dall'interno di una classe Fragment esistente:

Kotlin

val videoFragment = VideoPlayerFragment()
childFragmentManager.beginTransaction().apply {
    add(R.id.video_fragment, videoFragment)
    commit()
}

Java

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

Dall'interno di un frammento nidificato, puoi ottenere un riferimento al frammento padre chiamando getParentFragment().

La libreria di assistenza Android ora supporta anche i frammenti nidificati, quindi puoi implementare progettazioni di frammenti nidificate su Android 1.6 e versioni successive.

Nota: non puoi gonfiare un layout in un frammento se questo include un <fragment>. I frammenti nidificati sono supportati solo se aggiunti a un frammento in modo dinamico.

RenderScript

La funzionalità di calcolo di Renderscript è stata migliorata con le seguenti caratteristiche:

Funzionalità intrinseche per lo script

Puoi utilizzare le funzionalità intrinseche degli script integrati di Renderscript per implementare operazioni comuni per te, ad esempio:

Per utilizzare uno script intrinseco, chiama il metodo create() statico di ogni script intrinseco per creare un'istanza dello script. Quindi chiama i metodi set() disponibili di ogni script intrinseco per impostare gli input e le opzioni necessari. Infine, chiama il metodo forEach() per eseguire lo script.

Gruppi di script

Gli ScriptGroup consentono di concatenare script Renderscript correlati ed eseguirli con un'unica chiamata.

Utilizza un ScriptGroup.Builder per aggiungere tutti gli script al gruppo chiamando il numero addKernel(). Dopo aver aggiunto tutti gli script, crea le connessioni tra loro chiamando addConnection(). Dopo aver aggiunto le connessioni, chiama create() per creare il gruppo di script. Prima di eseguire il gruppo di script, specifica l'input Allocation e lo script iniziale da eseguire con il metodo setInput(Script.KernelID, Allocation) e fornisci l'output in Allocation in cui verrà scritto il risultato e lo script finale da eseguire con setOutput(). Infine, chiama execute() per eseguire il gruppo di script.

Script filtro

Filtroscript definisce i vincoli sulle API Renderscript esistenti che consentono l'esecuzione del codice risultante su una gamma più ampia di processori (CPU, GPU e DSP). Per creare file Filtroscript, crea file .fs anziché .rs e specifica #pragma rs_fp_relaxed per indicare al runtime di Renderscript, i tuoi script non richiedono una precisione in virgola mobile rigorosa IEEE 754-2008. Questa precisione consente lo svuotamento a zero per i denorm e il arrotondamento a zero. Inoltre, gli script di filtro non devono utilizzare tipi integrati a 32 bit e devono specificare una funzione root personalizzata utilizzando l'attributo __attribute__((kernel)), in quanto il filtroscript non supporta i puntatori, che sono definiti dalla firma predefinita della funzione root().

Nota: sebbene il supporto di Filtroscript sia nella piattaforma, l'assistenza per gli sviluppatori sarà disponibile nella release 21.0.1 di SDK Tools.

Per una visualizzazione dettagliata di tutte le modifiche all'API in Android 4.2, consulta il report Differenze API.