API per Android 4.2

Livello API: 17

Android 4.2 (JELLY_BEAN_MR1) è un aggiornamento della release di Jelly Bean che offre nuove funzionalità per 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 l'immagine di sistema Android 4.2 e la piattaforma SDK 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 la tua app utilizzando l'emulatore Android. Poi 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 condizioni al tuo codice 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 Creare UI compatibili con le versioni precedenti.

Per ulteriori informazioni sul funzionamento dei livelli API, consulta Che cos'è il livello API?

Importanti modifiche del comportamento

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

  • I fornitori di contenuti non vengono più esportati per impostazione predefinita. In altre parole, il valore predefinito dell'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 viene applicata solo se imposti android:targetSdkVersion o android:minSdkVersion su 17 o su un valore superiore. In caso contrario, il valore predefinito è ancora “true" anche su 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 richiede l'autorizzazione ACCESS_FINE_LOCATION.

    Per soddisfare le aspettative degli utenti in termini 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 sono ora 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 riuscirà automaticamente quando viene eseguita 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 in 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 in modo che tu possa associare JavaScript al tuo codice Android in modo più sicuro. Se imposti targetSdkVersion su 17 o su un valore superiore, ora devi aggiungere l'annotazione @JavascriptInterface a qualsiasi metodo che vuoi rendere disponibile per il tuo codice JavaScript (anche questo metodo deve essere pubblico). Se non fornisci l'annotazione, il metodo non è accessibile da una pagina web nel tuo WebView quando viene eseguito 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 viene lasciato inattivo mentre è collegato a un caricabatterie (anziché spegnere lo schermo). Daydream mostra un sogno alla volta, che può essere un display passivo puramente visivo che si chiude al tocco o essere interattivo e reattivo alla suite completa di eventi di input. I tuoi sogni vengono eseguiti nel processo dell'app e hanno accesso completo al toolkit dell'interfaccia utente di Android, inclusi visualizzazioni, layout e animazioni, quindi sono più flessibili e potenti degli sfondi animati o dei 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 la UI del tuo sogno, passa 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 metodi importanti di callback del ciclo di vita in aggiunta alle API Service di base, come onDreamingStarted(), onDreamingStopped() e onDetachedFromWindow(). Non puoi avviare un DreamService dalla tua app, poiché viene avviato automaticamente dal sistema.

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

Per rendere disponibile daydream 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 è possibile chiamare finish() per interromperlo.
  • Se vuoi un display completamente immersivo, puoi chiamare setFullscreen() per nascondere la barra di stato.
  • Prima dell'avvio di Daydream, la luminosità del display si abbassa per segnalare all'utente che il timeout di inattività si sta avvicinando. Se chiami il numero setScreenBright(true), puoi invece impostare la luminosità normale del display.

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 UI per il display secondario chiamando setContentView(). Come estensione della classe Dialog, la classe Presentation fornisce l'area geografica in cui la tua app può mostrare un'interfaccia utente univoca sul display secondario.

Per rilevare display secondari su cui puoi visualizzare Presentation, utilizza l'API DisplayManager o MediaRouter. Sebbene le API DisplayManager consentano di enumerare più visualizzazioni che possono essere collegate contemporaneamente, in genere è consigliabile utilizzare MediaRouter per accedere rapidamente alla visualizzazione predefinita del sistema per le presentazioni.

Per visualizzare quella predefinita per la tua presentazione, chiama MediaRouter.getSelectedRoute() e superala ROUTE_TYPE_LIVE_VIDEO. Viene restituito un oggetto MediaRouter.RouteInfo che descrive la route attualmente selezionata dal sistema per le presentazioni video. Se MediaRouter.RouteInfo non è null, chiama getPresentationDisplay() per ottenere che Display rappresenti il display connesso.

Puoi quindi visualizzare la presentazione passando l'oggetto Display a un costruttore per la tua classe Presentation. La presentazione 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(), basta chiamare il numero MediaRouter.getSelectedRoute() come indicato sopra.

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

Tieni presente che gli schermi collegati al dispositivo dell'utente spesso hanno uno schermo più grande e probabilmente una densità diversa. Poiché le caratteristiche dello schermo possono variare, devi fornire risorse ottimizzate specificamente per schermi di dimensioni così grandi. 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 di app alla schermata di blocco. Per poter utilizzare il widget per l'app 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, quindi 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 quando ti trovi nella schermata di blocco tramite l'attributo android:initialKeyguardLayout. Funziona come l'android:initialLayout, in quanto fornisce un layout che può essere visualizzato immediatamente fino a quando il widget dell'app non viene inizializzato e non è in grado di aggiornarlo.

Per ulteriori informazioni sulla creazione di widget delle app per la schermata di blocco, incluso come regolare le dimensioni del widget quando è attiva la 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 ha il 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 l'app funzioni correttamente con più utenti su un singolo dispositivo. Indipendentemente dal numero di utenti che possono esistere su un dispositivo, i dati che la tua app salva per un determinato utente vengono mantenuti separati da quelli che l'app salva per altri utenti. Il sistema tiene traccia di quali dati utente appartengono al processo utente in cui è in esecuzione la tua app e fornisce alla tua app l'accesso solo ai dati di quell'utente e non consente l'accesso ai dati di altri utenti.

Salvataggio dei 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, i 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 utilizzata per salvare i dati di un determinato utente, i dati non saranno accessibili durante l'esecuzione come utente diverso. Dal punto di vista della tua app, ogni utente usa 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 pratiche consigliate per identificare le installazioni univoche. Se crei un nuovo UUID al primo avvio dell'app, hai la certezza di ottenere un ID univoco per il monitoraggio di ciascun utente, indipendentemente dal numero di utenti che installano l'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), questi fornirà 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 a quella di Settings.Secure perché sono di sola lettura, ma viene applicata a livello globale a tutti gli spazi utente del dispositivo.

Diverse impostazioni esistenti sono state spostate qui da Settings.System o Settings.Secure. Se al momento la tua app apporta modifiche a impostazioni precedentemente definite in Settings.System (ad esempio AIRPLANE_MODE_ON), ciò non funzionerà più sui dispositivi con Android 4.2 o versioni successive se tali impostazioni sono state spostate in Settings.Global. Puoi continuare a leggere le impostazioni presenti in Settings.Global. Tuttavia, poiché tali impostazioni non sono più considerate sicure per la modifica delle app, il tentativo di eseguire questa operazione non andrà a buon fine e il sistema scriverà un avviso nel log di sistema durante l'esecuzione dell'app su Android 4.2 o versioni successive.

Supporto del 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 e indicazioni di lettura con scrittura da destra a sinistra (RTL), 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 su “true". Una volta abilitata, il sistema abiliterà varie API RTL per visualizzare la tua app con layout RTL. Ad esempio, la barra delle azioni mostrerà l'icona e il titolo sul lato destro e i pulsanti di azione a sinistra; inoltre, verranno invertiti anche tutti i layout che hai creato con le classi View fornite dal frame.

Se hai bisogno di ottimizzare ulteriormente l'aspetto della tua app quando viene visualizzata con un layout RTL, esistono due livelli di base di ottimizzazione:

  1. Convertire 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 grafici orientati nella direzione corrispondente a quella di lettura.

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

Nota: se utilizzi SQlite e i nomi delle tabelle o delle colonne sono "solo numeri", fai attenzione: l'utilizzo di String.format(String, Object...) può causare errori in cui i numeri sono stati convertiti nei loro equivalenti arabi se sul tuo dispositivo sono state impostate le impostazioni internazionali in arabo. 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 essi. Questo è utile per una varietà di situazioni in cui vuoi inserire componenti dinamici e riutilizzabili dell'interfaccia utente in un componente dell'interfaccia utente che è a sua volta 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, è sufficiente 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 del codice che aggiunge 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();

Da un frammento nidificato, puoi ottenere un riferimento al frammento padre chiamando getParentFragment().

Android Support Library 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:

Caratteristiche intrinseche dello script

Puoi utilizzare le funzionalità intrinseche degli script integrate di Renderscript che implementano operazioni comuni per te, ad esempio:

Per utilizzare uno script intrinseco, chiama il metodo create() statico di ogni instrinsic per creare un'istanza dello script. Quindi, chiami i metodi set() disponibili di ogni script intrinseci 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 gli script chiamando addConnection(). Quando hai finito di aggiungere 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 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 Filterscript, crea file .fs anziché .rs e specifica #pragma rs_fp_relaxed per comunicare 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 denormi e l'arrotondamento verso zero. Inoltre, gli script di filtro non devono utilizzare tipi integrati a 32 bit e devono specificare una funzione radice personalizzata utilizzando l'attributo __attribute__((kernel)), poiché il filtro non supporta i puntatori, che sono definiti dalla firma predefinita della funzione root().

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

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